Merge pull request #9160 from jordan-woyak/xinput2-stuck-keys
Linux/XInput2: Fix keys being stuck pressed on focus loss.
This commit is contained in:
commit
97de366b0f
|
@ -97,11 +97,11 @@ void PopulateDevices(void* const hwnd)
|
||||||
// Apply the event mask to the device and all its slaves. Only used in the
|
// 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
|
// constructor. Remember, each KeyboardMouse has its own copy of the event
|
||||||
// stream, which is how multiple event masks can "coexist."
|
// 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.
|
// Set the event mask for the master device.
|
||||||
mask->deviceid = deviceid;
|
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
|
// 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,
|
// 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
|
// devices) emit those. For keyboard devices, selecting slaves avoids
|
||||||
// dealing with key focus.
|
// dealing with key focus.
|
||||||
|
|
||||||
XIDeviceInfo* all_slaves;
|
|
||||||
XIDeviceInfo* current_slave;
|
|
||||||
int num_slaves;
|
int num_slaves;
|
||||||
|
XIDeviceInfo* const all_slaves = XIQueryDevice(m_display, XIAllDevices, &num_slaves);
|
||||||
all_slaves = XIQueryDevice(m_display, XIAllDevices, &num_slaves);
|
|
||||||
|
|
||||||
for (int i = 0; i < num_slaves; i++)
|
for (int i = 0; i < num_slaves; i++)
|
||||||
{
|
{
|
||||||
current_slave = &all_slaves[i];
|
XIDeviceInfo* const slave = &all_slaves[i];
|
||||||
if ((current_slave->use != XISlavePointer && current_slave->use != XISlaveKeyboard) ||
|
if ((slave->use != XISlavePointer && slave->use != XISlaveKeyboard) ||
|
||||||
current_slave->attachment != deviceid)
|
slave->attachment != deviceid)
|
||||||
|
{
|
||||||
continue;
|
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);
|
XIFreeDeviceInfo(all_slaves);
|
||||||
|
@ -138,34 +137,44 @@ KeyboardMouse::KeyboardMouse(Window window, int opcode, int pointer, int keyboar
|
||||||
// "context."
|
// "context."
|
||||||
m_display = XOpenDisplay(nullptr);
|
m_display = XOpenDisplay(nullptr);
|
||||||
|
|
||||||
int min_keycode, max_keycode;
|
// should always be 1
|
||||||
XDisplayKeycodes(m_display, &min_keycode, &max_keycode);
|
int unused;
|
||||||
|
XIDeviceInfo* const pointer_device = XIQueryDevice(m_display, pointer_deviceid, &unused);
|
||||||
int unused; // should always be 1
|
|
||||||
XIDeviceInfo* pointer_device = XIQueryDevice(m_display, pointer_deviceid, &unused);
|
|
||||||
name = std::string(pointer_device->name);
|
name = std::string(pointer_device->name);
|
||||||
XIFreeDeviceInfo(pointer_device);
|
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);
|
||||||
|
|
||||||
mask.mask_len = sizeof(mask_buf);
|
XIEventMask mask;
|
||||||
mask.mask = mask_buf;
|
mask.mask = mask_buf;
|
||||||
memset(mask_buf, 0, sizeof(mask_buf));
|
mask.mask_len = sizeof(mask_buf);
|
||||||
|
|
||||||
XISetMask(mask_buf, XI_ButtonPress);
|
SelectEventsForDevice(&mask, pointer_deviceid);
|
||||||
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);
|
unsigned char mask_buf[(XI_LASTEVENT + 7) / 8] = {};
|
||||||
|
XISetMask(mask_buf, XI_KeyPress);
|
||||||
|
XISetMask(mask_buf, XI_KeyRelease);
|
||||||
|
XISetMask(mask_buf, XI_FocusOut);
|
||||||
|
|
||||||
|
XIEventMask mask;
|
||||||
|
mask.mask = mask_buf;
|
||||||
|
mask.mask_len = sizeof(mask_buf);
|
||||||
|
|
||||||
|
SelectEventsForDevice(&mask, keyboard_deviceid);
|
||||||
|
}
|
||||||
|
|
||||||
// Keyboard Keys
|
// Keyboard Keys
|
||||||
|
int min_keycode, max_keycode;
|
||||||
|
XDisplayKeycodes(m_display, &min_keycode, &max_keycode);
|
||||||
for (int i = min_keycode; i <= max_keycode; ++i)
|
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())
|
if (temp_key->m_keyname.length())
|
||||||
AddInput(temp_key);
|
AddInput(temp_key);
|
||||||
else
|
else
|
||||||
|
@ -284,6 +293,10 @@ void KeyboardMouse::UpdateInput()
|
||||||
delta_y += delta_delta;
|
delta_y += delta_delta;
|
||||||
}
|
}
|
||||||
break;
|
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);
|
XFreeEventData(m_display, &event.xcookie);
|
||||||
|
@ -300,6 +313,14 @@ void KeyboardMouse::UpdateInput()
|
||||||
// Get the absolute position of the mouse pointer
|
// Get the absolute position of the mouse pointer
|
||||||
if (mouse_moved)
|
if (mouse_moved)
|
||||||
UpdateCursor();
|
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
|
std::string KeyboardMouse::GetName() const
|
||||||
|
|
|
@ -6,6 +6,8 @@
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <array>
|
||||||
|
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#include <X11/Xlib.h>
|
#include <X11/Xlib.h>
|
||||||
#include <X11/extensions/XInput2.h>
|
#include <X11/extensions/XInput2.h>
|
||||||
|
@ -24,7 +26,7 @@ class KeyboardMouse : public Core::Device
|
||||||
private:
|
private:
|
||||||
struct State
|
struct State
|
||||||
{
|
{
|
||||||
char keyboard[32];
|
std::array<char, 32> keyboard;
|
||||||
unsigned int buttons;
|
unsigned int buttons;
|
||||||
Common::Vec2 cursor;
|
Common::Vec2 cursor;
|
||||||
Common::Vec2 axis;
|
Common::Vec2 axis;
|
||||||
|
@ -90,7 +92,7 @@ private:
|
||||||
};
|
};
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void SelectEventsForDevice(Window window, XIEventMask* mask, int deviceid);
|
void SelectEventsForDevice(XIEventMask* mask, int deviceid);
|
||||||
void UpdateCursor();
|
void UpdateCursor();
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
@ -106,8 +108,9 @@ private:
|
||||||
Window m_window;
|
Window m_window;
|
||||||
Display* m_display;
|
Display* m_display;
|
||||||
State m_state{};
|
State m_state{};
|
||||||
int xi_opcode;
|
const int xi_opcode;
|
||||||
const int pointer_deviceid, keyboard_deviceid;
|
const int pointer_deviceid;
|
||||||
|
const int keyboard_deviceid;
|
||||||
std::string name;
|
std::string name;
|
||||||
};
|
};
|
||||||
} // namespace ciface::XInput2
|
} // namespace ciface::XInput2
|
||||||
|
|
Loading…
Reference in New Issue