From abd5989de8c095e6b4797a476c95a1c90688e4ca Mon Sep 17 00:00:00 2001 From: Roz K Date: Fri, 23 Dec 2022 13:28:29 +0100 Subject: [PATCH] Add basic XIM support for key events. --- __init__.py | 8 ++--- cpp/events.hpp | 4 ++- cpp/events/events_x11.cpp | 57 ++++++++++++++++++++++--------- cpp/opengl/render_context_glx.cpp | 36 +++++++++++++++++-- 4 files changed, 81 insertions(+), 24 deletions(-) diff --git a/__init__.py b/__init__.py index 92e1d04..3eb5ece 100644 --- a/__init__.py +++ b/__init__.py @@ -349,17 +349,15 @@ EVENT_KEY_PRESS = 0 EVENT_KEY_RELEASE = 1 class _EventKey(ctypes.Structure): - _fields_ = ( - ('keycode', ctypes.c_uint), - ) + _fields_ = ('code', ctypes.c_uint), ('symbol', ctypes.c_ushort), ('character', ctypes.c_wchar) -class _AllEvents(ctypes.Union): +class _Events(ctypes.Union): _fields_ = ( ('key', _EventKey), ) class Event(ctypes.Structure): - _fields_ = ('type', ctypes.c_uint), ('data', _AllEvents) + _fields_ = ('type', ctypes.c_uint), ('data', _Events) consume_events = _engine.rk_consume_events consume_events.restype = ctypes.c_uint diff --git a/cpp/events.hpp b/cpp/events.hpp index 4431e5b..593d73b 100644 --- a/cpp/events.hpp +++ b/cpp/events.hpp @@ -24,7 +24,9 @@ enum rk_event_type : rk_uint { }; struct rk_event_key { - rk_uint keycode; + rk_uint code; + rk_ushort symbol; + wchar_t character; }; struct rk_event { diff --git a/cpp/events/events_x11.cpp b/cpp/events/events_x11.cpp index b8c5375..a4689e4 100644 --- a/cpp/events/events_x11.cpp +++ b/cpp/events/events_x11.cpp @@ -16,9 +16,11 @@ #include "../events.hpp" #include -unsigned rk_events_mask = KeyPressMask | KeyReleaseMask; extern Display * rk_display; extern Window rk_window; +extern XIC rk_input_context; + +unsigned rk_events_mask = KeyPressMask | KeyReleaseMask; rk_uint rk_consume_events( rk_event * events, @@ -28,21 +30,44 @@ rk_uint rk_consume_events( } XEvent x11_event; unsigned nevents = 0; - for ( ; nevents < max_events ; ++nevents) { - if (XCheckWindowEvent(rk_display, rk_window, rk_events_mask, &x11_event)) { - rk_event & event = events[nevents]; - switch (x11_event.type) { - case KeyPress: - event.type = RK_EVENT_KEY_PRESS; - event.key.keycode = x11_event.xkey.keycode; - break; - case KeyRelease: - event.type = RK_EVENT_KEY_RELEASE; - event.key.keycode = x11_event.xkey.keycode; - break; - } - } else { - break; + wchar_t string[256]; + KeySym keysym; + Status status; + while (nevents < max_events && XCheckWindowEvent(rk_display, rk_window, rk_events_mask, &x11_event)) { + if (XFilterEvent(&x11_event, 0)) { + continue; + } + rk_event & event = events[nevents++]; + switch (x11_event.type) { + case KeyPress: + event.type = RK_EVENT_KEY_PRESS; + event.key.code = x11_event.xkey.keycode; + XwcLookupString(rk_input_context, &x11_event.xkey, string, 256, &keysym, &status); + switch (status) { + case XLookupChars: + event.key.symbol = XLookupKeysym(&x11_event.xkey, 0); + event.key.character = string[0]; + break; + case XLookupKeySym: + event.key.symbol = keysym; + event.key.character = 0; + break; + case XLookupBoth: + event.key.symbol = keysym; + event.key.character = string[0]; + break; + default: + event.key.symbol = 0; + event.key.character = 0; + break; + } + break; + case KeyRelease: + event.type = RK_EVENT_KEY_RELEASE; + event.key.code = x11_event.xkey.keycode; + event.key.symbol = XLookupKeysym(&x11_event.xkey, 0); + event.key.character = 0; + break; } } return nevents; diff --git a/cpp/opengl/render_context_glx.cpp b/cpp/opengl/render_context_glx.cpp index 9ed7ed3..8ddc963 100644 --- a/cpp/opengl/render_context_glx.cpp +++ b/cpp/opengl/render_context_glx.cpp @@ -21,9 +21,12 @@ #include #include +extern unsigned rk_events_mask; + Display * rk_display = nullptr; Window rk_window = 0; -extern unsigned rk_events_mask; +XIC rk_input_context = nullptr; +static XIM rk_input_manager = nullptr; static Colormap rk_colormap = 0; static GLXContext rk_context = nullptr; static bool rk_error_occured = false; @@ -94,6 +97,8 @@ rk_window_t rk_create_context( char const * name, unsigned width, unsigned height) { + XSetLocaleModifiers(""); + rk_display = XOpenDisplay(nullptr); if (!rk_display) { rk_printf("Failed to open X display."); @@ -151,14 +156,32 @@ rk_window_t rk_create_context( rk_window = XCreateWindow(rk_display, RootWindow(rk_display, vi->screen), 0, 0, width, height, 0, vi->depth, InputOutput, vi->visual, CWBorderPixel | CWColormap | CWEventMask, &swa); + XFree(vi); if (!rk_window) { rk_printf("Failed to create window."); rk_destroy_context(); return nullptr; } - XFree(vi); XStoreName(rk_display, rk_window, name); + + rk_input_manager = XOpenIM(rk_display, nullptr, nullptr, nullptr); + if (!rk_input_manager) { + rk_printf("Failed to open input manager."); + rk_destroy_context(); + return nullptr; + } + rk_input_context = XCreateIC(rk_input_manager, + XNInputStyle, XIMPreeditNone | XIMStatusNone, + XNClientWindow, rk_window, + NULL); + if (!rk_input_context) { + rk_printf("Failed to create input context."); + rk_destroy_context(); + return nullptr; + } + XMapWindow(rk_display, rk_window); + XSetICFocus(rk_input_context); char const * const glx_exts = glXQueryExtensionsString(rk_display, DefaultScreen(rk_display)); glXCreateContextAttribsARBProc const glXCreateContextAttribsARB = @@ -221,6 +244,15 @@ void rk_destroy_context() { glXDestroyContext(rk_display, rk_context); rk_context = nullptr; } + if (rk_input_context) { + XUnsetICFocus(rk_input_context); + XDestroyIC(rk_input_context); + rk_input_context = nullptr; + } + if (rk_input_manager) { + XCloseIM(rk_input_manager); + rk_input_manager = nullptr; + } if (rk_window) { XDestroyWindow(rk_display, rk_window); rk_window = 0;