mirror of
https://github.com/sezanzeb/input-remapper
synced 2024-11-04 12:00:16 +00:00
using get_keycode instead of evdev
This commit is contained in:
parent
6ceaab2488
commit
c2abf2c24f
@ -55,24 +55,26 @@ class Row(Gtk.ListBoxRow):
|
|||||||
character = self.character_input.get_text()
|
character = self.character_input.get_text()
|
||||||
return character if character else None
|
return character if character else None
|
||||||
|
|
||||||
def start_watching_keycodes(self, *args):
|
def highlight(self):
|
||||||
"""Start to periodically check if a keycode has been pressed.
|
"""Mark this row as changed."""
|
||||||
|
self.get_style_context().add_class('changed')
|
||||||
|
|
||||||
This is different from just listening for text input events
|
def unhighlight(self):
|
||||||
(as in Gtk.Entry), since keys may not write characters into the form
|
"""Mark this row as unchanged."""
|
||||||
because they are not mapped. Furthermore their keycode is needed,
|
self.get_style_context().remove_class('changed')
|
||||||
not their mapped character."""
|
|
||||||
keycode_reader.clear()
|
|
||||||
|
|
||||||
def iterate():
|
def on_character_input_change(self, entry):
|
||||||
self.check_newest_keycode()
|
keycode = self.get_keycode()
|
||||||
return self.keycode.is_focus() and self.window.window.is_active()
|
character = self.get_character()
|
||||||
|
|
||||||
GLib.timeout_add(1000 / 30, iterate)
|
self.highlight()
|
||||||
|
|
||||||
def check_newest_keycode(self):
|
if keycode is not None:
|
||||||
|
custom_mapping.change(None, keycode, character)
|
||||||
|
|
||||||
|
def on_key_pressed(self, button, event):
|
||||||
"""Check if a keycode has been pressed and if so, display it."""
|
"""Check if a keycode has been pressed and if so, display it."""
|
||||||
new_keycode = keycode_reader.read()
|
new_keycode = event.get_keycode()[1]
|
||||||
previous_keycode = self.get_keycode()
|
previous_keycode = self.get_keycode()
|
||||||
character = self.get_character()
|
character = self.get_character()
|
||||||
|
|
||||||
@ -106,25 +108,8 @@ class Row(Gtk.ListBoxRow):
|
|||||||
# else, the keycode has changed, the character is set, all good
|
# else, the keycode has changed, the character is set, all good
|
||||||
custom_mapping.change(previous_keycode, new_keycode, character)
|
custom_mapping.change(previous_keycode, new_keycode, character)
|
||||||
|
|
||||||
def highlight(self):
|
|
||||||
"""Mark this row as changed."""
|
|
||||||
self.get_style_context().add_class('changed')
|
|
||||||
|
|
||||||
def unhighlight(self):
|
|
||||||
"""Mark this row as unchanged."""
|
|
||||||
self.get_style_context().remove_class('changed')
|
|
||||||
|
|
||||||
def on_character_input_change(self, entry):
|
|
||||||
keycode = self.get_keycode()
|
|
||||||
character = self.get_character()
|
|
||||||
|
|
||||||
self.highlight()
|
|
||||||
|
|
||||||
if keycode is not None:
|
|
||||||
custom_mapping.change(None, keycode, character)
|
|
||||||
|
|
||||||
def put_together(self, keycode, character):
|
def put_together(self, keycode, character):
|
||||||
"""Create all GTK widgets."""
|
"""Create all child GTK widgets and connect their signals."""
|
||||||
delete_button = Gtk.EventBox()
|
delete_button = Gtk.EventBox()
|
||||||
delete_button.add(Gtk.Image.new_from_icon_name(
|
delete_button.add(Gtk.Image.new_from_icon_name(
|
||||||
'window-close',
|
'window-close',
|
||||||
@ -141,8 +126,8 @@ class Row(Gtk.ListBoxRow):
|
|||||||
if keycode is not None:
|
if keycode is not None:
|
||||||
keycode_input.set_label(str(keycode))
|
keycode_input.set_label(str(keycode))
|
||||||
keycode_input.connect(
|
keycode_input.connect(
|
||||||
'focus-in-event',
|
'key-press-event',
|
||||||
self.start_watching_keycodes
|
self.on_key_pressed
|
||||||
)
|
)
|
||||||
# make the togglebutton go back to its normal state when doing
|
# make the togglebutton go back to its normal state when doing
|
||||||
# something else in the UI
|
# something else in the UI
|
||||||
|
@ -106,7 +106,7 @@ class Window:
|
|||||||
|
|
||||||
self.select_newest_preset()
|
self.select_newest_preset()
|
||||||
|
|
||||||
GLib.timeout_add(100, self.check_add_row)
|
self.timeout = GLib.timeout_add(100, self.check_add_row)
|
||||||
|
|
||||||
def get(self, name):
|
def get(self, name):
|
||||||
"""Get a widget from the window"""
|
"""Get a widget from the window"""
|
||||||
@ -114,6 +114,7 @@ class Window:
|
|||||||
|
|
||||||
def on_close(self, *_):
|
def on_close(self, *_):
|
||||||
"""Safely close the application."""
|
"""Safely close the application."""
|
||||||
|
GLib.source_remove(self.timeout)
|
||||||
Gtk.main_quit()
|
Gtk.main_quit()
|
||||||
|
|
||||||
def check_add_row(self):
|
def check_add_row(self):
|
||||||
|
@ -47,6 +47,8 @@ def can_grab(path):
|
|||||||
class KeycodeReader:
|
class KeycodeReader:
|
||||||
"""Keeps reading keycodes in the background for the UI to use.
|
"""Keeps reading keycodes in the background for the UI to use.
|
||||||
|
|
||||||
|
This was written before I figured out there is get_keycode in GLib.
|
||||||
|
|
||||||
A new arriving keycode indicates that a button was pressed, so the
|
A new arriving keycode indicates that a button was pressed, so the
|
||||||
UI can keep checking for a new keycode on this object and act like the
|
UI can keep checking for a new keycode on this object and act like the
|
||||||
keycode went right to the input box.
|
keycode went right to the input box.
|
||||||
@ -96,9 +98,6 @@ class KeycodeReader:
|
|||||||
# value: 1 for down, 0 for up, 2 for hold.
|
# value: 1 for down, 0 for up, 2 for hold.
|
||||||
# this happens to report key codes that are 8 lower
|
# this happens to report key codes that are 8 lower
|
||||||
# than the ones reported by xev
|
# than the ones reported by xev
|
||||||
# TODO check if 280 and above works on wayland and
|
|
||||||
# if not, prevent anything > 255. adjust
|
|
||||||
# the maximum of keycodes before trying
|
|
||||||
newest_keycode = event.code + 8
|
newest_keycode = event.code + 8
|
||||||
return newest_keycode
|
return newest_keycode
|
||||||
|
|
||||||
|
@ -83,8 +83,6 @@ class Integration(unittest.TestCase):
|
|||||||
self.window = launch()
|
self.window = launch()
|
||||||
|
|
||||||
def tearDown(self):
|
def tearDown(self):
|
||||||
# before calling destroy to break everything (happened with
|
|
||||||
# check_add_row), make an iteration to clear all pending events.
|
|
||||||
gtk_iteration()
|
gtk_iteration()
|
||||||
self.window.on_close()
|
self.window.on_close()
|
||||||
self.window.window.destroy()
|
self.window.window.destroy()
|
||||||
@ -111,12 +109,14 @@ class Integration(unittest.TestCase):
|
|||||||
|
|
||||||
def test_rows(self):
|
def test_rows(self):
|
||||||
"""Comprehensive test for rows."""
|
"""Comprehensive test for rows."""
|
||||||
def read():
|
class FakeEvent:
|
||||||
"""Always return a different keycode for each row."""
|
def __init__(self, keycode):
|
||||||
# + 7 because keycodes usually start at 8
|
self.keycode = keycode
|
||||||
return len(self.window.get('key_list').get_children()) + 7
|
|
||||||
|
|
||||||
def change_empty_row(character):
|
def get_keycode(self):
|
||||||
|
return [False, self.keycode]
|
||||||
|
|
||||||
|
def change_empty_row(keycode, character):
|
||||||
"""Modify the one empty row that always exists."""
|
"""Modify the one empty row that always exists."""
|
||||||
# wait for the window to create a new empty row if needed
|
# wait for the window to create a new empty row if needed
|
||||||
time.sleep(0.2)
|
time.sleep(0.2)
|
||||||
@ -129,14 +129,9 @@ class Integration(unittest.TestCase):
|
|||||||
self.assertIsNone(row.keycode.get_label())
|
self.assertIsNone(row.keycode.get_label())
|
||||||
self.assertEqual(row.character_input.get_text(), '')
|
self.assertEqual(row.character_input.get_text(), '')
|
||||||
|
|
||||||
# focus the keycode to trigger reading the fake keycode
|
row.on_key_pressed(None, FakeEvent(keycode))
|
||||||
self.window.window.set_focus(row.keycode)
|
|
||||||
time.sleep(0.2)
|
|
||||||
gtk_iteration()
|
|
||||||
|
|
||||||
# it should be filled using the `read` patch
|
self.assertEqual(int(row.keycode.get_label()), keycode)
|
||||||
self.assertEqual(int(row.keycode.get_label()), len(rows) + 7)
|
|
||||||
self.window.window.set_focus(None)
|
|
||||||
|
|
||||||
# set the character to make the new row complete
|
# set the character to make the new row complete
|
||||||
row.character_input.set_text(character)
|
row.character_input.set_text(character)
|
||||||
@ -145,45 +140,44 @@ class Integration(unittest.TestCase):
|
|||||||
|
|
||||||
return row
|
return row
|
||||||
|
|
||||||
with patch.object(keycode_reader, 'read', read):
|
# add two rows by modifiying the one empty row that exists
|
||||||
# add two rows by modifiying the one empty row that exists
|
change_empty_row(10, 'a')
|
||||||
change_empty_row('a')
|
change_empty_row(11, 'b')
|
||||||
change_empty_row('b')
|
|
||||||
|
|
||||||
# one empty row added automatically again
|
# one empty row added automatically again
|
||||||
time.sleep(0.2)
|
time.sleep(0.2)
|
||||||
gtk_iteration()
|
gtk_iteration()
|
||||||
# sleep one more time because it's funny to watch the ui
|
# sleep one more time because it's funny to watch the ui
|
||||||
# during the test, how rows turn blue and stuff
|
# during the test, how rows turn blue and stuff
|
||||||
time.sleep(0.2)
|
time.sleep(0.2)
|
||||||
self.assertEqual(len(self.get_rows()), 3)
|
self.assertEqual(len(self.get_rows()), 3)
|
||||||
|
|
||||||
self.assertEqual(custom_mapping.get(8), 'a')
|
self.assertEqual(custom_mapping.get(10), 'a')
|
||||||
self.assertEqual(custom_mapping.get(9), 'b')
|
self.assertEqual(custom_mapping.get(11), 'b')
|
||||||
self.assertTrue(custom_mapping.changed)
|
self.assertTrue(custom_mapping.changed)
|
||||||
|
|
||||||
self.window.on_save_preset_clicked(None)
|
self.window.on_save_preset_clicked(None)
|
||||||
for row in self.get_rows():
|
for row in self.get_rows():
|
||||||
self.assertNotIn(
|
self.assertNotIn(
|
||||||
'changed',
|
'changed',
|
||||||
row.get_style_context().list_classes()
|
row.get_style_context().list_classes()
|
||||||
)
|
)
|
||||||
self.assertFalse(custom_mapping.changed)
|
self.assertFalse(custom_mapping.changed)
|
||||||
|
|
||||||
# now change the first row and it should turn blue,
|
# now change the first row and it should turn blue,
|
||||||
# but the other should remain unhighlighted
|
# but the other should remain unhighlighted
|
||||||
row = self.get_rows()[0]
|
row = self.get_rows()[0]
|
||||||
row.character_input.set_text('c')
|
row.character_input.set_text('c')
|
||||||
self.assertIn('changed', row.get_style_context().list_classes())
|
self.assertIn('changed', row.get_style_context().list_classes())
|
||||||
for row in self.get_rows()[1:]:
|
for row in self.get_rows()[1:]:
|
||||||
self.assertNotIn(
|
self.assertNotIn(
|
||||||
'changed',
|
'changed',
|
||||||
row.get_style_context().list_classes()
|
row.get_style_context().list_classes()
|
||||||
)
|
)
|
||||||
|
|
||||||
self.assertEqual(custom_mapping.get(8), 'c')
|
self.assertEqual(custom_mapping.get(10), 'c')
|
||||||
self.assertEqual(custom_mapping.get(9), 'b')
|
self.assertEqual(custom_mapping.get(11), 'b')
|
||||||
self.assertTrue(custom_mapping.changed)
|
self.assertTrue(custom_mapping.changed)
|
||||||
|
|
||||||
def test_rename_and_save(self):
|
def test_rename_and_save(self):
|
||||||
custom_mapping.change(None, 14, 'a')
|
custom_mapping.change(None, 14, 'a')
|
||||||
|
Loading…
Reference in New Issue
Block a user