keybinds 1.3.1__tar.gz → 1.3.2__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (53) hide show
  1. {keybinds-1.3.1 → keybinds-1.3.2}/PKG-INFO +1 -1
  2. {keybinds-1.3.1 → keybinds-1.3.2}/keybinds/__init__.py +1 -1
  3. {keybinds-1.3.1 → keybinds-1.3.2}/keybinds/_keyboard.py +16 -4
  4. {keybinds-1.3.1 → keybinds-1.3.2}/keybinds/_mouse.py +16 -4
  5. {keybinds-1.3.1 → keybinds-1.3.2}/keybinds/diagnostics/analysis.py +844 -816
  6. {keybinds-1.3.1 → keybinds-1.3.2}/keybinds/diagnostics/core.py +1 -0
  7. {keybinds-1.3.1 → keybinds-1.3.2}/keybinds/diagnostics/tracing.py +1 -0
  8. {keybinds-1.3.1 → keybinds-1.3.2}/keybinds/logical/keyboard.py +23 -5
  9. {keybinds-1.3.1 → keybinds-1.3.2}/keybinds/presets.py +41 -0
  10. {keybinds-1.3.1 → keybinds-1.3.2}/keybinds/simple.py +264 -238
  11. {keybinds-1.3.1 → keybinds-1.3.2}/keybinds/types.py +2 -0
  12. {keybinds-1.3.1 → keybinds-1.3.2}/keybinds.egg-info/PKG-INFO +1 -1
  13. {keybinds-1.3.1 → keybinds-1.3.2}/pyproject.toml +1 -1
  14. {keybinds-1.3.1 → keybinds-1.3.2}/tests/test_decorators_and_simple.py +8 -0
  15. {keybinds-1.3.1 → keybinds-1.3.2}/tests/test_runtime_bindings.py +63 -0
  16. {keybinds-1.3.1 → keybinds-1.3.2}/LICENSE +0 -0
  17. {keybinds-1.3.1 → keybinds-1.3.2}/README.md +0 -0
  18. {keybinds-1.3.1 → keybinds-1.3.2}/keybinds/_async.py +0 -0
  19. {keybinds-1.3.1 → keybinds-1.3.2}/keybinds/_backend.py +0 -0
  20. {keybinds-1.3.1 → keybinds-1.3.2}/keybinds/_base_bind.py +0 -0
  21. {keybinds-1.3.1 → keybinds-1.3.2}/keybinds/_bind_registry.py +0 -0
  22. {keybinds-1.3.1 → keybinds-1.3.2}/keybinds/_constants.py +0 -0
  23. {keybinds-1.3.1 → keybinds-1.3.2}/keybinds/_dispatcher.py +0 -0
  24. {keybinds-1.3.1 → keybinds-1.3.2}/keybinds/_hook.py +0 -0
  25. {keybinds-1.3.1 → keybinds-1.3.2}/keybinds/_parsing.py +0 -0
  26. {keybinds-1.3.1 → keybinds-1.3.2}/keybinds/_state.py +0 -0
  27. {keybinds-1.3.1 → keybinds-1.3.2}/keybinds/_window.py +0 -0
  28. {keybinds-1.3.1 → keybinds-1.3.2}/keybinds/bind.py +0 -0
  29. {keybinds-1.3.1 → keybinds-1.3.2}/keybinds/decorators.py +0 -0
  30. {keybinds-1.3.1 → keybinds-1.3.2}/keybinds/diagnostics/__init__.py +0 -0
  31. {keybinds-1.3.1 → keybinds-1.3.2}/keybinds/diagnostics/models.py +0 -0
  32. {keybinds-1.3.1 → keybinds-1.3.2}/keybinds/diagnostics/reporting.py +0 -0
  33. {keybinds-1.3.1 → keybinds-1.3.2}/keybinds/logical/__init__.py +0 -0
  34. {keybinds-1.3.1 → keybinds-1.3.2}/keybinds/logical/abbreviation.py +0 -0
  35. {keybinds-1.3.1 → keybinds-1.3.2}/keybinds/logical/parsing.py +0 -0
  36. {keybinds-1.3.1 → keybinds-1.3.2}/keybinds/logical/translate.py +0 -0
  37. {keybinds-1.3.1 → keybinds-1.3.2}/keybinds/winput/LICENSE +0 -0
  38. {keybinds-1.3.1 → keybinds-1.3.2}/keybinds/winput/__init__.py +0 -0
  39. {keybinds-1.3.1 → keybinds-1.3.2}/keybinds/winput/vk_codes.py +0 -0
  40. {keybinds-1.3.1 → keybinds-1.3.2}/keybinds/winput/winput.py +0 -0
  41. {keybinds-1.3.1 → keybinds-1.3.2}/keybinds.egg-info/SOURCES.txt +0 -0
  42. {keybinds-1.3.1 → keybinds-1.3.2}/keybinds.egg-info/dependency_links.txt +0 -0
  43. {keybinds-1.3.1 → keybinds-1.3.2}/keybinds.egg-info/requires.txt +0 -0
  44. {keybinds-1.3.1 → keybinds-1.3.2}/keybinds.egg-info/top_level.txt +0 -0
  45. {keybinds-1.3.1 → keybinds-1.3.2}/setup.cfg +0 -0
  46. {keybinds-1.3.1 → keybinds-1.3.2}/setup.py +0 -0
  47. {keybinds-1.3.1 → keybinds-1.3.2}/tests/test_bind_registry.py +0 -0
  48. {keybinds-1.3.1 → keybinds-1.3.2}/tests/test_bind_wait_and_is_pressed.py +0 -0
  49. {keybinds-1.3.1 → keybinds-1.3.2}/tests/test_diagnostics.py +0 -0
  50. {keybinds-1.3.1 → keybinds-1.3.2}/tests/test_logical_parsing.py +0 -0
  51. {keybinds-1.3.1 → keybinds-1.3.2}/tests/test_parsing.py +0 -0
  52. {keybinds-1.3.1 → keybinds-1.3.2}/tests/test_runtime_edge_cases.py +0 -0
  53. {keybinds-1.3.1 → keybinds-1.3.2}/tests/test_types.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: keybinds
