// Copyright (C) 2022 RozK // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Affero General Public License for more details. // // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . #include "../events.hpp" #include extern Display * rk_display; extern Window rk_window; 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; 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]; 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; 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; } ++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; }