XInput2.cpp 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501
  1. // Copyright 2013 Max Eliaser
  2. // SPDX-License-Identifier: GPL-2.0-or-later
  3. #include "InputCommon/ControllerInterface/Xlib/XInput2.h"
  4. #include <X11/XKBlib.h>
  5. #include <X11/extensions/XInput2.h>
  6. #include <cmath>
  7. #include <cstdlib>
  8. #include <cstring>
  9. #include <fmt/format.h>
  10. #include "Common/Logging/Log.h"
  11. #include "Common/StringUtil.h"
  12. #include "Core/Host.h"
  13. // This is an input plugin using the XInput 2.0 extension to the X11 protocol,
  14. // loosely based on the old XLib plugin. (Has nothing to do with the XInput
  15. // API on Windows.)
  16. // This plugin creates one KeyboardMouse object for each master pointer/
  17. // keyboard pair. Each KeyboardMouse object exports four types of controls:
  18. // * Mouse button controls: hardcoded at 32 of them, but could be made to
  19. // support infinitely many mouse buttons in theory; XInput2 has no limit.
  20. // * Mouse cursor controls: one for each cardinal direction. Calculated by
  21. // comparing the absolute position of the mouse pointer on screen to the
  22. // center of the emulator window.
  23. // * Mouse axis controls: one for each cardinal direction. Calculated using
  24. // a running average of relative mouse motion on each axis.
  25. // * Key controls: these correspond to a limited subset of the keyboard
  26. // keys.
  27. // Mouse axis control tuning. Unlike absolute mouse position, relative mouse
  28. // motion data needs to be tweaked and smoothed out a bit to be usable.
  29. // Mouse axis control output is simply divided by this number. In practice,
  30. // that just means you can use a smaller "dead zone" if you bind axis controls
  31. // to a joystick. No real need to make this customizable.
  32. #define MOUSE_AXIS_SENSITIVITY 8.0f
  33. // The mouse axis controls use a weighted running average. Each frame, the new
  34. // value is the average of the old value and the amount of relative mouse
  35. // motion during that frame. The old value is weighted by a ratio of
  36. // MOUSE_AXIS_SMOOTHING:1 compared to the new value. Increasing
  37. // MOUSE_AXIS_SMOOTHING makes the controls smoother, decreasing it makes them
  38. // more responsive. This might be useful as a user-customizable option.
  39. #define MOUSE_AXIS_SMOOTHING 1.5f
  40. // The scroll axis value should decay a lot faster than the mouse axes since
  41. // it should ideally register each click of the scroll wheel. Decreasing this
  42. // value makes it more likely that a scroll wheel input is registered, but less
  43. // likely to differentiate between different inputs, while increasing it will
  44. // more cleanly separate each scroll wheel click, but risks dropping some inputs
  45. #define SCROLL_AXIS_DECAY 1.1f
  46. namespace
  47. {
  48. // We need XInput 2.1 to get raw events on the root window even while another
  49. // client has a grab. If we request 2.2 or later, the server will not generate
  50. // emulated button presses from touch events, so we want exactly 2.1.
  51. constexpr int XINPUT_MAJOR = 2, XINPUT_MINOR = 1;
  52. } // namespace
  53. namespace ciface::XInput2
  54. {
  55. constexpr std::string_view SOURCE_NAME = "XInput2";
  56. class InputBackend final : public ciface::InputBackend
  57. {
  58. public:
  59. using ciface::InputBackend::InputBackend;
  60. void PopulateDevices() override;
  61. void HandleWindowChange() override;
  62. };
  63. std::unique_ptr<ciface::InputBackend> CreateInputBackend(ControllerInterface* controller_interface)
  64. {
  65. return std::make_unique<InputBackend>(controller_interface);
  66. }
  67. void InputBackend::HandleWindowChange()
  68. {
  69. GetControllerInterface().RemoveDevice(
  70. [](const auto* dev) { return dev->GetSource() == SOURCE_NAME; }, true);
  71. PopulateDevices();
  72. }
  73. // This function will add zero or more KeyboardMouse objects to devices.
  74. void InputBackend::PopulateDevices()
  75. {
  76. const WindowSystemInfo wsi = GetControllerInterface().GetWindowSystemInfo();
  77. if (wsi.type != WindowSystemType::X11)
  78. return;
  79. const auto hwnd = wsi.render_window;
  80. Display* dpy = XOpenDisplay(nullptr);
  81. // xi_opcode is important; it will be used to identify XInput events by
  82. // the polling loop in UpdateInput.
  83. int xi_opcode, event, error;
  84. // verify that the XInput extension is available
  85. if (!XQueryExtension(dpy, "XInputExtension", &xi_opcode, &event, &error))
  86. {
  87. WARN_LOG_FMT(CONTROLLERINTERFACE, "XInput extension not available (XQueryExtension)");
  88. return;
  89. }
  90. int major = XINPUT_MAJOR, minor = XINPUT_MINOR;
  91. if (XIQueryVersion(dpy, &major, &minor) != Success || major < XINPUT_MAJOR ||
  92. (major == XINPUT_MAJOR && minor < XINPUT_MINOR))
  93. {
  94. WARN_LOG_FMT(CONTROLLERINTERFACE, "XInput extension not available (XIQueryVersion)");
  95. return;
  96. }
  97. // register all master devices with Dolphin
  98. XIDeviceInfo* all_masters;
  99. XIDeviceInfo* current_master;
  100. double scroll_increment = 1.0f;
  101. int num_masters;
  102. all_masters = XIQueryDevice(dpy, XIAllMasterDevices, &num_masters);
  103. for (int i = 0; i < num_masters; i++)
  104. {
  105. current_master = &all_masters[i];
  106. if (current_master->use == XIMasterPointer)
  107. {
  108. // We need to query the master for the scroll wheel's increment, since the increment used
  109. // varies depending on what input driver is being used. For example, xf86-libinput uses 120.0.
  110. for (int j = 0; j < current_master->num_classes; j++)
  111. {
  112. if (current_master->classes[j]->type == XIScrollClass)
  113. {
  114. XIScrollClassInfo* scroll_event =
  115. reinterpret_cast<XIScrollClassInfo*>(current_master->classes[j]);
  116. scroll_increment = scroll_event->increment;
  117. break;
  118. }
  119. }
  120. // Since current_master is a master pointer, its attachment must
  121. // be a master keyboard.
  122. GetControllerInterface().AddDevice(
  123. std::make_shared<KeyboardMouse>((Window)hwnd, xi_opcode, current_master->deviceid,
  124. current_master->attachment, scroll_increment));
  125. }
  126. }
  127. XCloseDisplay(dpy);
  128. XIFreeDeviceInfo(all_masters);
  129. }
  130. KeyboardMouse::KeyboardMouse(Window window, int opcode, int pointer, int keyboard,
  131. double scroll_increment_)
  132. : m_window(window), xi_opcode(opcode), pointer_deviceid(pointer), keyboard_deviceid(keyboard),
  133. scroll_increment(scroll_increment_)
  134. {
  135. // The cool thing about each KeyboardMouse object having its own Display
  136. // is that each one gets its own separate copy of the X11 event stream,
  137. // which it can individually filter to get just the events it's interested
  138. // in. So be aware that each KeyboardMouse object actually has its own X11
  139. // "context."
  140. m_display = XOpenDisplay(nullptr);
  141. int major = XINPUT_MAJOR, minor = XINPUT_MINOR;
  142. XIQueryVersion(m_display, &major, &minor);
  143. // should always be 1
  144. int unused;
  145. XIDeviceInfo* const pointer_device = XIQueryDevice(m_display, pointer_deviceid, &unused);
  146. name = std::string(pointer_device->name);
  147. XIFreeDeviceInfo(pointer_device);
  148. // Tell core X functions which keyboard is "the" keyboard for this
  149. // X connection.
  150. XISetClientPointer(m_display, None, pointer_deviceid);
  151. {
  152. unsigned char mask_buf[(XI_LASTEVENT + 7) / 8] = {};
  153. XISetMask(mask_buf, XI_RawButtonPress);
  154. XISetMask(mask_buf, XI_RawButtonRelease);
  155. XISetMask(mask_buf, XI_RawMotion);
  156. XIEventMask mask;
  157. mask.mask = mask_buf;
  158. mask.mask_len = sizeof(mask_buf);
  159. mask.deviceid = pointer_deviceid;
  160. XISelectEvents(m_display, DefaultRootWindow(m_display), &mask, 1);
  161. }
  162. {
  163. unsigned char mask_buf[(XI_LASTEVENT + 7) / 8] = {};
  164. XISetMask(mask_buf, XI_RawKeyPress);
  165. XISetMask(mask_buf, XI_RawKeyRelease);
  166. XIEventMask mask;
  167. mask.mask = mask_buf;
  168. mask.mask_len = sizeof(mask_buf);
  169. mask.deviceid = keyboard_deviceid;
  170. XISelectEvents(m_display, DefaultRootWindow(m_display), &mask, 1);
  171. }
  172. // Keyboard Keys
  173. int min_keycode, max_keycode;
  174. XDisplayKeycodes(m_display, &min_keycode, &max_keycode);
  175. for (int i = min_keycode; i <= max_keycode; ++i)
  176. {
  177. Key* const temp_key = new Key(m_display, i, m_state.keyboard.data());
  178. if (temp_key->m_keyname.length())
  179. AddInput(temp_key);
  180. else
  181. delete temp_key;
  182. }
  183. // Add combined left/right modifiers with consistent naming across platforms.
  184. AddCombinedInput("Alt", {"Alt_L", "Alt_R"});
  185. AddCombinedInput("Shift", {"Shift_L", "Shift_R"});
  186. AddCombinedInput("Ctrl", {"Control_L", "Control_R"});
  187. // Mouse Buttons
  188. for (int i = 0; i < 32; i++)
  189. AddInput(new Button(i, &m_state.buttons));
  190. // Mouse Cursor, X-/+ and Y-/+
  191. for (int i = 0; i != 4; ++i)
  192. AddInput(new Cursor(!!(i & 2), !!(i & 1), (i & 2) ? &m_state.cursor.y : &m_state.cursor.x));
  193. // Mouse Axis, X-/+, Y-/+ and Z-/+
  194. AddInput(new Axis(0, false, &m_state.axis.x));
  195. AddInput(new Axis(0, true, &m_state.axis.x));
  196. AddInput(new Axis(1, false, &m_state.axis.y));
  197. AddInput(new Axis(1, true, &m_state.axis.y));
  198. AddInput(new Axis(2, false, &m_state.axis.z));
  199. AddInput(new Axis(2, true, &m_state.axis.z));
  200. // Relative Mouse, X-/+, Y-/+ and Z-/+
  201. AddInput(new RelativeMouse(0, false, &m_state.relative_mouse.x));
  202. AddInput(new RelativeMouse(0, true, &m_state.relative_mouse.x));
  203. AddInput(new RelativeMouse(1, false, &m_state.relative_mouse.y));
  204. AddInput(new RelativeMouse(1, true, &m_state.relative_mouse.y));
  205. AddInput(new RelativeMouse(2, false, &m_state.relative_mouse.z));
  206. AddInput(new RelativeMouse(2, true, &m_state.relative_mouse.z));
  207. }
  208. KeyboardMouse::~KeyboardMouse()
  209. {
  210. XCloseDisplay(m_display);
  211. }
  212. // Update the mouse cursor controls
  213. void KeyboardMouse::UpdateCursor(bool should_center_mouse)
  214. {
  215. double root_x, root_y, win_x, win_y;
  216. Window root, child;
  217. XWindowAttributes win_attribs;
  218. XGetWindowAttributes(m_display, m_window, &win_attribs);
  219. const auto win_width = std::max(win_attribs.width, 1);
  220. const auto win_height = std::max(win_attribs.height, 1);
  221. {
  222. XIButtonState button_state;
  223. XIModifierState mods;
  224. XIGroupState group;
  225. // Get the absolute position of the mouse pointer and the button state.
  226. XIQueryPointer(m_display, pointer_deviceid, m_window, &root, &child, &root_x, &root_y, &win_x,
  227. &win_y, &button_state, &mods, &group);
  228. // X buttons are 1-indexed, so to get 32 button bits we need a larger type
  229. // for the shift.
  230. u64 buttons_zero_indexed = 0;
  231. std::memcpy(&buttons_zero_indexed, button_state.mask,
  232. std::min<size_t>(button_state.mask_len, sizeof(m_state.buttons)));
  233. m_state.buttons = buttons_zero_indexed >> 1;
  234. free(button_state.mask);
  235. }
  236. if (should_center_mouse)
  237. {
  238. win_x = win_width / 2;
  239. win_y = win_height / 2;
  240. XIWarpPointer(m_display, pointer_deviceid, None, m_window, 0.0, 0.0, 0, 0, win_x, win_y);
  241. g_controller_interface.SetMouseCenteringRequested(false);
  242. }
  243. const auto window_scale = g_controller_interface.GetWindowInputScale();
  244. // the mouse position as a range from -1 to 1
  245. m_state.cursor.x = (win_x / win_width * 2 - 1) * window_scale.x;
  246. m_state.cursor.y = (win_y / win_height * 2 - 1) * window_scale.y;
  247. }
  248. Core::DeviceRemoval KeyboardMouse::UpdateInput()
  249. {
  250. XFlush(m_display);
  251. // for the axis controls
  252. float delta_x = 0.0f, delta_y = 0.0f, delta_z = 0.0f;
  253. double delta_delta;
  254. bool update_mouse = false, update_keyboard = false;
  255. // Iterate through the event queue, processing raw pointer motion events and
  256. // noting whether the button or key state has changed.
  257. XEvent event;
  258. while (XPending(m_display))
  259. {
  260. XNextEvent(m_display, &event);
  261. if (event.xcookie.type != GenericEvent)
  262. continue;
  263. if (event.xcookie.extension != xi_opcode)
  264. continue;
  265. if (!XGetEventData(m_display, &event.xcookie))
  266. continue;
  267. switch (event.xcookie.evtype)
  268. {
  269. case XI_RawButtonPress:
  270. case XI_RawButtonRelease:
  271. update_mouse = true;
  272. break;
  273. case XI_RawKeyPress:
  274. case XI_RawKeyRelease:
  275. update_keyboard = true;
  276. break;
  277. case XI_RawMotion:
  278. {
  279. update_mouse = true;
  280. XIRawEvent* raw_event = (XIRawEvent*)event.xcookie.data;
  281. float values[4] = {};
  282. size_t value_idx = 0;
  283. // We only care about the first 4 axes, which should always be available at minimum
  284. for (int i = 0; i < 4; ++i)
  285. {
  286. if (XIMaskIsSet(raw_event->valuators.mask, i))
  287. {
  288. values[i] = raw_event->raw_values[value_idx++];
  289. }
  290. }
  291. delta_delta = values[0];
  292. // test for inf and nan
  293. if (delta_delta == delta_delta && 1 + delta_delta != delta_delta)
  294. delta_x += delta_delta;
  295. delta_delta = values[1];
  296. // test for inf and nan
  297. if (delta_delta == delta_delta && 1 + delta_delta != delta_delta)
  298. delta_y += delta_delta;
  299. // Scroll wheel input gets scaled to be similar to the mouse axes
  300. delta_delta = values[3] * 8.0 / scroll_increment;
  301. // test for inf and nan
  302. if (delta_delta == delta_delta && 1 + delta_delta != delta_delta)
  303. delta_z += delta_delta;
  304. break;
  305. }
  306. }
  307. XFreeEventData(m_display, &event.xcookie);
  308. }
  309. m_state.relative_mouse.x = delta_x;
  310. m_state.relative_mouse.y = delta_y;
  311. m_state.relative_mouse.z = delta_z;
  312. // apply axis smoothing
  313. m_state.axis.x *= MOUSE_AXIS_SMOOTHING;
  314. m_state.axis.x += delta_x;
  315. m_state.axis.x /= MOUSE_AXIS_SMOOTHING + 1.0f;
  316. m_state.axis.y *= MOUSE_AXIS_SMOOTHING;
  317. m_state.axis.y += delta_y;
  318. m_state.axis.y /= MOUSE_AXIS_SMOOTHING + 1.0f;
  319. m_state.axis.z += delta_z;
  320. m_state.axis.z /= SCROLL_AXIS_DECAY;
  321. const bool should_center_mouse = g_controller_interface.IsMouseCenteringRequested() &&
  322. (Host_RendererHasFocus() || Host_TASInputHasFocus());
  323. // When a TAS Input window has focus and "Enable Controller Input" is checked most types of
  324. // input should be read normally as if the render window had focus instead. The cursor is an
  325. // exception, as otherwise using the mouse to set any control in the TAS Input window will also
  326. // update the Wii IR value (or any other input controlled by the cursor).
  327. const bool should_update_mouse = update_mouse && !Host_TASInputHasFocus();
  328. if (should_update_mouse || should_center_mouse)
  329. UpdateCursor(should_center_mouse);
  330. if (update_keyboard)
  331. XQueryKeymap(m_display, m_state.keyboard.data());
  332. return Core::DeviceRemoval::Keep;
  333. }
  334. std::string KeyboardMouse::GetName() const
  335. {
  336. // This is the name string we got from the X server for this master
  337. // pointer/keyboard pair.
  338. return name;
  339. }
  340. std::string KeyboardMouse::GetSource() const
  341. {
  342. return std::string(SOURCE_NAME);
  343. }
  344. int KeyboardMouse::GetSortPriority() const
  345. {
  346. return DEFAULT_DEVICE_SORT_PRIORITY;
  347. }
  348. KeyboardMouse::Key::Key(Display* const display, KeyCode keycode, const char* keyboard)
  349. : m_display(display), m_keyboard(keyboard), m_keycode(keycode)
  350. {
  351. int i = 0;
  352. KeySym keysym = 0;
  353. do
  354. {
  355. keysym = XkbKeycodeToKeysym(m_display, keycode, i, 0);
  356. i++;
  357. } while (keysym == NoSymbol && i < 8);
  358. // Convert to upper case for the keyname
  359. if (keysym >= 97 && keysym <= 122)
  360. keysym -= 32;
  361. // 0x0110ffff is the top of the unicode character range according
  362. // to keysymdef.h although it is probably more than we need.
  363. if (keysym == NoSymbol || keysym > 0x0110ffff || XKeysymToString(keysym) == nullptr)
  364. m_keyname = std::string();
  365. else
  366. m_keyname = std::string(XKeysymToString(keysym));
  367. }
  368. ControlState KeyboardMouse::Key::GetState() const
  369. {
  370. return (m_keyboard[m_keycode / 8] & (1 << (m_keycode % 8))) != 0;
  371. }
  372. KeyboardMouse::Button::Button(unsigned int index, u32* buttons) : m_buttons(buttons), m_index(index)
  373. {
  374. name = fmt::format("Click {}", m_index + 1);
  375. }
  376. ControlState KeyboardMouse::Button::GetState() const
  377. {
  378. return ((*m_buttons & (1 << m_index)) != 0);
  379. }
  380. KeyboardMouse::Cursor::Cursor(u8 index, bool positive, const float* cursor)
  381. : m_cursor(cursor), m_index(index), m_positive(positive)
  382. {
  383. name = fmt::format("Cursor {}{}", static_cast<char>('X' + m_index), (m_positive ? '+' : '-'));
  384. }
  385. ControlState KeyboardMouse::Cursor::GetState() const
  386. {
  387. return std::max(0.0f, *m_cursor / (m_positive ? 1.0f : -1.0f));
  388. }
  389. KeyboardMouse::Axis::Axis(u8 index, bool positive, const float* axis)
  390. : m_axis(axis), m_index(index), m_positive(positive)
  391. {
  392. name = fmt::format("Axis {}{}", static_cast<char>('X' + m_index), (m_positive ? '+' : '-'));
  393. }
  394. KeyboardMouse::RelativeMouse::RelativeMouse(u8 index, bool positive, const float* axis)
  395. : m_axis(axis), m_index(index), m_positive(positive)
  396. {
  397. name =
  398. fmt::format("RelativeMouse {}{}", static_cast<char>('X' + m_index), (m_positive ? '+' : '-'));
  399. }
  400. ControlState KeyboardMouse::Axis::GetState() const
  401. {
  402. return std::max(0.0f, *m_axis / (m_positive ? MOUSE_AXIS_SENSITIVITY : -MOUSE_AXIS_SENSITIVITY));
  403. }
  404. ControlState KeyboardMouse::RelativeMouse::GetState() const
  405. {
  406. return std::max(0.0f, *m_axis / (m_positive ? MOUSE_AXIS_SENSITIVITY : -MOUSE_AXIS_SENSITIVITY));
  407. }
  408. } // namespace ciface::XInput2