| 
									
										
										
										
											2022-12-23 10:18:26 +01:00
										 |  |  | // 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 <http://www.gnu.org/licenses/>.
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include "../events.hpp"
 | 
					
						
							|  |  |  | #include <X11/Xlib.h>
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | extern Display * rk_display; | 
					
						
							|  |  |  | extern Window rk_window; | 
					
						
							| 
									
										
										
										
											2022-12-23 13:28:29 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-12-24 06:36:20 +01:00
										 |  |  | 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(); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2022-12-23 10:18:26 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | rk_uint rk_consume_events( | 
					
						
							|  |  |  |     rk_event * events, | 
					
						
							|  |  |  |     rk_uint max_events) { | 
					
						
							| 
									
										
										
										
											2022-12-24 06:36:20 +01:00
										 |  |  |     static wchar_t string[256]; | 
					
						
							| 
									
										
										
										
											2022-12-23 10:18:26 +01:00
										 |  |  |     if (!events || !max_events) { | 
					
						
							|  |  |  |         return 0; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     XEvent x11_event; | 
					
						
							| 
									
										
										
										
											2022-12-23 13:28:29 +01:00
										 |  |  |     KeySym keysym; | 
					
						
							|  |  |  |     Status status; | 
					
						
							| 
									
										
										
										
											2022-12-24 06:36:20 +01:00
										 |  |  |     unsigned nevents = 0; | 
					
						
							| 
									
										
										
										
											2022-12-23 13:28:29 +01:00
										 |  |  |     while (nevents < max_events && XCheckWindowEvent(rk_display, rk_window, rk_events_mask, &x11_event)) { | 
					
						
							|  |  |  |         if (XFilterEvent(&x11_event, 0)) { | 
					
						
							|  |  |  |             continue; | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2022-12-24 06:36:20 +01:00
										 |  |  |         rk_event & event = events[nevents]; | 
					
						
							| 
									
										
										
										
											2022-12-23 13:28:29 +01:00
										 |  |  |         switch (x11_event.type) { | 
					
						
							| 
									
										
										
										
											2022-12-24 06:36:20 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |             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; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-12-23 13:28:29 +01:00
										 |  |  |             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; | 
					
						
							|  |  |  |                 } | 
					
						
							| 
									
										
										
										
											2022-12-24 06:36:20 +01:00
										 |  |  |                 ++nevents; | 
					
						
							| 
									
										
										
										
											2022-12-23 13:28:29 +01:00
										 |  |  |                 break; | 
					
						
							| 
									
										
										
										
											2022-12-24 06:36:20 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-12-23 13:28:29 +01:00
										 |  |  |             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; | 
					
						
							| 
									
										
										
										
											2022-12-24 06:36:20 +01:00
										 |  |  |                 ++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; | 
					
						
							| 
									
										
										
										
											2022-12-23 13:28:29 +01:00
										 |  |  |                 break; | 
					
						
							| 
									
										
										
										
											2022-12-23 10:18:26 +01:00
										 |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     return nevents; | 
					
						
							|  |  |  | } |