actions.py 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104
  1. import abc
  2. import logging
  3. import typing
  4. import Xlib.protocol.event
  5. import Xlib.X
  6. class EngineAction:
  7. def __init__(self, target_engine_index: typing.Optional[int] = None):
  8. self._target_engine_index = target_engine_index
  9. @abc.abstractmethod
  10. def execute_on_window(self, overlay, xkeyevent, engine_window):
  11. raise NotImplementedError()
  12. def execute(self, overlay, xkeyevent):
  13. if not self._target_engine_index:
  14. for target_window in overlay.engine_windows:
  15. self.execute_on_window(overlay, xkeyevent, target_window)
  16. elif self._target_engine_index >= len(overlay.engine_windows):
  17. logging.warning("target engine index out of bounds")
  18. else:
  19. self.execute_on_window(
  20. overlay, xkeyevent, overlay.engine_windows[self._target_engine_index]
  21. )
  22. class CenterClickAction(EngineAction):
  23. def __init__(self, target_engine_index, factor_x, factor_y):
  24. super().__init__(target_engine_index=target_engine_index,)
  25. self._button = Xlib.X.Button1
  26. self._factor_x = factor_x
  27. self._factor_y = factor_y
  28. def execute_on_window(self, overlay, xkeyevent, engine_window):
  29. engine_geometry = engine_window.get_geometry()
  30. smaller_dimension = min(engine_geometry.width, engine_geometry.height)
  31. attr = dict(
  32. window=engine_window,
  33. detail=self._button,
  34. state=xkeyevent.state,
  35. event_x=int(engine_geometry.width / 2 + smaller_dimension * self._factor_x),
  36. event_y=int(
  37. engine_geometry.height / 2 + smaller_dimension * self._factor_y
  38. ),
  39. # apparently root_x & root_y do not need to correspond with event_x/y.
  40. # attributes are still required to be set.
  41. root_x=0, # xkeyevent.root_x,
  42. root_y=0, # xkeyevent.root_y,
  43. child=xkeyevent.child,
  44. root=xkeyevent.root,
  45. time=xkeyevent.time, # X.CurrentTime
  46. same_screen=xkeyevent.same_screen,
  47. )
  48. if isinstance(xkeyevent, Xlib.protocol.event.KeyPress):
  49. e = Xlib.protocol.event.ButtonPress(**attr)
  50. else:
  51. e = Xlib.protocol.event.ButtonRelease(**attr)
  52. engine_window.send_event(e)
  53. class SelectGagAction(CenterClickAction):
  54. X_OFFSET = -0.286
  55. X_FACTOR = 0.081
  56. def __init__(self, target_engine_index, column_index, factor_y):
  57. super().__init__(
  58. target_engine_index=target_engine_index,
  59. factor_x=self.X_OFFSET + self.X_FACTOR * column_index,
  60. factor_y=factor_y,
  61. )
  62. class RewriteKeyEventAction(EngineAction):
  63. def __init__(self, target_engine_index: typing.Optional[int] = None, keysym=None):
  64. super().__init__(target_engine_index=target_engine_index,)
  65. self._keysym = keysym
  66. def execute_on_window(self, overlay, xkeyevent, engine_window):
  67. engine_window.send_event(
  68. type(xkeyevent)(
  69. window=engine_window,
  70. detail=overlay.xdisplay.keysym_to_keycode(self._keysym)
  71. if self._keysym
  72. else xkeyevent.detail,
  73. state=xkeyevent.state,
  74. root_x=xkeyevent.root_x,
  75. root_y=xkeyevent.root_y,
  76. event_x=xkeyevent.event_x,
  77. event_y=xkeyevent.event_y,
  78. child=xkeyevent.child,
  79. root=xkeyevent.root,
  80. time=xkeyevent.time, # X.CurrentTime
  81. same_screen=xkeyevent.same_screen,
  82. )
  83. )
  84. class ToggleOverlayAction:
  85. def execute(self, overlay, xkeyevent):
  86. if isinstance(xkeyevent, Xlib.protocol.event.KeyPress):
  87. overlay.toggle()