| 
									
										
										
										
											2013-07-09 22:49:58 -08:00
										 |  |  | // Copyright 2013 Max Eliaser
 | 
					
						
							| 
									
										
										
										
											2015-05-25 13:11:41 +02:00
										 |  |  | // Licensed under GPLv2+
 | 
					
						
							| 
									
										
										
										
											2013-07-09 22:49:58 -08:00
										 |  |  | // Refer to the license.txt file included.
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  | #include <X11/XKBlib.h>
 | 
					
						
							| 
									
										
										
										
											2013-07-09 22:49:58 -08:00
										 |  |  | #include <cmath>
 | 
					
						
							| 
									
										
										
										
											2015-10-05 22:45:55 -05:00
										 |  |  | #include <cstdlib>
 | 
					
						
							| 
									
										
										
										
											2014-09-18 23:17:41 -05:00
										 |  |  | #include <cstring>
 | 
					
						
							| 
									
										
										
										
											2014-02-17 05:18:15 -05:00
										 |  |  | 
 | 
					
						
							|  |  |  | #include "InputCommon/ControllerInterface/Xlib/XInput2.h"
 | 
					
						
							| 
									
										
										
										
											2013-07-09 22:49:58 -08:00
										 |  |  | 
 | 
					
						
							|  |  |  | // This is an input plugin using the XInput 2.0 extension to the X11 protocol,
 | 
					
						
							| 
									
										
										
										
											2013-10-29 01:23:17 -04:00
										 |  |  | // loosely based on the old XLib plugin. (Has nothing to do with the XInput
 | 
					
						
							|  |  |  | // API on Windows.)
 | 
					
						
							| 
									
										
										
										
											2013-07-09 22:49:58 -08:00
										 |  |  | 
 | 
					
						
							|  |  |  | // This plugin creates one KeyboardMouse object for each master pointer/
 | 
					
						
							|  |  |  | // keyboard pair. Each KeyboardMouse object exports four types of controls:
 | 
					
						
							|  |  |  | // *    Mouse button controls: hardcoded at five of them, but could be made to
 | 
					
						
							|  |  |  | //      support infinitely many mouse buttons in theory; XInput2 has no limit.
 | 
					
						
							|  |  |  | // *    Mouse cursor controls: one for each cardinal direction. Calculated by
 | 
					
						
							|  |  |  | //      comparing the absolute position of the mouse pointer on screen to the
 | 
					
						
							|  |  |  | //      center of the emulator window.
 | 
					
						
							|  |  |  | // *    Mouse axis controls: one for each cardinal direction. Calculated using
 | 
					
						
							|  |  |  | //      a running average of relative mouse motion on each axis.
 | 
					
						
							| 
									
										
										
										
											2013-10-29 01:23:17 -04:00
										 |  |  | // *    Key controls: these correspond to a limited subset of the keyboard
 | 
					
						
							| 
									
										
										
										
											2013-07-09 22:49:58 -08:00
										 |  |  | //      keys.
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Mouse axis control tuning. Unlike absolute mouse position, relative mouse
 | 
					
						
							|  |  |  | // motion data needs to be tweaked and smoothed out a bit to be usable.
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-10-29 01:23:17 -04:00
										 |  |  | // Mouse axis control output is simply divided by this number. In practice,
 | 
					
						
							| 
									
										
										
										
											2013-07-09 22:49:58 -08:00
										 |  |  | // that just means you can use a smaller "dead zone" if you bind axis controls
 | 
					
						
							|  |  |  | // to a joystick. No real need to make this customizable.
 | 
					
						
							| 
									
										
										
										
											2014-02-16 15:30:18 -05:00
										 |  |  | #define MOUSE_AXIS_SENSITIVITY 8.0f
 | 
					
						
							| 
									
										
										
										
											2013-07-09 22:49:58 -08:00
										 |  |  | 
 | 
					
						
							|  |  |  | // The mouse axis controls use a weighted running average. Each frame, the new
 | 
					
						
							| 
									
										
										
										
											2013-10-29 01:23:17 -04:00
										 |  |  | // value is the average of the old value and the amount of relative mouse
 | 
					
						
							| 
									
										
										
										
											2013-07-09 22:49:58 -08:00
										 |  |  | // motion during that frame. The old value is weighted by a ratio of
 | 
					
						
							|  |  |  | // MOUSE_AXIS_SMOOTHING:1 compared to the new value. Increasing
 | 
					
						
							|  |  |  | // MOUSE_AXIS_SMOOTHING makes the controls smoother, decreasing it makes them
 | 
					
						
							|  |  |  | // more responsive. This might be useful as a user-customizable option.
 | 
					
						
							| 
									
										
										
										
											2014-02-16 15:30:18 -05:00
										 |  |  | #define MOUSE_AXIS_SMOOTHING 1.5f
 | 
					
						
							| 
									
										
										
										
											2013-07-09 22:49:58 -08:00
										 |  |  | 
 | 
					
						
							|  |  |  | namespace ciface | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | namespace XInput2 | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | // This function will add zero or more KeyboardMouse objects to devices.
 | 
					
						
							| 
									
										
										
										
											2016-10-16 13:39:05 -07:00
										 |  |  | void PopulateDevices(void* const hwnd) | 
					
						
							| 
									
										
										
										
											2013-07-09 22:49:58 -08:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   Display* dpy = XOpenDisplay(nullptr); | 
					
						
							| 
									
										
										
										
											2013-10-29 01:23:17 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   // xi_opcode is important; it will be used to identify XInput events by
 | 
					
						
							|  |  |  |   // the polling loop in UpdateInput.
 | 
					
						
							|  |  |  |   int xi_opcode, event, error; | 
					
						
							| 
									
										
										
										
											2013-10-29 01:23:17 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   // verify that the XInput extension is available
 | 
					
						
							|  |  |  |   if (!XQueryExtension(dpy, "XInputExtension", &xi_opcode, &event, &error)) | 
					
						
							|  |  |  |     return; | 
					
						
							| 
									
										
										
										
											2013-10-29 01:23:17 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   // verify that the XInput extension is at at least version 2.0
 | 
					
						
							|  |  |  |   int major = 2, minor = 0; | 
					
						
							| 
									
										
										
										
											2013-10-29 01:23:17 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   if (XIQueryVersion(dpy, &major, &minor) != Success) | 
					
						
							|  |  |  |     return; | 
					
						
							| 
									
										
										
										
											2013-10-29 01:23:17 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   // register all master devices with Dolphin
 | 
					
						
							| 
									
										
										
										
											2013-10-29 01:23:17 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   XIDeviceInfo* all_masters; | 
					
						
							|  |  |  |   XIDeviceInfo* current_master; | 
					
						
							|  |  |  |   int num_masters; | 
					
						
							| 
									
										
										
										
											2013-10-29 01:23:17 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   all_masters = XIQueryDevice(dpy, XIAllMasterDevices, &num_masters); | 
					
						
							| 
									
										
										
										
											2013-10-29 01:23:17 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   for (int i = 0; i < num_masters; i++) | 
					
						
							|  |  |  |   { | 
					
						
							|  |  |  |     current_master = &all_masters[i]; | 
					
						
							|  |  |  |     if (current_master->use == XIMasterPointer) | 
					
						
							| 
									
										
										
										
											2016-06-25 21:46:39 +02:00
										 |  |  |     { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |       // Since current_master is a master pointer, its attachment must
 | 
					
						
							|  |  |  |       // be a master keyboard.
 | 
					
						
							| 
									
										
										
										
											2016-06-25 21:46:39 +02:00
										 |  |  |       g_controller_interface.AddDevice(std::make_shared<KeyboardMouse>( | 
					
						
							| 
									
										
										
										
											2016-06-12 17:08:04 +02:00
										 |  |  |           (Window)hwnd, xi_opcode, current_master->deviceid, current_master->attachment)); | 
					
						
							| 
									
										
										
										
											2016-06-25 21:46:39 +02:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   } | 
					
						
							| 
									
										
										
										
											2013-10-29 01:23:17 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   XCloseDisplay(dpy); | 
					
						
							| 
									
										
										
										
											2013-10-29 01:23:17 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   XIFreeDeviceInfo(all_masters); | 
					
						
							| 
									
										
										
										
											2013-07-09 22:49:58 -08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-10-29 01:23:17 -04:00
										 |  |  | // Apply the event mask to the device and all its slaves. Only used in the
 | 
					
						
							| 
									
										
										
										
											2013-07-09 22:49:58 -08:00
										 |  |  | // constructor. Remember, each KeyboardMouse has its own copy of the event
 | 
					
						
							|  |  |  | // stream, which is how multiple event masks can "coexist."
 | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  | void KeyboardMouse::SelectEventsForDevice(Window window, XIEventMask* mask, int deviceid) | 
					
						
							| 
									
										
										
										
											2013-07-09 22:49:58 -08:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   // Set the event mask for the master device.
 | 
					
						
							|  |  |  |   mask->deviceid = deviceid; | 
					
						
							|  |  |  |   XISelectEvents(m_display, window, mask, 1); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   // Query all the master device's slaves and set the same event mask for
 | 
					
						
							|  |  |  |   // those too. There are two reasons we want to do this. For mouse devices,
 | 
					
						
							|  |  |  |   // we want the raw motion events, and only slaves (i.e. physical hardware
 | 
					
						
							|  |  |  |   // devices) emit those. For keyboard devices, selecting slaves avoids
 | 
					
						
							|  |  |  |   // dealing with key focus.
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   XIDeviceInfo* all_slaves; | 
					
						
							|  |  |  |   XIDeviceInfo* current_slave; | 
					
						
							|  |  |  |   int num_slaves; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   all_slaves = XIQueryDevice(m_display, XIAllDevices, &num_slaves); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   for (int i = 0; i < num_slaves; i++) | 
					
						
							|  |  |  |   { | 
					
						
							|  |  |  |     current_slave = &all_slaves[i]; | 
					
						
							|  |  |  |     if ((current_slave->use != XISlavePointer && current_slave->use != XISlaveKeyboard) || | 
					
						
							|  |  |  |         current_slave->attachment != deviceid) | 
					
						
							|  |  |  |       continue; | 
					
						
							|  |  |  |     mask->deviceid = current_slave->deviceid; | 
					
						
							|  |  |  |     XISelectEvents(m_display, window, mask, 1); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   XIFreeDeviceInfo(all_slaves); | 
					
						
							| 
									
										
										
										
											2013-07-09 22:49:58 -08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-10-29 01:23:17 -04:00
										 |  |  | KeyboardMouse::KeyboardMouse(Window window, int opcode, int pointer, int keyboard) | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |     : m_window(window), xi_opcode(opcode), pointer_deviceid(pointer), keyboard_deviceid(keyboard) | 
					
						
							| 
									
										
										
										
											2013-07-09 22:49:58 -08:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   memset(&m_state, 0, sizeof(m_state)); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   // The cool thing about each KeyboardMouse object having its own Display
 | 
					
						
							|  |  |  |   // is that each one gets its own separate copy of the X11 event stream,
 | 
					
						
							|  |  |  |   // which it can individually filter to get just the events it's interested
 | 
					
						
							|  |  |  |   // in. So be aware that each KeyboardMouse object actually has its own X11
 | 
					
						
							|  |  |  |   // "context."
 | 
					
						
							|  |  |  |   m_display = XOpenDisplay(nullptr); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   int min_keycode, max_keycode; | 
					
						
							|  |  |  |   XDisplayKeycodes(m_display, &min_keycode, &max_keycode); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   int unused;  // should always be 1
 | 
					
						
							|  |  |  |   XIDeviceInfo* pointer_device = XIQueryDevice(m_display, pointer_deviceid, &unused); | 
					
						
							|  |  |  |   name = std::string(pointer_device->name); | 
					
						
							|  |  |  |   XIFreeDeviceInfo(pointer_device); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   XIEventMask mask; | 
					
						
							|  |  |  |   unsigned char mask_buf[(XI_LASTEVENT + 7) / 8]; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   mask.mask_len = sizeof(mask_buf); | 
					
						
							|  |  |  |   mask.mask = mask_buf; | 
					
						
							|  |  |  |   memset(mask_buf, 0, sizeof(mask_buf)); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   XISetMask(mask_buf, XI_ButtonPress); | 
					
						
							|  |  |  |   XISetMask(mask_buf, XI_ButtonRelease); | 
					
						
							|  |  |  |   XISetMask(mask_buf, XI_RawMotion); | 
					
						
							|  |  |  |   XISetMask(mask_buf, XI_KeyPress); | 
					
						
							|  |  |  |   XISetMask(mask_buf, XI_KeyRelease); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   SelectEventsForDevice(DefaultRootWindow(m_display), &mask, pointer_deviceid); | 
					
						
							|  |  |  |   SelectEventsForDevice(DefaultRootWindow(m_display), &mask, keyboard_deviceid); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   // Keyboard Keys
 | 
					
						
							|  |  |  |   for (int i = min_keycode; i <= max_keycode; ++i) | 
					
						
							|  |  |  |   { | 
					
						
							|  |  |  |     Key* temp_key = new Key(m_display, i, m_state.keyboard); | 
					
						
							|  |  |  |     if (temp_key->m_keyname.length()) | 
					
						
							|  |  |  |       AddInput(temp_key); | 
					
						
							|  |  |  |     else | 
					
						
							|  |  |  |       delete temp_key; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   // Mouse Buttons
 | 
					
						
							|  |  |  |   for (int i = 0; i < 5; i++) | 
					
						
							|  |  |  |     AddInput(new Button(i, &m_state.buttons)); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   // Mouse Cursor, X-/+ and Y-/+
 | 
					
						
							|  |  |  |   for (int i = 0; i != 4; ++i) | 
					
						
							|  |  |  |     AddInput(new Cursor(!!(i & 2), !!(i & 1), (i & 2) ? &m_state.cursor.y : &m_state.cursor.x)); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   // Mouse Axis, X-/+ and Y-/+
 | 
					
						
							|  |  |  |   for (int i = 0; i != 4; ++i) | 
					
						
							|  |  |  |     AddInput(new Axis(!!(i & 2), !!(i & 1), (i & 2) ? &m_state.axis.y : &m_state.axis.x)); | 
					
						
							| 
									
										
										
										
											2013-07-09 22:49:58 -08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | KeyboardMouse::~KeyboardMouse() | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   XCloseDisplay(m_display); | 
					
						
							| 
									
										
										
										
											2013-07-09 22:49:58 -08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Update the mouse cursor controls
 | 
					
						
							|  |  |  | void KeyboardMouse::UpdateCursor() | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   double root_x, root_y, win_x, win_y; | 
					
						
							|  |  |  |   Window root, child; | 
					
						
							| 
									
										
										
										
											2013-10-29 01:23:17 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   // unused-- we're not interested in button presses here, as those are
 | 
					
						
							|  |  |  |   // updated using events
 | 
					
						
							|  |  |  |   XIButtonState button_state; | 
					
						
							|  |  |  |   XIModifierState mods; | 
					
						
							|  |  |  |   XIGroupState group; | 
					
						
							| 
									
										
										
										
											2013-10-29 01:23:17 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   XIQueryPointer(m_display, pointer_deviceid, m_window, &root, &child, &root_x, &root_y, &win_x, | 
					
						
							|  |  |  |                  &win_y, &button_state, &mods, &group); | 
					
						
							| 
									
										
										
										
											2013-10-29 01:23:17 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   free(button_state.mask); | 
					
						
							| 
									
										
										
										
											2013-07-09 22:49:58 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   XWindowAttributes win_attribs; | 
					
						
							|  |  |  |   XGetWindowAttributes(m_display, m_window, &win_attribs); | 
					
						
							| 
									
										
										
										
											2013-07-09 22:49:58 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   // the mouse position as a range from -1 to 1
 | 
					
						
							|  |  |  |   m_state.cursor.x = win_x / (float)win_attribs.width * 2 - 1; | 
					
						
							|  |  |  |   m_state.cursor.y = win_y / (float)win_attribs.height * 2 - 1; | 
					
						
							| 
									
										
										
										
											2013-07-09 22:49:58 -08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-11-13 00:55:14 -08:00
										 |  |  | void KeyboardMouse::UpdateInput() | 
					
						
							| 
									
										
										
										
											2013-07-09 22:49:58 -08:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   XFlush(m_display); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   // for the axis controls
 | 
					
						
							|  |  |  |   float delta_x = 0.0f, delta_y = 0.0f; | 
					
						
							|  |  |  |   double delta_delta; | 
					
						
							| 
									
										
										
										
											2016-09-03 15:03:18 -07:00
										 |  |  |   bool mouse_moved = false; | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |   // Iterate through the event queue - update the axis controls, mouse
 | 
					
						
							|  |  |  |   // button controls, and keyboard controls.
 | 
					
						
							|  |  |  |   XEvent event; | 
					
						
							|  |  |  |   while (XPending(m_display)) | 
					
						
							|  |  |  |   { | 
					
						
							|  |  |  |     XNextEvent(m_display, &event); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (event.xcookie.type != GenericEvent) | 
					
						
							|  |  |  |       continue; | 
					
						
							|  |  |  |     if (event.xcookie.extension != xi_opcode) | 
					
						
							|  |  |  |       continue; | 
					
						
							|  |  |  |     if (!XGetEventData(m_display, &event.xcookie)) | 
					
						
							|  |  |  |       continue; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     // only one of these will get used
 | 
					
						
							|  |  |  |     XIDeviceEvent* dev_event = (XIDeviceEvent*)event.xcookie.data; | 
					
						
							|  |  |  |     XIRawEvent* raw_event = (XIRawEvent*)event.xcookie.data; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     switch (event.xcookie.evtype) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |     case XI_ButtonPress: | 
					
						
							|  |  |  |       m_state.buttons |= 1 << (dev_event->detail - 1); | 
					
						
							|  |  |  |       break; | 
					
						
							|  |  |  |     case XI_ButtonRelease: | 
					
						
							|  |  |  |       m_state.buttons &= ~(1 << (dev_event->detail - 1)); | 
					
						
							|  |  |  |       break; | 
					
						
							|  |  |  |     case XI_KeyPress: | 
					
						
							|  |  |  |       m_state.keyboard[dev_event->detail / 8] |= 1 << (dev_event->detail % 8); | 
					
						
							|  |  |  |       break; | 
					
						
							|  |  |  |     case XI_KeyRelease: | 
					
						
							|  |  |  |       m_state.keyboard[dev_event->detail / 8] &= ~(1 << (dev_event->detail % 8)); | 
					
						
							|  |  |  |       break; | 
					
						
							|  |  |  |     case XI_RawMotion: | 
					
						
							| 
									
										
										
										
											2016-09-03 15:03:18 -07:00
										 |  |  |       mouse_moved = true; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |       // always safe because there is always at least one byte in
 | 
					
						
							|  |  |  |       // raw_event->valuators.mask, and if a bit is set in the mask,
 | 
					
						
							|  |  |  |       // then the value in raw_values is also available.
 | 
					
						
							|  |  |  |       if (XIMaskIsSet(raw_event->valuators.mask, 0)) | 
					
						
							|  |  |  |       { | 
					
						
							|  |  |  |         delta_delta = raw_event->raw_values[0]; | 
					
						
							|  |  |  |         // test for inf and nan
 | 
					
						
							|  |  |  |         if (delta_delta == delta_delta && 1 + delta_delta != delta_delta) | 
					
						
							|  |  |  |           delta_x += delta_delta; | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |       if (XIMaskIsSet(raw_event->valuators.mask, 1)) | 
					
						
							|  |  |  |       { | 
					
						
							|  |  |  |         delta_delta = raw_event->raw_values[1]; | 
					
						
							|  |  |  |         // test for inf and nan
 | 
					
						
							|  |  |  |         if (delta_delta == delta_delta && 1 + delta_delta != delta_delta) | 
					
						
							|  |  |  |           delta_y += delta_delta; | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |       break; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     XFreeEventData(m_display, &event.xcookie); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   // apply axis smoothing
 | 
					
						
							|  |  |  |   m_state.axis.x *= MOUSE_AXIS_SMOOTHING; | 
					
						
							|  |  |  |   m_state.axis.x += delta_x; | 
					
						
							|  |  |  |   m_state.axis.x /= MOUSE_AXIS_SMOOTHING + 1.0f; | 
					
						
							|  |  |  |   m_state.axis.y *= MOUSE_AXIS_SMOOTHING; | 
					
						
							|  |  |  |   m_state.axis.y += delta_y; | 
					
						
							|  |  |  |   m_state.axis.y /= MOUSE_AXIS_SMOOTHING + 1.0f; | 
					
						
							| 
									
										
										
										
											2016-09-03 15:03:18 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  |   // Get the absolute position of the mouse pointer
 | 
					
						
							|  |  |  |   if (mouse_moved) | 
					
						
							|  |  |  |     UpdateCursor(); | 
					
						
							| 
									
										
										
										
											2013-07-09 22:49:58 -08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | std::string KeyboardMouse::GetName() const | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   // This is the name string we got from the X server for this master
 | 
					
						
							|  |  |  |   // pointer/keyboard pair.
 | 
					
						
							|  |  |  |   return name; | 
					
						
							| 
									
										
										
										
											2013-07-09 22:49:58 -08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | std::string KeyboardMouse::GetSource() const | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   return "XInput2"; | 
					
						
							| 
									
										
										
										
											2013-07-09 22:49:58 -08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | KeyboardMouse::Key::Key(Display* const display, KeyCode keycode, const char* keyboard) | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |     : m_display(display), m_keyboard(keyboard), m_keycode(keycode) | 
					
						
							| 
									
										
										
										
											2013-07-09 22:49:58 -08:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   int i = 0; | 
					
						
							|  |  |  |   KeySym keysym = 0; | 
					
						
							|  |  |  |   do | 
					
						
							|  |  |  |   { | 
					
						
							|  |  |  |     keysym = XkbKeycodeToKeysym(m_display, keycode, i, 0); | 
					
						
							|  |  |  |     i++; | 
					
						
							|  |  |  |   } while (keysym == NoSymbol && i < 8); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   // Convert to upper case for the keyname
 | 
					
						
							|  |  |  |   if (keysym >= 97 && keysym <= 122) | 
					
						
							|  |  |  |     keysym -= 32; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   // 0x0110ffff is the top of the unicode character range according
 | 
					
						
							|  |  |  |   // to keysymdef.h although it is probably more than we need.
 | 
					
						
							|  |  |  |   if (keysym == NoSymbol || keysym > 0x0110ffff || XKeysymToString(keysym) == nullptr) | 
					
						
							|  |  |  |     m_keyname = std::string(); | 
					
						
							|  |  |  |   else | 
					
						
							|  |  |  |     m_keyname = std::string(XKeysymToString(keysym)); | 
					
						
							| 
									
										
										
										
											2013-07-09 22:49:58 -08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | ControlState KeyboardMouse::Key::GetState() const | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   return (m_keyboard[m_keycode / 8] & (1 << (m_keycode % 8))) != 0; | 
					
						
							| 
									
										
										
										
											2013-07-09 22:49:58 -08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-10-02 02:20:46 -04:00
										 |  |  | KeyboardMouse::Button::Button(unsigned int index, unsigned int* buttons) | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |     : m_buttons(buttons), m_index(index) | 
					
						
							| 
									
										
										
										
											2013-07-09 22:49:58 -08:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   // this will be a problem if we remove the hardcoded five-button limit
 | 
					
						
							|  |  |  |   name = std::string("Click ") + (char)('1' + m_index); | 
					
						
							| 
									
										
										
										
											2013-07-09 22:49:58 -08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-07-20 13:39:28 -08:00
										 |  |  | ControlState KeyboardMouse::Button::GetState() const | 
					
						
							| 
									
										
										
										
											2013-07-09 22:49:58 -08:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   return ((*m_buttons & (1 << m_index)) != 0); | 
					
						
							| 
									
										
										
										
											2013-07-09 22:49:58 -08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-10-02 02:20:46 -04:00
										 |  |  | KeyboardMouse::Cursor::Cursor(u8 index, bool positive, const float* cursor) | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |     : m_cursor(cursor), m_index(index), m_positive(positive) | 
					
						
							| 
									
										
										
										
											2013-07-09 22:49:58 -08:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   name = std::string("Cursor ") + (char)('X' + m_index) + (m_positive ? '+' : '-'); | 
					
						
							| 
									
										
										
										
											2013-07-09 22:49:58 -08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-07-20 13:39:28 -08:00
										 |  |  | ControlState KeyboardMouse::Cursor::GetState() const | 
					
						
							| 
									
										
										
										
											2013-07-09 22:49:58 -08:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   return std::max(0.0f, *m_cursor / (m_positive ? 1.0f : -1.0f)); | 
					
						
							| 
									
										
										
										
											2013-07-09 22:49:58 -08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-10-02 02:20:46 -04:00
										 |  |  | KeyboardMouse::Axis::Axis(u8 index, bool positive, const float* axis) | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |     : m_axis(axis), m_index(index), m_positive(positive) | 
					
						
							| 
									
										
										
										
											2013-07-09 22:49:58 -08:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   name = std::string("Axis ") + (char)('X' + m_index) + (m_positive ? '+' : '-'); | 
					
						
							| 
									
										
										
										
											2013-07-09 22:49:58 -08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-07-20 13:39:28 -08:00
										 |  |  | ControlState KeyboardMouse::Axis::GetState() const | 
					
						
							| 
									
										
										
										
											2013-07-09 22:49:58 -08:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   return std::max(0.0f, *m_axis / (m_positive ? MOUSE_AXIS_SENSITIVITY : -MOUSE_AXIS_SENSITIVITY)); | 
					
						
							| 
									
										
										
										
											2013-07-09 22:49:58 -08:00
										 |  |  | } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | } |