From 65b25c8be37aff5ab94c1c0b5a1410afa8a87f2b Mon Sep 17 00:00:00 2001 From: Roz K Date: Sat, 24 Dec 2022 06:36:20 +0100 Subject: [PATCH] Add button and motion events. --- __init__.py | 43 ++++++-- cpp/events.hpp | 37 +++++-- cpp/events/events_x11.cpp | 164 ++++++++++++++++++++++++++++-- cpp/opengl/render_context_glx.cpp | 29 +----- cpp/types.hpp | 8 +- 5 files changed, 232 insertions(+), 49 deletions(-) diff --git a/__init__.py b/__init__.py index 3eb5ece..eac4b35 100644 --- a/__init__.py +++ b/__init__.py @@ -345,24 +345,55 @@ destroy_shader.argtypes = ( terminate = _engine.rk_terminate -EVENT_KEY_PRESS = 0 -EVENT_KEY_RELEASE = 1 +EVENT_FOCUS_IN = 0 +EVENT_FOCUS_OUT = 1 +EVENT_KEY_PRESS = 2 +EVENT_KEY_RELEASE = 3 +EVENT_BUTTON_PRESS = 4 +EVENT_BUTTON_RELEASE = 5 +EVENT_MOTION = 6 + +BUTTON_LEFT = 1 +BUTTON_MIDDLE = 2 +BUTTON_RIGHT = 3 +BUTTON_WHEEL_UP = 4 +BUTTON_WHEEL_DOWN = 5 class _EventKey(ctypes.Structure): - _fields_ = ('code', ctypes.c_uint), ('symbol', ctypes.c_ushort), ('character', ctypes.c_wchar) + _fields_ = ( + ('code', ctypes.c_uint), + ('symbol', ctypes.c_uint), + ('character', ctypes.c_wchar)) + +class _EventButton(ctypes.Structure): + _fields_ = ('index', ctypes.c_uint), + +class _EventMotion(ctypes.Structure): + _fields_ = ( + ('x', ctypes.c_int), + ('y', ctypes.c_int)) class _Events(ctypes.Union): _fields_ = ( ('key', _EventKey), - ) + ('button', _EventButton), + ('motion', _EventMotion)) class Event(ctypes.Structure): _fields_ = ('type', ctypes.c_uint), ('data', _Events) +set_autorepeat = _engine.rk_set_autorepeat +set_autorepeat.argtypes = ( + ctypes.c_bool,) # autorepeat + +set_acceleration = _engine.rk_set_acceleration +set_acceleration.argtypes = ( + ctypes.c_uint, # numerator + ctypes.c_uint, # denominator + ctypes.c_uint) # threshold + consume_events = _engine.rk_consume_events consume_events.restype = ctypes.c_uint consume_events.argtypes = ( ctypes.POINTER(Event), # events ctypes.c_uint) # max_events - -flush_events = _engine.rk_flush_events diff --git a/cpp/events.hpp b/cpp/events.hpp index 593d73b..c6e7507 100644 --- a/cpp/events.hpp +++ b/cpp/events.hpp @@ -19,27 +19,52 @@ #include "types.hpp" enum rk_event_type : rk_uint { - RK_EVENT_KEY_PRESS = 0, - RK_EVENT_KEY_RELEASE = 1 + RK_EVENT_FOCUS_IN = 0, + RK_EVENT_FOCUS_OUT = 1, + RK_EVENT_KEY_PRESS = 2, + RK_EVENT_KEY_RELEASE = 3, + RK_EVENT_BUTTON_PRESS = 4, + RK_EVENT_BUTTON_RELEASE = 5, + RK_EVENT_MOTION = 6 }; struct rk_event_key { rk_uint code; - rk_ushort symbol; - wchar_t character; + rk_uint symbol; + rk_wchar character; +}; + +struct rk_event_button { + rk_uint index; +}; + +struct rk_event_motion { + rk_int x; + rk_int y; }; struct rk_event { rk_event_type type; union { rk_event_key key; + rk_event_button button; + rk_event_motion motion; }; }; +extern bool rk_initialize_events(); +extern void rk_terminate_events(); + +RK_EXPORT void rk_set_autorepeat( + rk_bool autorepeat); + +RK_EXPORT void rk_set_acceleration( + rk_uint numerator, + rk_uint denominator, + rk_uint threshold); + RK_EXPORT rk_uint rk_consume_events( rk_event * events, rk_uint max_events); -RK_EXPORT void rk_flush_events(); - #endif // _RK_ENGINE_EVENTS_H diff --git a/cpp/events/events_x11.cpp b/cpp/events/events_x11.cpp index a4689e4..e427769 100644 --- a/cpp/events/events_x11.cpp +++ b/cpp/events/events_x11.cpp @@ -18,27 +18,153 @@ extern Display * rk_display; extern Window rk_window; -extern XIC rk_input_context; -unsigned rk_events_mask = KeyPressMask | KeyReleaseMask; +unsigned rk_events_mask = FocusChangeMask | + KeyPressMask | KeyReleaseMask | ButtonPressMask | ButtonReleaseMask | PointerMotionMask; + +static XIM rk_input_manager = nullptr; +static XIC rk_input_context = nullptr; + +static bool rk_focused = false; +static bool rk_keyboard_autorepeat = false; +static XKeyboardState rk_previous_keyboard_state; +static int rk_previous_accel_numerator, rk_accel_numerator = 1; +static int rk_previous_accel_denominator, rk_accel_denominator = 1; +static int rk_previous_threshold, rk_accel_threshold = 0; + +static void rk_backup_setup() { + XGetKeyboardControl(rk_display, &rk_previous_keyboard_state); + XGetPointerControl(rk_display, + &rk_previous_accel_numerator, &rk_previous_accel_denominator, &rk_previous_threshold); +} + +static void rk_restore_setup() { + if (AutoRepeatModeOn == rk_previous_keyboard_state.global_auto_repeat) { + XAutoRepeatOn(rk_display); + } else { + XAutoRepeatOff(rk_display); + } + XChangePointerControl(rk_display, True, True, + rk_previous_accel_numerator, rk_previous_accel_denominator, rk_previous_threshold); +} + +static void rk_apply_setup() { + if (rk_keyboard_autorepeat) { + XAutoRepeatOn(rk_display); + } else { + XAutoRepeatOff(rk_display); + } + XChangePointerControl(rk_display, True, True, rk_accel_numerator, rk_accel_denominator, rk_accel_threshold); +} + +bool rk_initialize_events() { + rk_focused = false; + rk_backup_setup(); + rk_keyboard_autorepeat = (AutoRepeatModeOn == rk_previous_keyboard_state.global_auto_repeat); + rk_accel_numerator = rk_previous_accel_numerator; + rk_accel_denominator = rk_previous_accel_denominator; + rk_accel_threshold = rk_previous_threshold; + rk_input_manager = XOpenIM(rk_display, nullptr, nullptr, nullptr); + if (!rk_input_manager) { + return false; + } + rk_input_context = XCreateIC(rk_input_manager, + XNInputStyle, XIMPreeditNone | XIMStatusNone, + XNClientWindow, rk_window, + NULL); + if (!rk_input_context) { + return false; + } + XSetICFocus(rk_input_context); + return true; +} + +void rk_terminate_events() { + rk_restore_setup(); + 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; + } +} + +static void rk_focus_in() { + if (!rk_focused) { + rk_backup_setup(); + rk_apply_setup(); + XGrabPointer(rk_display, rk_window, True, + ButtonPressMask | ButtonReleaseMask | PointerMotionMask, + GrabModeAsync, GrabModeAsync, rk_window, None, CurrentTime); + rk_focused = true; + } +} + +static void rk_focus_out() { + if (rk_focused) { + XUngrabPointer(rk_display, CurrentTime); + rk_restore_setup(); + rk_focused = false; + } +} + +void rk_set_autorepeat( + rk_bool autorepeat) { + rk_keyboard_autorepeat = autorepeat; + if (rk_focused) { + rk_apply_setup(); + } +} + +void rk_set_acceleration( + rk_uint numerator, + rk_uint denominator, + rk_uint threshold) { + rk_accel_numerator = numerator; + rk_accel_denominator = denominator; + rk_accel_threshold = threshold; + if (rk_focused) { + rk_apply_setup(); + } +} rk_uint rk_consume_events( rk_event * events, rk_uint max_events) { + static wchar_t string[256]; if (!events || !max_events) { return 0; } XEvent x11_event; - unsigned nevents = 0; - wchar_t string[256]; KeySym keysym; Status status; + unsigned nevents = 0; 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++]; + rk_event & event = events[nevents]; switch (x11_event.type) { + + case FocusIn: + if (NotifyNormal == x11_event.xfocus.mode) { + rk_focus_in(); + event.type = RK_EVENT_FOCUS_IN; + ++nevents; + } + break; + + case FocusOut: + if (NotifyNormal == x11_event.xfocus.mode) { + rk_focus_out(); + event.type = RK_EVENT_FOCUS_OUT; + ++nevents; + } + break; + case KeyPress: event.type = RK_EVENT_KEY_PRESS; event.key.code = x11_event.xkey.keycode; @@ -61,20 +187,36 @@ rk_uint rk_consume_events( event.key.character = 0; break; } + ++nevents; 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; + ++nevents; + break; + + case ButtonPress: + event.type = RK_EVENT_BUTTON_PRESS; + event.button.index = x11_event.xbutton.button; + ++nevents; + break; + + case ButtonRelease: + event.type = RK_EVENT_BUTTON_RELEASE; + event.button.index = x11_event.xbutton.button; + ++nevents; + break; + + case MotionNotify: + event.type = RK_EVENT_MOTION; + event.motion.x = x11_event.xbutton.x; + event.motion.y = x11_event.xbutton.y; + ++nevents; break; } } return nevents; } - -void rk_flush_events() { - XEvent x11_event; - while (XCheckWindowEvent(rk_display, rk_window, rk_events_mask, &x11_event)) { - } -} diff --git a/cpp/opengl/render_context_glx.cpp b/cpp/opengl/render_context_glx.cpp index 8ddc963..92f8920 100644 --- a/cpp/opengl/render_context_glx.cpp +++ b/cpp/opengl/render_context_glx.cpp @@ -16,6 +16,7 @@ // Adapted from https://www.khronos.org/opengl/wiki/Tutorial:_OpenGL_3.0_Context_Creation_(GLX) #include "render_context.hpp" +#include "../events.hpp" #include #include #include @@ -25,8 +26,7 @@ extern unsigned rk_events_mask; Display * rk_display = nullptr; Window rk_window = 0; -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; @@ -164,24 +164,13 @@ rk_window_t rk_create_context( } 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."); + if (!rk_initialize_events()) { + rk_printf("Failed to initialize events."); 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 = @@ -244,15 +233,7 @@ 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; - } + rk_terminate_events(); if (rk_window) { XDestroyWindow(rk_display, rk_window); rk_window = 0; diff --git a/cpp/types.hpp b/cpp/types.hpp index ba918dd..72f22ee 100644 --- a/cpp/types.hpp +++ b/cpp/types.hpp @@ -18,11 +18,13 @@ #include #include -#include #define RK_EXPORT extern "C" -typedef void * rk_handle_t; +typedef bool rk_bool; +typedef char rk_char; +typedef wchar_t rk_wchar; +typedef int8_t rk_byte; typedef uint8_t rk_ubyte; typedef int16_t rk_short; typedef uint16_t rk_ushort; @@ -31,4 +33,6 @@ typedef uint32_t rk_uint; typedef int64_t rk_long; typedef uint64_t rk_ulong; +typedef void * rk_handle_t; + #endif // _RK_ENGINE_TYPES_H