diff --git a/data/input-remapper.glade b/data/input-remapper.glade
index 9ce29959..49de9a94 100644
--- a/data/input-remapper.glade
+++ b/data/input-remapper.glade
@@ -801,7 +801,7 @@ Gives your keys back their original function
False
- 160
+ 200
True
True
diff --git a/inputremapper/event_combination.py b/inputremapper/event_combination.py
index 6cc70d8d..23336051 100644
--- a/inputremapper/event_combination.py
+++ b/inputremapper/event_combination.py
@@ -53,12 +53,14 @@ class EventCombination(Tuple[InputEvent]):
events = []
for init_arg in init_args:
event = None
+
for constructor in InputEvent.__get_validators__():
try:
event = constructor(init_arg)
break
except InputEventCreationError:
pass
+
if event:
events.append(event)
else:
@@ -68,7 +70,7 @@ class EventCombination(Tuple[InputEvent]):
def __str__(self):
# only used in tests and logging
- return f"EventCombination({', '.join([str(e.event_tuple) for e in self])})"
+ return f""
@classmethod
def __get_validators__(cls):
diff --git a/inputremapper/gui/editor/editor.py b/inputremapper/gui/editor/editor.py
index 96a4ca57..6e126c0b 100644
--- a/inputremapper/gui/editor/editor.py
+++ b/inputremapper/gui/editor/editor.py
@@ -23,14 +23,11 @@
import re
-import locale
-import gettext
-import os
-from inputremapper.configs.data import get_data_path
-from inputremapper.gui.gettext import _
+import time
from gi.repository import Gtk, GLib, Gdk
+from inputremapper.gui.gettext import _
from inputremapper.gui.editor.autocompletion import Autocompletion
from inputremapper.configs.system_mapping import system_mapping
from inputremapper.gui.active_preset import active_preset
@@ -110,6 +107,9 @@ def ensure_everything_saved(func):
SET_KEY_FIRST = _("Set the key first")
+RECORD_ALL = float("inf")
+RECORD_NONE = 0
+
class Editor:
"""Maintains the widgets of the editor."""
@@ -138,14 +138,7 @@ class Editor:
# keys were not pressed yet
self._input_has_arrived = False
- toggle = self.get_recording_toggle()
- toggle.connect("focus-out-event", self._reset_keycode_consumption)
- toggle.connect("focus-out-event", lambda *_: toggle.set_active(False))
- toggle.connect("toggled", self._on_recording_toggle_toggle)
- # Don't leave the input when using arrow keys or tab. wait for the
- # window to consume the keycode from the reader. I.e. a tab input should
- # be recorded, instead of causing the recording to stop.
- toggle.connect("key-press-event", lambda *args: Gdk.EVENT_STOP)
+ self.record_events_until = RECORD_NONE
text_input = self.get_text_input()
text_input.connect("focus-out-event", self.on_text_input_unfocus)
@@ -161,6 +154,16 @@ class Editor:
GLib.source_remove(timeout)
self.timeouts = []
+ def _on_toggle_clicked(self, toggle, event=None):
+ if toggle.get_active():
+ self._show_press_key()
+ else:
+ self._show_change_key()
+
+ @ensure_everything_saved
+ def _on_toggle_unfocus(self, toggle, event=None):
+ toggle.set_active(False)
+
@ensure_everything_saved
def on_text_input_unfocus(self, *_):
"""When unfocusing the text it saves.
@@ -184,7 +187,8 @@ class Editor:
One could debounce saving on text-change to avoid those logs, but that just
sounds like a huge source of race conditions and is also hard to test.
"""
- pass
+ print("on_text_input_unfocus")
+ pass # the decorator will be triggered
@ensure_everything_saved
def _on_target_input_changed(self, *_):
@@ -229,31 +233,25 @@ class Editor:
def _setup_recording_toggle(self):
"""Prepare the toggle button for recording key inputs."""
- toggle = self.get("key_recording_toggle")
- toggle.connect(
- "focus-out-event",
- self._show_change_key,
- )
- toggle.connect(
- "focus-in-event",
- self._show_press_key,
- )
- toggle.connect(
- "clicked",
- lambda _: (
- self._show_press_key()
- if toggle.get_active()
- else self._show_change_key()
- ),
- )
+ toggle = self.get_recording_toggle()
+ toggle.connect("focus-out-event", self._show_change_key)
+ toggle.connect("focus-in-event", self._show_press_key)
+ toggle.connect("clicked", self._on_toggle_clicked)
+ toggle.connect("focus-out-event", self._reset_keycode_consumption)
+ toggle.connect("focus-out-event", self._on_toggle_unfocus)
+ toggle.connect("toggled", self._on_recording_toggle_toggle)
+ # Don't leave the input when using arrow keys or tab. wait for the
+ # window to consume the keycode from the reader. I.e. a tab input should
+ # be recorded, instead of causing the recording to stop.
+ toggle.connect("key-press-event", lambda *args: Gdk.EVENT_STOP)
- def _show_press_key(self, *_):
+ def _show_press_key(self, *args):
"""Show user friendly instructions."""
- self.get("key_recording_toggle").set_label("Press Key")
+ self.get_recording_toggle().set_label("Press Key")
- def _show_change_key(self, *_):
+ def _show_change_key(self, *args):
"""Show user friendly instructions."""
- self.get("key_recording_toggle").set_label("Change Key")
+ self.get_recording_toggle().set_label("Change Key")
def _setup_source_view(self):
"""Prepare the code editor."""
@@ -322,8 +320,12 @@ class Editor:
presets accidentally before configuring the key and then it's gone. It can
only be saved to the preset if a key is configured. This avoids that pitfall.
"""
+ logger.debug("Disabling the text input")
text_input = self.get_text_input()
+
+ # beware that this also disables event listeners like focus-out-event:
text_input.set_sensitive(False)
+
text_input.set_opacity(0.5)
if clear or self.get_symbol_input_text() == "":
@@ -332,6 +334,7 @@ class Editor:
def enable_symbol_input(self):
"""Don't display help information anymore and allow changing the symbol."""
+ logger.debug("Enabling the text input")
text_input = self.get_text_input()
text_input.set_sensitive(True)
text_input.set_opacity(1)
@@ -428,6 +431,11 @@ class Editor:
"""Show what the user is currently pressing in the user interface."""
self.active_selection_label.set_combination(combination)
+ if combination and len(combination) > 0:
+ self.enable_symbol_input()
+ else:
+ self.disable_symbol_input()
+
def get_combination(self):
"""Get the EventCombination object from the left column.
@@ -491,11 +499,16 @@ class Editor:
return True
- def _on_recording_toggle_toggle(self, *args):
+ def _on_recording_toggle_toggle(self, toggle):
"""Refresh useful usage information."""
- if not self.get_recording_toggle().get_active():
+ if not toggle.get_active():
+ # if more events arrive from the time when the toggle was still on,
+ # use them.
+ self.record_events_until = time.time()
return
+ self.record_events_until = RECORD_ALL
+
self._reset_keycode_consumption()
reader.clear()
if not self.user_interface.can_modify_preset():
@@ -505,7 +518,7 @@ class Editor:
self.user_interface.show_status(
CTX_ERROR, _('Use "Stop Injection" to stop before editing')
)
- self.get_recording_toggle().set_active(False)
+ toggle.set_active(False)
def _on_delete_button_clicked(self, *_):
"""Destroy the row and remove it from the config."""
@@ -560,22 +573,28 @@ class Editor:
self.user_interface.save_preset()
def is_waiting_for_input(self):
- """Check if the user is interacting with the ToggleButton for combination recording."""
+ """Check if the user is trying to record buttons."""
return self.get_recording_toggle().get_active()
- def consume_newest_keycode(self, combination):
- """To capture events from keyboards, mice and gamepads.
-
- Parameters
- ----------
- combination : EventCombination or None
- """
+ def should_record_combination(self, combination):
+ """Check if the combination was written when the toggle was active."""
+ # At this point the toggle might already be off, because some keys that are
+ # used while the toggle was still on might cause the focus of the toggle to
+ # be lost, like multimedia keys. This causes the toggle to be disabled.
+ # Yet, this event should be mapped.
+ timestamp = max([event.timestamp() for event in combination])
+ return timestamp < self.record_events_until
+
+ def consume_newest_keycode(self, combination: EventCombination):
+ """To capture events from keyboards, mice and gamepads."""
self._switch_focus_if_complete()
if combination is None:
return
- if not self.is_waiting_for_input():
+ if not self.should_record_combination(combination):
+ # the event arrived after the toggle has been deactivated
+ logger.debug("Recording toggle is not on")
return
if not isinstance(combination, EventCombination):
@@ -592,7 +611,7 @@ class Editor:
)
logger.info("%s %s", combination, msg)
self.user_interface.show_status(CTX_KEYCODE, msg)
- return True
+ return
if combination.is_problematic():
self.user_interface.show_status(
@@ -620,8 +639,13 @@ class Editor:
symbol = self.get_symbol_input_text()
target = self.get_target_selection()
- # the symbol is empty and therefore the mapping is not complete
- if not symbol or not target:
+ if not symbol:
+ # has not been entered yet
+ logger.debug("Symbol missing")
+ return
+
+ if not target:
+ logger.debug("Target missing")
return
# else, the keycode has changed, the symbol is set, all good
@@ -648,6 +672,7 @@ class Editor:
all_keys_released = reader.get_unreleased_keys() is None
if all_keys_released and self._input_has_arrived and self.get_combination():
+ logger.debug("Recording complete")
# A key was pressed and then released.
# Switch to the symbol. idle_add this so that the
# keycode event won't write into the symbol input as well.
diff --git a/inputremapper/gui/helper.py b/inputremapper/gui/helper.py
index f0d228ed..d5be0994 100644
--- a/inputremapper/gui/helper.py
+++ b/inputremapper/gui/helper.py
@@ -48,8 +48,13 @@ from inputremapper import utils
from inputremapper.user import USER
-TERMINATE = "terminate"
-REFRESH_GROUPS = "refresh_groups"
+# received by the helper
+CMD_TERMINATE = "terminate"
+CMD_REFRESH_GROUPS = "refresh_groups"
+
+# sent by the helper to the reader
+MSG_GROUPS = "groups"
+MSG_EVENT = "event"
def is_helper_running():
@@ -88,7 +93,7 @@ class RootHelper:
def _send_groups(self):
"""Send the groups to the gui."""
- self._results.send({"type": "groups", "message": groups.dumps()})
+ self._results.send({"type": MSG_GROUPS, "message": groups.dumps()})
def _handle_commands(self):
"""Handle all unread commands."""
@@ -99,11 +104,11 @@ class RootHelper:
cmd = self._commands.recv()
logger.debug('Received command "%s"', cmd)
- if cmd == TERMINATE:
+ if cmd == CMD_TERMINATE:
logger.debug("Helper terminates")
sys.exit(0)
- if cmd == REFRESH_GROUPS:
+ if cmd == CMD_REFRESH_GROUPS:
groups.refresh()
self._send_groups()
continue
@@ -209,7 +214,7 @@ class RootHelper:
self._results.send(
{
- "type": "event",
+ "type": MSG_EVENT,
"message": (event.sec, event.usec, event.type, event.code, event.value),
}
)
diff --git a/inputremapper/gui/reader.py b/inputremapper/gui/reader.py
index f87c56c0..4bd29bc0 100644
--- a/inputremapper/gui/reader.py
+++ b/inputremapper/gui/reader.py
@@ -32,7 +32,12 @@ from inputremapper.logger import logger
from inputremapper.event_combination import EventCombination
from inputremapper.groups import groups, GAMEPAD
from inputremapper.ipc.pipe import Pipe
-from inputremapper.gui.helper import TERMINATE, REFRESH_GROUPS
+from inputremapper.gui.helper import (
+ MSG_EVENT,
+ MSG_GROUPS,
+ CMD_TERMINATE,
+ CMD_REFRESH_GROUPS,
+)
from inputremapper import utils
from inputremapper.gui.active_preset import active_preset
from inputremapper.user import USER
@@ -88,14 +93,14 @@ class Reader:
message_type = message["type"]
message_body = message["message"]
- if message_type == "groups":
+ if message_type == MSG_GROUPS:
if message_body != groups.dumps():
groups.loads(message_body)
logger.debug("Received %d devices", len(groups))
self._groups_updated = True
return None
- if message_type == "event":
+ if message_type == MSG_EVENT:
return InputEvent(*message_body)
logger.error('Received unknown message "%s"', message)
@@ -139,12 +144,12 @@ class Reader:
continue
if event.value == 0:
- logger.debug_key(event.event_tuple, "release")
+ logger.debug_key(event, "release")
self._release(event.type_and_code)
continue
- if self._unreleased.get(event.type_and_code) == event.event_tuple:
- logger.debug_key(event.event_tuple, "duplicate key down")
+ if self._unreleased.get(event.type_and_code) == event:
+ logger.debug_key(event, "duplicate key down")
self._debounce_start(event.event_tuple)
continue
@@ -154,8 +159,8 @@ class Reader:
# from release to input in order to remember it. Since all release
# events have value 0, the value is not used in the combination.
key_down_received = True
- logger.debug_key(event.event_tuple, "down")
- self._unreleased[event.type_and_code] = event.event_tuple
+ logger.debug_key(event, "down")
+ self._unreleased[event.type_and_code] = event
self._debounce_start(event.event_tuple)
previous_event = event
@@ -190,11 +195,11 @@ class Reader:
def terminate(self):
"""Stop reading keycodes for good."""
logger.debug("Sending close msg to helper")
- self._commands.send(TERMINATE)
+ self._commands.send(CMD_TERMINATE)
def refresh_groups(self):
"""Ask the helper for new device groups."""
- self._commands.send(REFRESH_GROUPS)
+ self._commands.send(CMD_REFRESH_GROUPS)
def clear(self):
"""Next time when reading don't return the previous keycode."""
diff --git a/inputremapper/gui/user_interface.py b/inputremapper/gui/user_interface.py
index 053d0683..69d1d6dd 100644
--- a/inputremapper/gui/user_interface.py
+++ b/inputremapper/gui/user_interface.py
@@ -407,12 +407,18 @@ class UserInterface:
# letting go of one of the keys of a combination won't just make
# it return the leftover key, it will continue to return None because
# they have already been read.
- key = reader.read()
+ combination = reader.read()
if reader.are_new_groups_available():
self.populate_devices()
- self.editor.consume_newest_keycode(key)
+ # giving editor its own interval and making it call reader.read itself causes
+ # incredibly frustrating and miraculous problems. Do not do it. Observations:
+ # - test_autocomplete_key fails if the gui has been launched and closed by a
+ # previous test already
+ # Maybe it has something to do with the order of editor.consume_newest_keycode
+ # and user_interface.populate_devices.
+ self.editor.consume_newest_keycode(combination)
return True
diff --git a/inputremapper/input_event.py b/inputremapper/input_event.py
index 3acdbd6c..796cbfc1 100644
--- a/inputremapper/input_event.py
+++ b/inputremapper/input_event.py
@@ -116,6 +116,18 @@ class InputEvent:
"""event type, code, value"""
return self.type, self.code, self.value
+ def __str__(self):
+ if self.type == evdev.ecodes.EV_KEY:
+ key_name = evdev.ecodes.bytype[self.type].get(self.code, self.code)
+ action = "down" if self.value == 1 else "up"
+ return f""
+
+ return f""
+
+ def timestamp(self):
+ """Return the unix timestamp of when the event was seen."""
+ return self.sec + self.usec / 1000000
+
def modify(
self,
sec: int = None,
diff --git a/inputremapper/logger.py b/inputremapper/logger.py
index 4118b4e5..ab3cbead 100644
--- a/inputremapper/logger.py
+++ b/inputremapper/logger.py
@@ -61,10 +61,10 @@ def debug_key(self, key, msg, *args):
msg = msg % args
str_key = str(key)
str_key = str_key.replace(",)", ")")
- spacing = " " + "-" * max(0, 30 - len(str_key))
+ spacing = " " + "·" * max(0, 30 - len(msg))
if len(spacing) == 1:
spacing = ""
- msg = f"{str_key}{spacing} {msg}"
+ msg = f"{msg}{spacing} {str_key}"
if msg == previous_key_debug_log:
# avoid some super spam from EV_ABS events
diff --git a/tests/integration/test_gui.py b/tests/integration/test_gui.py
index 2a118643..8e64df38 100644
--- a/tests/integration/test_gui.py
+++ b/tests/integration/test_gui.py
@@ -288,7 +288,7 @@ class GuiTestBase(unittest.TestCase):
raise e
# try again
- print("Test failed, trying again")
+ print("Test failed, trying again...")
self.tearDown()
self.setUp()
@@ -335,6 +335,17 @@ class GuiTestBase(unittest.TestCase):
def tearDownClass(cls):
UserInterface.start_processes = cls.original_start_processes
+ def activate_recording_toggle(self):
+ logger.info("Activating the recording toggle")
+ self.set_focus(self.toggle)
+ self.toggle.set_active(True)
+
+ def disable_recording_toggle(self):
+ logger.info("Deactivating the recording toggle")
+ self.set_focus(None)
+ # should happen automatically:
+ self.assertFalse(self.toggle.get_active())
+
def set_focus(self, widget):
logger.info("Focusing %s", widget)
@@ -781,23 +792,31 @@ class TestGui(GuiTestBase):
"Button A + Button B + Button C",
)
+ def test_is_waiting_for_input(self):
+ self.activate_recording_toggle()
+ self.assertTrue(self.editor.is_waiting_for_input())
+
+ self.disable_recording_toggle()
+ self.assertFalse(self.editor.is_waiting_for_input())
+
def test_editor_simple(self):
self.assertEqual(self.toggle.get_label(), "Change Key")
self.assertEqual(len(self.selection_label_listbox.get_children()), 1)
selection_label = self.selection_label_listbox.get_children()[0]
- self.set_focus(self.toggle)
- self.toggle.set_active(True)
+ self.activate_recording_toggle()
+ self.assertTrue(self.editor.is_waiting_for_input())
self.assertEqual(self.toggle.get_label(), "Press Key")
- self.editor.consume_newest_keycode(None)
+ self.user_interface.consume_newest_keycode()
# nothing happens
self.assertIsNone(selection_label.get_combination())
self.assertEqual(len(active_preset), 0)
self.assertEqual(self.toggle.get_label(), "Press Key")
- self.editor.consume_newest_keycode(EventCombination([EV_KEY, 30, 1]))
+ send_event_to_reader(InputEvent.from_tuple((EV_KEY, 30, 1)))
+ self.user_interface.consume_newest_keycode()
# no symbol configured yet, so the active_preset remains empty
self.assertEqual(len(active_preset), 0)
self.assertEqual(len(selection_label.get_combination()), 1)
@@ -806,9 +825,10 @@ class TestGui(GuiTestBase):
# but KEY_ is removed from the text for display purposes
self.assertEqual(selection_label.get_label(), "a")
- # providing the same key again (Maybe this could happen for gamepads or
- # something, idk) doesn't do any harm
- self.editor.consume_newest_keycode(EventCombination([EV_KEY, 30, 1]))
+ # providing the same key again doesn't do any harm
+ # (Maybe this could happen for gamepads or something, idk)
+ send_event_to_reader(InputEvent.from_tuple((EV_KEY, 30, 1)))
+ self.user_interface.consume_newest_keycode()
self.assertEqual(len(active_preset), 0) # not released yet
self.assertEqual(len(selection_label.get_combination()), 1)
self.assertEqual(selection_label.get_combination()[0], (EV_KEY, 30, 1))
@@ -821,11 +841,17 @@ class TestGui(GuiTestBase):
2,
)
+ self.disable_recording_toggle()
self.set_focus(self.editor.get_text_input())
+ self.assertFalse(self.editor.is_waiting_for_input())
+
self.editor.set_symbol_input_text("Shift_L")
+
self.set_focus(None)
+ self.assertFalse(self.editor.is_waiting_for_input())
- self.assertEqual(len(active_preset), 1)
+ num_mappings = len(active_preset)
+ self.assertEqual(num_mappings, 1)
time.sleep(0.1)
gtk_iteration()
@@ -1970,7 +1996,7 @@ class TestGui(GuiTestBase):
self.assertTrue(os.path.exists(f"{device_path}/new preset.json"))
def test_enable_disable_symbol_input(self):
- self.editor.disable_symbol_input()
+ # should be disabled by default since no key is recorded yet
self.assertEqual(self.get_unfiltered_symbol_input_text(), SET_KEY_FIRST)
self.assertFalse(self.editor.get_text_input().get_sensitive())
@@ -1978,6 +2004,26 @@ class TestGui(GuiTestBase):
self.assertEqual(self.get_unfiltered_symbol_input_text(), "")
self.assertTrue(self.editor.get_text_input().get_sensitive())
+ # disable it
+ self.editor.disable_symbol_input()
+ self.assertFalse(self.editor.get_text_input().get_sensitive())
+
+ # try to enable it by providing a key via set_combination
+ self.editor.set_combination(EventCombination((1, 201, 1)))
+ self.assertEqual(self.get_unfiltered_symbol_input_text(), "")
+ self.assertTrue(self.editor.get_text_input().get_sensitive())
+
+ # disable it again
+ self.editor.set_combination(None)
+ self.assertFalse(self.editor.get_text_input().get_sensitive())
+
+ # try to enable it via the reader
+ self.activate_recording_toggle()
+ send_event_to_reader(InputEvent.from_tuple((EV_KEY, 101, 1)))
+ self.user_interface.consume_newest_keycode()
+ self.assertEqual(self.get_unfiltered_symbol_input_text(), "")
+ self.assertTrue(self.editor.get_text_input().get_sensitive())
+
# it wouldn't clear user input, if for whatever reason (a bug?) there is user
# input in there when enable_symbol_input is called.
self.editor.set_symbol_input_text("foo")
diff --git a/tests/test.py b/tests/test.py
index 8b5bf624..5f9d7388 100644
--- a/tests/test.py
+++ b/tests/test.py
@@ -565,7 +565,7 @@ def send_event_to_reader(event):
def quick_cleanup(log=True):
"""Reset the applications state."""
if log:
- print("quick cleanup")
+ print("Quick cleanup...")
for device in list(pending_events.keys()):
try:
@@ -648,13 +648,16 @@ def quick_cleanup(log=True):
uinput.write_count = 0
uinput.write_history = []
+ if log:
+ print("Quick cleanup done")
+
def cleanup():
"""Reset the applications state.
Using this is slower, usually quick_cleanup() is sufficient.
"""
- print("cleanup")
+ print("Cleanup...")
os.system("pkill -f input-remapper-service")
os.system("pkill -f input-remapper-control")
@@ -665,6 +668,8 @@ def cleanup():
with patch.object(sys, "argv", ["input-remapper-service"]):
global_uinputs.prepare()
+ print("Cleanup done")
+
def spy(obj, name):
"""Convenient wrapper for patch.object(..., ..., wraps=...)."""
diff --git a/tests/unit/test_event_combination.py b/tests/unit/test_event_combination.py
index d1458260..661c929d 100644
--- a/tests/unit/test_event_combination.py
+++ b/tests/unit/test_event_combination.py
@@ -31,20 +31,17 @@ class TestKey(unittest.TestCase):
def test_key(self):
# its very similar to regular tuples, but with some extra stuff
key_1 = EventCombination((1, 3, 1), (1, 5, 1))
- self.assertEqual(str(key_1), "EventCombination((1, 3, 1), (1, 5, 1))")
self.assertEqual(len(key_1), 2)
self.assertEqual(key_1[0], (1, 3, 1))
self.assertEqual(key_1[1], (1, 5, 1))
self.assertEqual(hash(key_1), hash(((1, 3, 1), (1, 5, 1))))
key_2 = EventCombination((1, 3, 1))
- self.assertEqual(str(key_2), "EventCombination((1, 3, 1))")
self.assertEqual(len(key_2), 1)
self.assertNotEqual(key_2, key_1)
self.assertNotEqual(hash(key_2), hash(key_1))
key_3 = EventCombination((1, 3, 1))
- self.assertEqual(str(key_3), "EventCombination((1, 3, 1))")
self.assertEqual(len(key_3), 1)
self.assertEqual(key_3, key_2)
self.assertNotEqual(key_3, (1, 3, 1))
@@ -52,15 +49,11 @@ class TestKey(unittest.TestCase):
self.assertEqual(hash(key_3), hash(((1, 3, 1),)))
key_4 = EventCombination(*key_3)
- self.assertEqual(str(key_4), "EventCombination((1, 3, 1))")
self.assertEqual(len(key_4), 1)
self.assertEqual(key_4, key_3)
self.assertEqual(hash(key_4), hash(key_3))
key_5 = EventCombination(*key_4, *key_4, (1, 7, 1))
- self.assertEqual(
- str(key_5), "EventCombination((1, 3, 1), (1, 3, 1), (1, 7, 1))"
- )
self.assertEqual(len(key_5), 3)
self.assertNotEqual(key_5, key_4)
self.assertNotEqual(hash(key_5), hash(key_4))
diff --git a/tests/unit/test_logger.py b/tests/unit/test_logger.py
index c198aea5..348af2a8 100644
--- a/tests/unit/test_logger.py
+++ b/tests/unit/test_logger.py
@@ -50,8 +50,14 @@ class TestLogger(unittest.TestCase):
logger.debug_key(((1, 200, -1), (1, 5, 1)), "foo %s", (1, 2))
with open(path, "r") as f:
content = f.read().lower()
- self.assertIn("((1, 2, 1)) ------------------- foo 1234 bar", content)
- self.assertIn("((1, 200, -1), (1, 5, 1)) ----- foo (1, 2)", content)
+ self.assertIn(
+ "foo 1234 bar ·················· ((1, 2, 1))",
+ content,
+ )
+ self.assertIn(
+ "foo (1, 2) ···················· ((1, 200, -1), (1, 5, 1))",
+ content,
+ )
def test_log_info(self):
update_verbosity(debug=False)