Another shot at squishing this bug.
This commit is contained in:
@@ -5,4 +5,4 @@
|
|||||||
# By Chrys, Storm Dragon, and contributors.
|
# By Chrys, Storm Dragon, and contributors.
|
||||||
|
|
||||||
version = "2026.05.12"
|
version = "2026.05.12"
|
||||||
code_name = "master"
|
code_name = "testing"
|
||||||
|
|||||||
@@ -157,6 +157,7 @@ class driver(inputDriver):
|
|||||||
self.interesting_keys = set()
|
self.interesting_keys = set()
|
||||||
self.fenrir_keys = set()
|
self.fenrir_keys = set()
|
||||||
self.failed_grabs = 0
|
self.failed_grabs = 0
|
||||||
|
self.modifier_state = 0
|
||||||
|
|
||||||
def initialize(self, environment):
|
def initialize(self, environment):
|
||||||
self.env = environment
|
self.env = environment
|
||||||
@@ -188,6 +189,7 @@ class driver(inputDriver):
|
|||||||
)
|
)
|
||||||
)
|
)
|
||||||
self.num_lock_mask = self.find_num_lock_mask()
|
self.num_lock_mask = self.find_num_lock_mask()
|
||||||
|
self.refresh_modifier_state()
|
||||||
self.refresh_interesting_keys()
|
self.refresh_interesting_keys()
|
||||||
self.refresh_grabs(force=True)
|
self.refresh_grabs(force=True)
|
||||||
self.env["runtime"]["ProcessManager"].add_custom_event_thread(
|
self.env["runtime"]["ProcessManager"].add_custom_event_thread(
|
||||||
@@ -306,6 +308,7 @@ class driver(inputDriver):
|
|||||||
key_name = input_event["event_name"]
|
key_name = input_event["event_name"]
|
||||||
if not self.should_emit_key(key_name):
|
if not self.should_emit_key(key_name):
|
||||||
return
|
return
|
||||||
|
self.update_modifier_state_from_event(input_event)
|
||||||
self.write_debug(
|
self.write_debug(
|
||||||
"x11Driver key event "
|
"x11Driver key event "
|
||||||
+ key_name
|
+ key_name
|
||||||
@@ -360,8 +363,41 @@ class driver(inputDriver):
|
|||||||
"event_usec": int((event_time % 1) * 1000000),
|
"event_usec": int((event_time % 1) * 1000000),
|
||||||
"event_state": 1 if event.type == X.KeyPress else 0,
|
"event_state": 1 if event.type == X.KeyPress else 0,
|
||||||
"event_type": event.type,
|
"event_type": event.type,
|
||||||
|
"event_raw_state": getattr(event, "state", 0),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
def refresh_modifier_state(self):
|
||||||
|
try:
|
||||||
|
pointer = self.root.query_pointer()
|
||||||
|
self.modifier_state = getattr(pointer, "mask", 0)
|
||||||
|
except Exception:
|
||||||
|
self.modifier_state = 0
|
||||||
|
|
||||||
|
def update_modifier_state_from_event(self, input_event):
|
||||||
|
key_name = input_event["event_name"]
|
||||||
|
event_state = input_event["event_state"]
|
||||||
|
raw_state = input_event.get("event_raw_state", self.modifier_state)
|
||||||
|
self.modifier_state = raw_state
|
||||||
|
if key_name == "KEY_NUMLOCK":
|
||||||
|
self.update_lock_modifier_state(self.num_lock_mask, event_state)
|
||||||
|
elif key_name == "KEY_CAPSLOCK":
|
||||||
|
self.update_lock_modifier_state(X.LockMask, event_state)
|
||||||
|
else:
|
||||||
|
modifier_mask = self.modifier_masks.get(key_name, 0)
|
||||||
|
if modifier_mask:
|
||||||
|
if event_state == 1:
|
||||||
|
self.modifier_state |= modifier_mask
|
||||||
|
elif event_state == 0:
|
||||||
|
self.modifier_state &= ~modifier_mask
|
||||||
|
|
||||||
|
def update_lock_modifier_state(self, modifier_mask, event_state):
|
||||||
|
if not modifier_mask or event_state != 1:
|
||||||
|
return
|
||||||
|
if self.modifier_state & modifier_mask:
|
||||||
|
self.modifier_state &= ~modifier_mask
|
||||||
|
else:
|
||||||
|
self.modifier_state |= modifier_mask
|
||||||
|
|
||||||
def keycode_to_key_name(self, keycode, state=0):
|
def keycode_to_key_name(self, keycode, state=0):
|
||||||
key_names = []
|
key_names = []
|
||||||
for keysym_name in self.keycode_to_keysym_names(keycode):
|
for keysym_name in self.keycode_to_keysym_names(keycode):
|
||||||
@@ -643,15 +679,13 @@ class driver(inputDriver):
|
|||||||
self.ungrab_all_devices()
|
self.ungrab_all_devices()
|
||||||
|
|
||||||
def get_led_state(self, led=0):
|
def get_led_state(self, led=0):
|
||||||
try:
|
if led == 0:
|
||||||
pointer = self.root.query_pointer()
|
return bool(
|
||||||
mask = getattr(pointer, "mask", 0)
|
self.num_lock_mask
|
||||||
if led == 0:
|
and self.modifier_state & self.num_lock_mask
|
||||||
return bool(self.num_lock_mask and mask & self.num_lock_mask)
|
)
|
||||||
if led == 1:
|
if led == 1:
|
||||||
return bool(mask & X.LockMask)
|
return bool(self.modifier_state & X.LockMask)
|
||||||
except Exception:
|
|
||||||
pass
|
|
||||||
return False
|
return False
|
||||||
|
|
||||||
def set_led_state(self, led_dict):
|
def set_led_state(self, led_dict):
|
||||||
|
|||||||
@@ -201,16 +201,49 @@ def test_x11_optional_modifier_masks_can_exclude_numlock():
|
|||||||
|
|
||||||
|
|
||||||
@pytest.mark.unit
|
@pytest.mark.unit
|
||||||
def test_x11_get_led_state_reads_lock_modifiers_from_pointer_mask():
|
def test_x11_get_led_state_reads_cached_lock_modifiers_without_x_round_trip():
|
||||||
x11 = X11Driver()
|
x11 = X11Driver()
|
||||||
x11.num_lock_mask = X.Mod2Mask
|
x11.num_lock_mask = X.Mod2Mask
|
||||||
pointer = Mock(mask=X.Mod2Mask | X.LockMask)
|
x11.modifier_state = X.Mod2Mask | X.LockMask
|
||||||
x11.root = Mock()
|
x11.root = Mock()
|
||||||
x11.root.query_pointer.return_value = pointer
|
|
||||||
|
|
||||||
assert x11.get_led_state(0) is True
|
assert x11.get_led_state(0) is True
|
||||||
assert x11.get_led_state(1) is True
|
assert x11.get_led_state(1) is True
|
||||||
assert x11.get_led_state(2) is False
|
assert x11.get_led_state(2) is False
|
||||||
|
x11.root.query_pointer.assert_not_called()
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.unit
|
||||||
|
def test_x11_update_modifier_state_tracks_event_masks_and_lock_toggles():
|
||||||
|
x11 = X11Driver()
|
||||||
|
x11.num_lock_mask = X.Mod2Mask
|
||||||
|
|
||||||
|
x11.update_modifier_state_from_event(
|
||||||
|
{
|
||||||
|
"event_name": "KEY_KP8",
|
||||||
|
"event_state": 1,
|
||||||
|
"event_raw_state": X.Mod2Mask,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
assert x11.get_led_state(0) is True
|
||||||
|
|
||||||
|
x11.update_modifier_state_from_event(
|
||||||
|
{
|
||||||
|
"event_name": "KEY_NUMLOCK",
|
||||||
|
"event_state": 1,
|
||||||
|
"event_raw_state": X.Mod2Mask,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
assert x11.get_led_state(0) is False
|
||||||
|
|
||||||
|
x11.update_modifier_state_from_event(
|
||||||
|
{
|
||||||
|
"event_name": "KEY_CAPSLOCK",
|
||||||
|
"event_state": 1,
|
||||||
|
"event_raw_state": 0,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
assert x11.get_led_state(1) is True
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.unit
|
@pytest.mark.unit
|
||||||
|
|||||||
Reference in New Issue
Block a user