3
- Version: 1.3.1
3
+ Version: 1.3.2
4
4
  Summary: Flexible global keyboard & mouse hotkeys for Windows
5
5
  Author: echolane
6
6
  License: MIT License
@@ -36,7 +36,7 @@ from ._backend import reinstall_hooks, rehook
36
36
 
37
37
  from ._constants import register_key_token
38
38
 
39
- __version__ = "1.3.1"
39
+ __version__ = "1.3.2"
40
40
 
41
41
  __all__ = [
42
42
  "Trigger","SuppressPolicy","ChordPolicy","OrderPolicy","FocusPolicy","InjectedPolicy","TextBoundaryPolicy","TextBackspacePolicy","OsKeyRepeatPolicy","ReplacementPolicy",
@@ -717,16 +717,28 @@ class Bind(BaseBind[winput.KeyboardEvent]):
717
717
 
718
718
  threading.Thread(target=_repeat, daemon=True).start()
719
719
 
720
- elif trig == Trigger.ON_DOUBLE_TAP and full and fresh_down and not is_repeat:
721
- win = self.config.timing.double_tap_window_ms
720
+ elif trig in (Trigger.ON_DOUBLE_TAP, Trigger.ON_TRIPLE_TAP) and full and fresh_down and not is_repeat:
721
+ required_taps = 2 if trig == Trigger.ON_DOUBLE_TAP else 3
722
+ win = (
723
+ self.config.timing.double_tap_window_ms
724
+ if trig == Trigger.ON_DOUBLE_TAP
725
+ else self.config.timing.triple_tap_window_ms
726
+ )
722
727
  if (now_ms - self._tap_last_ms) <= win:
723
728
  self._tap_count += 1
724
729
  else:
725
730
  self._tap_count = 1
726
731
  self._tap_last_ms = now_ms
727
- trace.note("decision", "double_tap_progress", tap_count=self._tap_count, window_ms=win)
732
+ progress_reason = "double_tap_progress" if trig == Trigger.ON_DOUBLE_TAP else "triple_tap_progress"
733
+ trace.note(
734
+ "decision",
735
+ progress_reason,
736
+ tap_count=self._tap_count,
737
+ required_taps=required_taps,
738
+ window_ms=win,
739
+ )
728
740
 
729
- if self._tap_count >= 2:
741
+ if self._tap_count >= required_taps:
730
742
  self._tap_count = 0
731
743
  fired = fire_if_allowed(now_ms)
732
744
  if fired is not None and self.config.suppress == SuppressPolicy.WHEN_MATCHED:
@@ -293,15 +293,27 @@ class MouseBind(BaseBind[winput.MouseEvent]):
293
293
 
294
294
  threading.Thread(target=_repeat, daemon=True).start()
295
295
 
296
- elif trig == Trigger.ON_DOUBLE_TAP and is_down:
297
- win = self.config.timing.double_tap_window_ms
296
+ elif trig in (Trigger.ON_DOUBLE_TAP, Trigger.ON_TRIPLE_TAP) and is_down:
297
+ required_taps = 2 if trig == Trigger.ON_DOUBLE_TAP else 3
298
+ win = (
299
+ self.config.timing.double_tap_window_ms
300
+ if trig == Trigger.ON_DOUBLE_TAP
301
+ else self.config.timing.triple_tap_window_ms
302
+ )
298
303
  if (now_ms - self._tap_last_ms) <= win:
299
304
  self._tap_count += 1
300
305
  else:
301
306
  self._tap_count = 1
302
307
  self._tap_last_ms = now_ms
303
- trace.note("decision", "double_tap_progress", tap_count=self._tap_count, window_ms=win)
304
- if self._tap_count >= 2:
308
+ progress_reason = "double_tap_progress" if trig == Trigger.ON_DOUBLE_TAP else "triple_tap_progress"
309
+ trace.note(
310
+ "decision",
311
+ progress_reason,
312
+ tap_count=self._tap_count,
313
+ required_taps=required_taps,
314
+ window_ms=win,
315
+ )
316
+ if self._tap_count >= required_taps:
305
317
  self._tap_count = 0
306
318
  fired = fire_if_allowed(now_ms)
307
319
  if fired is not None and self.config.suppress == SuppressPolicy.WHEN_MATCHED: