wxWidgets / Phoenix

wxPython's Project Phoenix. A new implementation of wxPython, better, stronger, faster than he was before.
http://wxpython.org/
2.28k stars 514 forks source link

Key events do not return code when non-latin keyboard layout is active #1391

Open DarkFenX opened 4 years ago

DarkFenX commented 4 years ago

Affects both xorg and wayland.

Operating system: Debian Linux wxPython version & source: 4.0.6 from debian repos Python version & source: 3.7 from debian repos

Description of the problem: Gnome 3, latin layout: when you press "A" key, code 65 is printed. With non-latin layout (e.g. russian), code 0 is printed.

Example is stolen from #1144

# -*- coding: utf-8 -*-

import wx
import wx.stc

class MyFrame(wx.Frame):
    def __init__(self, parent):
        wx.Frame.__init__(self, parent, -1, "Key test")
        self.SetSize((600, 500))

        self.textCrl = wx.TextCtrl(self, style=wx.TE_MULTILINE)
        self.styledTextCtrl = wx.stc.StyledTextCtrl(self)
        self.logCtrl = wx.TextCtrl(self, style=wx.TE_READONLY | wx.TE_MULTILINE)

        self.textCrl.Bind(wx.EVT_KEY_DOWN, handler=self._onTextCtrlKeyDown)
        self.styledTextCtrl.Bind(wx.EVT_KEY_DOWN, handler=self._onStyledTextCtrlKeyDown)

        sizer = wx.BoxSizer(wx.VERTICAL)
        sizer.Add(self.textCrl, 1, wx.EXPAND)
        sizer.Add(self.styledTextCtrl, 1, wx.EXPAND)
        sizer.Add(self.logCtrl, 1, wx.EXPAND)
        self.SetSizer(sizer)

    def _onTextCtrlKeyDown(self, event):
        text = '[TextCtrl] EVT_KEY_DOWN. Key code = {}\n'.format(event.GetKeyCode())
        self.logCtrl.AppendText(text)
        event.Skip()

    def _onStyledTextCtrlKeyDown(self, event):
        text = '[StyledTextCtrl] EVT_KEY_DOWN. Key code = {}\n'.format(event.GetKeyCode())
        self.logCtrl.AppendText(text)
        event.Skip()

if __name__ == '__main__':
    app = wx.App(0)

    frame = MyFrame(None)
    app.SetTopWindow(frame)
    frame.Show()

    app.MainLoop()
unxed commented 1 year ago

Also ran into this problem. Solution is possible at least under wxGTK, where you have raw x11 key codes returned by GetRawKeyFlags(). You have to get raw x11 key code, and then determine keycode value through the x11 api. Here is example in C, maybe the same approach is possible in Python.

#include <xkbcommon/xkbcommon.h>
// ...
auto key_code = event.GetKeyCode();

#if defined (__WXGTK__)
if (key_code == 0) {
  xkb_context *ctx = xkb_context_new(XKB_CONTEXT_NO_FLAGS);
  struct xkb_rule_names names = {
    .rules = NULL,
    .model = NULL,
    .layout = "us",
    .variant = NULL,
    .options = NULL
  };
  xkb_keymap *keymap = xkb_keymap_new_from_names(ctx, &names, XKB_KEYMAP_COMPILE_NO_FLAGS);
  xkb_state *state = xkb_state_new(keymap);

  xkb_keycode_t keycode = GetRawKeyFlags();

  char key_code_str[64];
  xkb_state_key_get_utf8(state, keycode, key_code_str, sizeof(key_code_str));
  key_code = toupper(key_code_str[0]);

  xkb_state_unref(state);
  xkb_keymap_unref(keymap);
  xkb_context_unref(ctx);
}
#endif