diff --git a/data/key-mapper.glade b/data/key-mapper.glade
index e78728c4..091062e6 100644
--- a/data/key-mapper.glade
+++ b/data/key-mapper.glade
@@ -541,7 +541,7 @@
False
diff --git a/keymapper/config.py b/keymapper/config.py
index ced14988..b47d436a 100644
--- a/keymapper/config.py
+++ b/keymapper/config.py
@@ -195,6 +195,10 @@ class GlobalConfig(ConfigBase):
if preset is not None:
self.set(f'autoload.{device}', preset)
else:
+ logger.info(
+ 'Not loading injecting for "%s" automatically anmore',
+ device
+ )
self.remove(f'autoload.{device}')
def iterate_autoload_presets(self):
diff --git a/keymapper/dev/injector.py b/keymapper/dev/injector.py
index 791d6e50..24424e54 100644
--- a/keymapper/dev/injector.py
+++ b/keymapper/dev/injector.py
@@ -46,20 +46,27 @@ CLOSE = 0
def is_numlock_on():
"""Get the current state of the numlock."""
- xset_q = subprocess.check_output(['xset', 'q']).decode()
- num_lock_status = re.search(
- r'Num Lock:\s+(.+?)\s',
- xset_q
- )
+ try:
+ xset_q = subprocess.check_output(['xset', 'q']).decode()
+ num_lock_status = re.search(
+ r'Num Lock:\s+(.+?)\s',
+ xset_q
+ )
- if num_lock_status is not None:
- return num_lock_status[1] == 'on'
+ if num_lock_status is not None:
+ return num_lock_status[1] == 'on'
- return False
+ return False
+ except subprocess.CalledProcessError:
+ # tty
+ return None
def set_numlock(state):
"""Set the numlock to a given state of True or False."""
+ if state is None:
+ return
+
value = {
True: 'on',
False: 'off'
@@ -81,8 +88,11 @@ def ensure_numlock(func):
# for some reason, grabbing a device can modify the num lock state.
# remember it and apply back later
numlock_before = is_numlock_on()
+
result = func(*args, **kwargs)
+
set_numlock(numlock_before)
+
return result
return wrapped
diff --git a/keymapper/gtk/window.py b/keymapper/gtk/window.py
index 5b722786..60c7cf05 100755
--- a/keymapper/gtk/window.py
+++ b/keymapper/gtk/window.py
@@ -70,6 +70,22 @@ def get_selected_row_bg():
return color.to_string()
+class HandlerDisabled:
+ """Safely modify a widget without causing handlers to be called.
+
+ Use in a with statement.
+ """
+ def __init__(self, widget, handler):
+ self.widget = widget
+ self.handler = handler
+
+ def __enter__(self):
+ self.widget.handler_block_by_func(self.handler)
+
+ def __exit__(self, *_):
+ self.widget.handler_unblock_by_func(self.handler)
+
+
class Window:
"""User Interface."""
def __init__(self):
@@ -358,7 +374,7 @@ class Window:
keycode_reader.start_reading(device)
GLib.timeout_add(10, self.show_device_mapping_status)
- def on_preset_autoload_switch_activate(self, _, active):
+ def on_autoload_switch(self, _, active):
"""Load the preset automatically next time the user logs in."""
device = self.selected_device
preset = self.selected_preset
@@ -442,10 +458,12 @@ class Window:
key_list.insert(single_key_mapping, -1)
autoload_switch = self.get('preset_autoload_switch')
- autoload_switch.set_active(config.is_autoloaded(
- self.selected_device,
- self.selected_preset
- ))
+
+ with HandlerDisabled(autoload_switch, self.on_autoload_switch):
+ autoload_switch.set_active(config.is_autoloaded(
+ self.selected_device,
+ self.selected_preset
+ ))
self.get('preset_name_input').set_text('')
self.add_empty()
diff --git a/tests/testcases/test_integration.py b/tests/testcases/test_integration.py
index 6bf6a014..770943ee 100644
--- a/tests/testcases/test_integration.py
+++ b/tests/testcases/test_integration.py
@@ -122,15 +122,20 @@ class TestIntegration(unittest.TestCase):
self.assertFalse(self.window.show_device_mapping_status())
def test_autoload(self):
- self.window.on_preset_autoload_switch_activate(None, False)
+ self.window.on_autoload_switch(None, False)
self.assertFalse(config.is_autoloaded(
self.window.selected_device,
self.window.selected_preset
))
- # select a preset for the first device
self.window.on_select_device(FakeDropdown('device 1'))
- self.window.on_preset_autoload_switch_activate(None, True)
+ gtk_iteration()
+ self.assertFalse(self.window.get('preset_autoload_switch').get_active())
+
+ # select a preset for the first device
+ self.window.get('preset_autoload_switch').set_active(True)
+ gtk_iteration()
+ self.assertTrue(self.window.get('preset_autoload_switch').get_active())
self.assertTrue(config.is_autoloaded('device 1', 'new preset'))
self.assertFalse(config.is_autoloaded('device 2', 'new preset'))
self.assertListEqual(
@@ -138,9 +143,18 @@ class TestIntegration(unittest.TestCase):
[('device 1', 'new preset')]
)
+ # switch the preset, the switch should be correct and the config
+ # not changed.
+ self.window.on_create_preset_clicked(None)
+ gtk_iteration()
+ self.assertEqual(self.window.selected_preset, 'new preset 2')
+ self.assertFalse(self.window.get('preset_autoload_switch').get_active())
+ self.assertTrue(config.is_autoloaded('device 1', 'new preset'))
+
# select a preset for the second device
self.window.on_select_device(FakeDropdown('device 2'))
- self.window.on_preset_autoload_switch_activate(None, True)
+ self.window.get('preset_autoload_switch').set_active(True)
+ gtk_iteration()
self.assertTrue(config.is_autoloaded('device 1', 'new preset'))
self.assertTrue(config.is_autoloaded('device 2', 'new preset'))
self.assertListEqual(
@@ -149,7 +163,8 @@ class TestIntegration(unittest.TestCase):
)
# disable autoloading for the second device
- self.window.on_preset_autoload_switch_activate(None, False)
+ self.window.get('preset_autoload_switch').set_active(False)
+ gtk_iteration()
self.assertTrue(config.is_autoloaded('device 1', 'new preset'))
self.assertFalse(config.is_autoloaded('device 2', 'new preset'))
self.assertListEqual(