Add basic XIM support for key events.

This commit is contained in:
Roz K 2022-12-23 13:28:29 +01:00
parent 61cfdbccf3
commit abd5989de8
Signed by: roz
GPG Key ID: 51FBF4E483E1C822
4 changed files with 81 additions and 24 deletions

View File

@ -349,17 +349,15 @@ EVENT_KEY_PRESS = 0
EVENT_KEY_RELEASE = 1 EVENT_KEY_RELEASE = 1
class _EventKey(ctypes.Structure): class _EventKey(ctypes.Structure):
_fields_ = ( _fields_ = ('code', ctypes.c_uint), ('symbol', ctypes.c_ushort), ('character', ctypes.c_wchar)
('keycode', ctypes.c_uint),
)
class _AllEvents(ctypes.Union): class _Events(ctypes.Union):
_fields_ = ( _fields_ = (
('key', _EventKey), ('key', _EventKey),
) )
class Event(ctypes.Structure): 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 = _engine.rk_consume_events
consume_events.restype = ctypes.c_uint consume_events.restype = ctypes.c_uint

View File

@ -24,7 +24,9 @@ enum rk_event_type : rk_uint {
}; };
struct rk_event_key { struct rk_event_key {
rk_uint keycode; rk_uint code;
rk_ushort symbol;
wchar_t character;
}; };
struct rk_event { struct rk_event {

View File

@ -16,9 +16,11 @@
#include "../events.hpp" #include "../events.hpp"
#include <X11/Xlib.h> #include <X11/Xlib.h>
unsigned rk_events_mask = KeyPressMask | KeyReleaseMask;
extern Display * rk_display; extern Display * rk_display;
extern Window rk_window; extern Window rk_window;
extern XIC rk_input_context;
unsigned rk_events_mask = KeyPressMask | KeyReleaseMask;
rk_uint rk_consume_events( rk_uint rk_consume_events(
rk_event * events, rk_event * events,
@ -28,20 +30,43 @@ rk_uint rk_consume_events(
} }
XEvent x11_event; XEvent x11_event;
unsigned nevents = 0; unsigned nevents = 0;
for ( ; nevents < max_events ; ++nevents) { wchar_t string[256];
if (XCheckWindowEvent(rk_display, rk_window, rk_events_mask, &x11_event)) { KeySym keysym;
rk_event & event = events[nevents]; 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) { switch (x11_event.type) {
case KeyPress: case KeyPress:
event.type = RK_EVENT_KEY_PRESS; event.type = RK_EVENT_KEY_PRESS;
event.key.keycode = x11_event.xkey.keycode; 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; break;
case KeyRelease: case KeyRelease:
event.type = RK_EVENT_KEY_RELEASE; event.type = RK_EVENT_KEY_RELEASE;
event.key.keycode = x11_event.xkey.keycode; event.key.code = x11_event.xkey.keycode;
break; event.key.symbol = XLookupKeysym(&x11_event.xkey, 0);
} event.key.character = 0;
} else {
break; break;
} }
} }

View File

@ -21,9 +21,12 @@
#include <GLES3/gl32.h> #include <GLES3/gl32.h>
#include <X11/Xlib.h> #include <X11/Xlib.h>
extern unsigned rk_events_mask;
Display * rk_display = nullptr; Display * rk_display = nullptr;
Window rk_window = 0; 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 Colormap rk_colormap = 0;
static GLXContext rk_context = nullptr; static GLXContext rk_context = nullptr;
static bool rk_error_occured = false; static bool rk_error_occured = false;
@ -94,6 +97,8 @@ rk_window_t rk_create_context(
char const * name, char const * name,
unsigned width, unsigned width,
unsigned height) { unsigned height) {
XSetLocaleModifiers("");
rk_display = XOpenDisplay(nullptr); rk_display = XOpenDisplay(nullptr);
if (!rk_display) { if (!rk_display) {
rk_printf("Failed to open X 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), rk_window = XCreateWindow(rk_display, RootWindow(rk_display, vi->screen),
0, 0, width, height, 0, vi->depth, InputOutput, vi->visual, 0, 0, width, height, 0, vi->depth, InputOutput, vi->visual,
CWBorderPixel | CWColormap | CWEventMask, &swa); CWBorderPixel | CWColormap | CWEventMask, &swa);
XFree(vi);
if (!rk_window) { if (!rk_window) {
rk_printf("Failed to create window."); rk_printf("Failed to create window.");
rk_destroy_context(); rk_destroy_context();
return nullptr; return nullptr;
} }
XFree(vi);
XStoreName(rk_display, rk_window, name); 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); XMapWindow(rk_display, rk_window);
XSetICFocus(rk_input_context);
char const * const glx_exts = glXQueryExtensionsString(rk_display, DefaultScreen(rk_display)); char const * const glx_exts = glXQueryExtensionsString(rk_display, DefaultScreen(rk_display));
glXCreateContextAttribsARBProc const glXCreateContextAttribsARB = glXCreateContextAttribsARBProc const glXCreateContextAttribsARB =
@ -221,6 +244,15 @@ void rk_destroy_context() {
glXDestroyContext(rk_display, rk_context); glXDestroyContext(rk_display, rk_context);
rk_context = nullptr; 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) { if (rk_window) {
XDestroyWindow(rk_display, rk_window); XDestroyWindow(rk_display, rk_window);
rk_window = 0; rk_window = 0;