summaryrefslogtreecommitdiff
path: root/Source/Core/InputCommon/ControllerInterface/Xlib/XInput2.cpp
diff options
context:
space:
mode:
authorJordan Woyak <jordan.woyak@gmail.com>2020-10-19 10:21:28 -0500
committerJordan Woyak <jordan.woyak@gmail.com>2020-10-19 11:46:01 -0500
commitbbb12a7560b0f8e44ef3881e11e60c9db6e8449d (patch)
treee11f42feba54072cc60758d626d86cf8f6275a05 /Source/Core/InputCommon/ControllerInterface/Xlib/XInput2.cpp
parent696f08ede3c3bd1c88429ca5fe9c8baf42679c56 (diff)
Linux/XInput2: Fix keys being stuck pressed on focus loss.
Diffstat (limited to 'Source/Core/InputCommon/ControllerInterface/Xlib/XInput2.cpp')
-rw-r--r--Source/Core/InputCommon/ControllerInterface/Xlib/XInput2.cpp79
1 files changed, 50 insertions, 29 deletions
diff --git a/Source/Core/InputCommon/ControllerInterface/Xlib/XInput2.cpp b/Source/Core/InputCommon/ControllerInterface/Xlib/XInput2.cpp
index 9ec1c2be35..dac0c085fa 100644
--- a/Source/Core/InputCommon/ControllerInterface/Xlib/XInput2.cpp
+++ b/Source/Core/InputCommon/ControllerInterface/Xlib/XInput2.cpp
@@ -97,11 +97,11 @@ void PopulateDevices(void* const hwnd)
// Apply the event mask to the device and all its slaves. Only used in the
// constructor. Remember, each KeyboardMouse has its own copy of the event
// stream, which is how multiple event masks can "coexist."
-void KeyboardMouse::SelectEventsForDevice(Window window, XIEventMask* mask, int deviceid)
+void KeyboardMouse::SelectEventsForDevice(XIEventMask* mask, int deviceid)
{
// Set the event mask for the master device.
mask->deviceid = deviceid;
- XISelectEvents(m_display, window, mask, 1);
+ XISelectEvents(m_display, DefaultRootWindow(m_display), 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,
@@ -109,20 +109,19 @@ void KeyboardMouse::SelectEventsForDevice(Window window, XIEventMask* mask, int
// 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);
+ XIDeviceInfo* const 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)
+ XIDeviceInfo* const slave = &all_slaves[i];
+ if ((slave->use != XISlavePointer && slave->use != XISlaveKeyboard) ||
+ slave->attachment != deviceid)
+ {
continue;
- mask->deviceid = current_slave->deviceid;
- XISelectEvents(m_display, window, mask, 1);
+ }
+ mask->deviceid = slave->deviceid;
+ XISelectEvents(m_display, DefaultRootWindow(m_display), mask, 1);
}
XIFreeDeviceInfo(all_slaves);
@@ -138,34 +137,44 @@ KeyboardMouse::KeyboardMouse(Window window, int opcode, int pointer, int keyboar
// "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);
+ // should always be 1
+ int unused;
+ XIDeviceInfo* const 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];
+ {
+ unsigned char mask_buf[(XI_LASTEVENT + 7) / 8] = {};
+ XISetMask(mask_buf, XI_ButtonPress);
+ XISetMask(mask_buf, XI_ButtonRelease);
+ XISetMask(mask_buf, XI_RawMotion);
+
+ XIEventMask mask;
+ mask.mask = mask_buf;
+ mask.mask_len = sizeof(mask_buf);
- mask.mask_len = sizeof(mask_buf);
- mask.mask = mask_buf;
- memset(mask_buf, 0, sizeof(mask_buf));
+ SelectEventsForDevice(&mask, pointer_deviceid);
+ }
+
+ {
+ unsigned char mask_buf[(XI_LASTEVENT + 7) / 8] = {};
+ XISetMask(mask_buf, XI_KeyPress);
+ XISetMask(mask_buf, XI_KeyRelease);
+ XISetMask(mask_buf, XI_FocusOut);
- 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);
+ XIEventMask mask;
+ mask.mask = mask_buf;
+ mask.mask_len = sizeof(mask_buf);
- SelectEventsForDevice(DefaultRootWindow(m_display), &mask, pointer_deviceid);
- SelectEventsForDevice(DefaultRootWindow(m_display), &mask, keyboard_deviceid);
+ SelectEventsForDevice(&mask, keyboard_deviceid);
+ }
// Keyboard Keys
+ int min_keycode, max_keycode;
+ XDisplayKeycodes(m_display, &min_keycode, &max_keycode);
for (int i = min_keycode; i <= max_keycode; ++i)
{
- Key* temp_key = new Key(m_display, i, m_state.keyboard);
+ Key* const temp_key = new Key(m_display, i, m_state.keyboard.data());
if (temp_key->m_keyname.length())
AddInput(temp_key);
else
@@ -284,6 +293,10 @@ void KeyboardMouse::UpdateInput()
delta_y += delta_delta;
}
break;
+ case XI_FocusOut:
+ // Clear keyboard state on FocusOut as we will not be receiving KeyRelease events.
+ m_state.keyboard.fill(0);
+ break;
}
XFreeEventData(m_display, &event.xcookie);
@@ -300,6 +313,14 @@ void KeyboardMouse::UpdateInput()
// Get the absolute position of the mouse pointer
if (mouse_moved)
UpdateCursor();
+
+ // KeyRelease and FocusOut events are sometimes not received.
+ // Cycling Alt-Tab and landing on the same window results in a stuck "Alt" key.
+ // Unpressed keys are released here.
+ std::array<char, 32> keyboard;
+ XQueryKeymap(m_display, keyboard.data());
+ for (size_t i = 0; i != keyboard.size(); ++i)
+ m_state.keyboard[i] &= keyboard[i];
}
std::string KeyboardMouse::GetName() const