codekingpro/portable-devtools
114k
1import traceback2 3import win32api4import win32con5import win32ui6 7from . import IDLEenvironment, keycodes8 9HANDLER_ARGS_GUESS = 010HANDLER_ARGS_NATIVE = 111HANDLER_ARGS_IDLE = 212HANDLER_ARGS_EXTENSION = 313 14next_id = 500015 16event_to_commands = {} # dict of integer IDs to event names.17command_to_events = {} # dict of event names to int IDs18 19 20def assign_command_id(event, id=0):21 global next_id22 if id == 0:23 id = event_to_commands.get(event, 0)24 if id == 0:25 id = next_id26 next_id = next_id + 127 # Only map the ones we allocated - specified ones are assumed to have a handler28 command_to_events[id] = event29 event_to_commands[event] = id30 return id31 32 33class SendCommandHandler:34 def __init__(self, cmd):35 self.cmd = cmd36 37 def __call__(self, *args):38 win32ui.GetMainFrame().SendMessage(win32con.WM_COMMAND, self.cmd)39 40 41class Binding:42 def __init__(self, handler, handler_args_type):43 self.handler = handler44 self.handler_args_type = handler_args_type45 46 47class BindingsManager:48 def __init__(self, parent_view):49 self.parent_view = parent_view50 self.bindings = {} # dict of Binding instances.51 self.keymap = {}52 53 def prepare_configure(self):54 self.keymap = {}55 56 def complete_configure(self):57 for id in command_to_events.keys():58 self.parent_view.HookCommand(self._OnCommand, id)59 60 def close(self):61 self.parent_view = self.bindings = self.keymap = None62 63 def report_error(self, problem):64 try:65 win32ui.SetStatusText(problem, 1)66 except win32ui.error:67 # No status bar!68 print(problem)69 70 def update_keymap(self, keymap):71 self.keymap.update(keymap)72 73 def bind(self, event, handler, handler_args_type=HANDLER_ARGS_GUESS, cid=0):74 if handler is None:75 handler = SendCommandHandler(cid)76 self.bindings[event] = self._new_binding(handler, handler_args_type)77 self.bind_command(event, cid)78 79 def bind_command(self, event, id=0):80 "Binds an event to a Windows control/command ID"81 id = assign_command_id(event, id)82 return id83 84 def get_command_id(self, event):85 id = event_to_commands.get(event)86 if id is None:87 # See if we even have an event of that name!?88 if event not in self.bindings:89 return None90 id = self.bind_command(event)91 return id92 93 def _OnCommand(self, id, code):94 event = command_to_events.get(id)95 if event is None:96 self.report_error("No event associated with event ID %d" % id)97 return 198 return self.fire(event)99 100 def _new_binding(self, event, handler_args_type):101 return Binding(event, handler_args_type)102 103 def _get_IDLE_handler(self, ext, handler):104 try:105 instance = self.parent_view.idle.IDLEExtension(ext)106 name = handler.replace("-", "_") + "_event"107 return getattr(instance, name)108 except (ImportError, AttributeError):109 msg = "Can not find event '%s' in IDLE extension '%s'" % (handler, ext)110 self.report_error(msg)111 return None112 113 def fire(self, event, event_param=None):114 # Fire the specified event. Result is native Pythonwin result115 # (ie, 1==pass one, 0 or None==handled)116 117 # First look up the event directly - if there, we are set.118 binding = self.bindings.get(event)119 if binding is None:120 # If possible, find it!121 # A native method name122 handler = getattr(self.parent_view, event + "Event", None)123 if handler is None:124 # Can't decide if I should report an error??125 self.report_error("The event name '%s' can not be found." % event)126 # Either way, just let the default handlers grab it.127 return 1128 binding = self._new_binding(handler, HANDLER_ARGS_NATIVE)129 # Cache it.130 self.bindings[event] = binding131 132 handler_args_type = binding.handler_args_type133 # Now actually fire it.134 if handler_args_type == HANDLER_ARGS_GUESS:135 # Can't be native, as natives are never added with "guess".136 # Must be extension or IDLE.137 if event[0] == "<":138 handler_args_type = HANDLER_ARGS_IDLE139 else:140 handler_args_type = HANDLER_ARGS_EXTENSION141 try:142 if handler_args_type == HANDLER_ARGS_EXTENSION:143 args = self.parent_view.idle, event_param144 else:145 args = (event_param,)146 rc = binding.handler(*args)147 if handler_args_type == HANDLER_ARGS_IDLE:148 # Convert to our return code.149 if rc in (None, "break"):150 rc = 0151 else:152 rc = 1153 except:154 message = "Firing event '%s' failed." % event155 print(message)156 traceback.print_exc()157 self.report_error(message)158 rc = 1 # Let any default handlers have a go!159 return rc160 161 def fire_key_event(self, msg):162 key = msg[2]163 keyState = 0164 if win32api.GetKeyState(win32con.VK_CONTROL) & 0x8000:165 keyState = (166 keyState | win32con.RIGHT_CTRL_PRESSED | win32con.LEFT_CTRL_PRESSED167 )168 if win32api.GetKeyState(win32con.VK_SHIFT) & 0x8000:169 keyState = keyState | win32con.SHIFT_PRESSED170 if win32api.GetKeyState(win32con.VK_MENU) & 0x8000:171 keyState = keyState | win32con.LEFT_ALT_PRESSED | win32con.RIGHT_ALT_PRESSED172 keyinfo = key, keyState173 # Special hacks for the dead-char key on non-US keyboards.174 # (XXX - which do not work :-(175 event = self.keymap.get(keyinfo)176 if event is None:177 return 1178 return self.fire(event, None)179 