keyboard.py 2.6 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677
  1. from typing import Any, Callable, List, Literal, Optional
  2. from typing_extensions import Self
  3. from ..binding import BindableProperty
  4. from ..element import Element
  5. from ..events import (
  6. GenericEventArguments,
  7. KeyboardAction,
  8. KeyboardKey,
  9. KeyboardModifiers,
  10. KeyEventArguments,
  11. handle_event,
  12. )
  13. class Keyboard(Element, component='keyboard.js'):
  14. active = BindableProperty()
  15. def __init__(self,
  16. on_key: Optional[Callable[..., Any]] = None, *,
  17. active: bool = True,
  18. repeating: bool = True,
  19. ignore: List[Literal['input', 'select', 'button', 'textarea']] =
  20. ['input', 'select', 'button', 'textarea'], # noqa: B006
  21. ) -> None:
  22. """Keyboard
  23. Adds global keyboard event tracking.
  24. :param on_key: callback to be executed when keyboard events occur.
  25. :param active: boolean flag indicating whether the callback should be executed or not (default: `True`)
  26. :param repeating: boolean flag indicating whether held keys should be sent repeatedly (default: `True`)
  27. :param ignore: ignore keys when one of these element types is focussed (default: `['input', 'select', 'button', 'textarea']`)
  28. """
  29. super().__init__()
  30. self._key_handlers = [on_key] if on_key else []
  31. self.active = active
  32. self._props['events'] = ['keydown', 'keyup']
  33. self._props['repeating'] = repeating
  34. self._props['ignore'] = ignore[:]
  35. self.on('key', self._handle_key)
  36. def _handle_key(self, e: GenericEventArguments) -> None:
  37. if not self.active:
  38. return
  39. action = KeyboardAction(
  40. keydown=e.args['action'] == 'keydown',
  41. keyup=e.args['action'] == 'keyup',
  42. repeat=e.args['repeat'],
  43. )
  44. modifiers = KeyboardModifiers(
  45. alt=e.args['altKey'],
  46. ctrl=e.args['ctrlKey'],
  47. meta=e.args['metaKey'],
  48. shift=e.args['shiftKey'],
  49. )
  50. key = KeyboardKey(
  51. name=e.args['key'],
  52. code=e.args['code'],
  53. location=e.args['location'],
  54. )
  55. arguments = KeyEventArguments(
  56. sender=self,
  57. client=self.client,
  58. action=action,
  59. modifiers=modifiers,
  60. key=key,
  61. )
  62. for handler in self._key_handlers:
  63. handle_event(handler, arguments)
  64. def on_key(self, handler: Callable[..., Any]) -> Self:
  65. """Add a callback to be invoked when keyboard events occur."""
  66. self._key_handlers.append(handler)
  67. return self