Funktionierender Prototyp des Serious Games zur Vermittlung von Wissen zu Software-Engineering-Arbeitsmodellen.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

bindings.py 5.9KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178
  1. import traceback
  2. import win32api
  3. import win32con
  4. import win32ui
  5. from . import IDLEenvironment, keycodes
  6. HANDLER_ARGS_GUESS = 0
  7. HANDLER_ARGS_NATIVE = 1
  8. HANDLER_ARGS_IDLE = 2
  9. HANDLER_ARGS_EXTENSION = 3
  10. next_id = 5000
  11. event_to_commands = {} # dict of integer IDs to event names.
  12. command_to_events = {} # dict of event names to int IDs
  13. def assign_command_id(event, id=0):
  14. global next_id
  15. if id == 0:
  16. id = event_to_commands.get(event, 0)
  17. if id == 0:
  18. id = next_id
  19. next_id = next_id + 1
  20. # Only map the ones we allocated - specified ones are assumed to have a handler
  21. command_to_events[id] = event
  22. event_to_commands[event] = id
  23. return id
  24. class SendCommandHandler:
  25. def __init__(self, cmd):
  26. self.cmd = cmd
  27. def __call__(self, *args):
  28. win32ui.GetMainFrame().SendMessage(win32con.WM_COMMAND, self.cmd)
  29. class Binding:
  30. def __init__(self, handler, handler_args_type):
  31. self.handler = handler
  32. self.handler_args_type = handler_args_type
  33. class BindingsManager:
  34. def __init__(self, parent_view):
  35. self.parent_view = parent_view
  36. self.bindings = {} # dict of Binding instances.
  37. self.keymap = {}
  38. def prepare_configure(self):
  39. self.keymap = {}
  40. def complete_configure(self):
  41. for id in command_to_events.keys():
  42. self.parent_view.HookCommand(self._OnCommand, id)
  43. def close(self):
  44. self.parent_view = self.bindings = self.keymap = None
  45. def report_error(self, problem):
  46. try:
  47. win32ui.SetStatusText(problem, 1)
  48. except win32ui.error:
  49. # No status bar!
  50. print(problem)
  51. def update_keymap(self, keymap):
  52. self.keymap.update(keymap)
  53. def bind(self, event, handler, handler_args_type=HANDLER_ARGS_GUESS, cid=0):
  54. if handler is None:
  55. handler = SendCommandHandler(cid)
  56. self.bindings[event] = self._new_binding(handler, handler_args_type)
  57. self.bind_command(event, cid)
  58. def bind_command(self, event, id=0):
  59. "Binds an event to a Windows control/command ID"
  60. id = assign_command_id(event, id)
  61. return id
  62. def get_command_id(self, event):
  63. id = event_to_commands.get(event)
  64. if id is None:
  65. # See if we even have an event of that name!?
  66. if event not in self.bindings:
  67. return None
  68. id = self.bind_command(event)
  69. return id
  70. def _OnCommand(self, id, code):
  71. event = command_to_events.get(id)
  72. if event is None:
  73. self.report_error("No event associated with event ID %d" % id)
  74. return 1
  75. return self.fire(event)
  76. def _new_binding(self, event, handler_args_type):
  77. return Binding(event, handler_args_type)
  78. def _get_IDLE_handler(self, ext, handler):
  79. try:
  80. instance = self.parent_view.idle.IDLEExtension(ext)
  81. name = handler.replace("-", "_") + "_event"
  82. return getattr(instance, name)
  83. except (ImportError, AttributeError):
  84. msg = "Can not find event '%s' in IDLE extension '%s'" % (handler, ext)
  85. self.report_error(msg)
  86. return None
  87. def fire(self, event, event_param=None):
  88. # Fire the specified event. Result is native Pythonwin result
  89. # (ie, 1==pass one, 0 or None==handled)
  90. # First look up the event directly - if there, we are set.
  91. binding = self.bindings.get(event)
  92. if binding is None:
  93. # If possible, find it!
  94. # A native method name
  95. handler = getattr(self.parent_view, event + "Event", None)
  96. if handler is None:
  97. # Can't decide if I should report an error??
  98. self.report_error("The event name '%s' can not be found." % event)
  99. # Either way, just let the default handlers grab it.
  100. return 1
  101. binding = self._new_binding(handler, HANDLER_ARGS_NATIVE)
  102. # Cache it.
  103. self.bindings[event] = binding
  104. handler_args_type = binding.handler_args_type
  105. # Now actually fire it.
  106. if handler_args_type == HANDLER_ARGS_GUESS:
  107. # Can't be native, as natives are never added with "guess".
  108. # Must be extension or IDLE.
  109. if event[0] == "<":
  110. handler_args_type = HANDLER_ARGS_IDLE
  111. else:
  112. handler_args_type = HANDLER_ARGS_EXTENSION
  113. try:
  114. if handler_args_type == HANDLER_ARGS_EXTENSION:
  115. args = self.parent_view.idle, event_param
  116. else:
  117. args = (event_param,)
  118. rc = binding.handler(*args)
  119. if handler_args_type == HANDLER_ARGS_IDLE:
  120. # Convert to our return code.
  121. if rc in (None, "break"):
  122. rc = 0
  123. else:
  124. rc = 1
  125. except:
  126. message = "Firing event '%s' failed." % event
  127. print(message)
  128. traceback.print_exc()
  129. self.report_error(message)
  130. rc = 1 # Let any default handlers have a go!
  131. return rc
  132. def fire_key_event(self, msg):
  133. key = msg[2]
  134. keyState = 0
  135. if win32api.GetKeyState(win32con.VK_CONTROL) & 0x8000:
  136. keyState = (
  137. keyState | win32con.RIGHT_CTRL_PRESSED | win32con.LEFT_CTRL_PRESSED
  138. )
  139. if win32api.GetKeyState(win32con.VK_SHIFT) & 0x8000:
  140. keyState = keyState | win32con.SHIFT_PRESSED
  141. if win32api.GetKeyState(win32con.VK_MENU) & 0x8000:
  142. keyState = keyState | win32con.LEFT_ALT_PRESSED | win32con.RIGHT_ALT_PRESSED
  143. keyinfo = key, keyState
  144. # Special hacks for the dead-char key on non-US keyboards.
  145. # (XXX - which do not work :-(
  146. event = self.keymap.get(keyinfo)
  147. if event is None:
  148. return 1
  149. return self.fire(event, None)