def _event_to_key_presses(self, ev): """ For this `KEY_EVENT_RECORD`, return a list of `KeyPress` instances. """ assert type(ev) == KEY_EVENT_RECORD and ev.KeyDown result = None u_char = ev.uChar.UnicodeChar ascii_char = u_char.encode('utf-8') # NOTE: We don't use `ev.uChar.AsciiChar`. That appears to be latin-1 # encoded. See also: # https://github.com/ipython/ipython/issues/10004 # https://github.com/jonathanslenders/python-prompt-toolkit/issues/389 if u_char == '\x00': if ev.VirtualKeyCode in self.keycodes: result = KeyPress(self.keycodes[ev.VirtualKeyCode], '') else: if ascii_char in self.mappings: if self.mappings[ascii_char] == Keys.ControlJ: u_char = '\n' # Windows sends \n, turn into \r for unix compatibility. result = KeyPress(self.mappings[ascii_char], u_char) else: result = KeyPress(u_char, u_char) # Correctly handle Control-Arrow keys. if (ev.ControlKeyState & self.LEFT_CTRL_PRESSED or ev.ControlKeyState & self.RIGHT_CTRL_PRESSED) and result: if result.key == Keys.Left: result.key = Keys.ControlLeft if result.key == Keys.Right: result.key = Keys.ControlRight if result.key == Keys.Up: result.key = Keys.ControlUp if result.key == Keys.Down: result.key = Keys.ControlDown # Turn 'Tab' into 'BackTab' when shift was pressed. if ev.ControlKeyState & self.SHIFT_PRESSED and result: if result.key == Keys.Tab: result.key = Keys.BackTab # Turn 'Space' into 'ControlSpace' when control was pressed. if (ev.ControlKeyState & self.LEFT_CTRL_PRESSED or ev.ControlKeyState & self.RIGHT_CTRL_PRESSED) and result and result.data == ' ': result = KeyPress(Keys.ControlSpace, ' ') # Turn Control-Enter into META-Enter. (On a vt100 terminal, we cannot # detect this combination. But it's really practical on Windows.) if (ev.ControlKeyState & self.LEFT_CTRL_PRESSED or ev.ControlKeyState & self.RIGHT_CTRL_PRESSED) and result and \ result.key == Keys.ControlJ: return [KeyPress(Keys.Escape, ''), result] # Return result. If alt was pressed, prefix the result with an # 'Escape' key, just like unix VT100 terminals do. # NOTE: Only replace the left alt with escape. The right alt key often # acts as altgr and is used in many non US keyboard layouts for # typing some special characters, like a backslash. We don't want # all backslashes to be prefixed with escape. (Esc-\ has a # meaning in E-macs, for instance.) if result: meta_pressed = ev.ControlKeyState & self.LEFT_ALT_PRESSED if meta_pressed: return [KeyPress(Keys.Escape, ''), result] else: return [result] else: return []
def _event_to_key_presses(self, ev: KEY_EVENT_RECORD) -> List[KeyPress]: """ For this `KEY_EVENT_RECORD`, return a list of `KeyPress` instances. """ assert type(ev) == KEY_EVENT_RECORD and ev.KeyDown result: Optional[KeyPress] = None control_key_state = ev.ControlKeyState u_char = ev.uChar.UnicodeChar # Use surrogatepass because u_char may be an unmatched surrogate ascii_char = u_char.encode("utf-8", "surrogatepass") # NOTE: We don't use `ev.uChar.AsciiChar`. That appears to be the # unicode code point truncated to 1 byte. See also: # https://github.com/ipython/ipython/issues/10004 # https://github.com/jonathanslenders/python-prompt-toolkit/issues/389 if u_char == "\x00": if ev.VirtualKeyCode in self.keycodes: result = KeyPress(self.keycodes[ev.VirtualKeyCode], "") else: if ascii_char in self.mappings: if self.mappings[ascii_char] == Keys.ControlJ: u_char = ( "\n" # Windows sends \n, turn into \r for unix compatibility. ) result = KeyPress(self.mappings[ascii_char], u_char) else: result = KeyPress(u_char, u_char) # First we handle Shift-Control-Arrow/Home/End (need to do this first) if ((control_key_state & self.LEFT_CTRL_PRESSED or control_key_state & self.RIGHT_CTRL_PRESSED) and control_key_state & self.SHIFT_PRESSED and result): mapping: Dict[str, str] = { Keys.Left: Keys.ControlShiftLeft, Keys.Right: Keys.ControlShiftRight, Keys.Up: Keys.ControlShiftUp, Keys.Down: Keys.ControlShiftDown, Keys.Home: Keys.ControlShiftHome, Keys.End: Keys.ControlShiftEnd, Keys.Insert: Keys.ControlShiftInsert, Keys.PageUp: Keys.ControlShiftPageUp, Keys.PageDown: Keys.ControlShiftPageDown, } result.key = mapping.get(result.key, result.key) # Correctly handle Control-Arrow/Home/End and Control-Insert/Delete keys. if (control_key_state & self.LEFT_CTRL_PRESSED or control_key_state & self.RIGHT_CTRL_PRESSED) and result: mapping = { Keys.Left: Keys.ControlLeft, Keys.Right: Keys.ControlRight, Keys.Up: Keys.ControlUp, Keys.Down: Keys.ControlDown, Keys.Home: Keys.ControlHome, Keys.End: Keys.ControlEnd, Keys.Insert: Keys.ControlInsert, Keys.Delete: Keys.ControlDelete, Keys.PageUp: Keys.ControlPageUp, Keys.PageDown: Keys.ControlPageDown, } result.key = mapping.get(result.key, result.key) # Turn 'Tab' into 'BackTab' when shift was pressed. # Also handle other shift-key combination if control_key_state & self.SHIFT_PRESSED and result: mapping = { Keys.Tab: Keys.BackTab, Keys.Left: Keys.ShiftLeft, Keys.Right: Keys.ShiftRight, Keys.Up: Keys.ShiftUp, Keys.Down: Keys.ShiftDown, Keys.Home: Keys.ShiftHome, Keys.End: Keys.ShiftEnd, Keys.Insert: Keys.ShiftInsert, Keys.Delete: Keys.ShiftDelete, Keys.PageUp: Keys.ShiftPageUp, Keys.PageDown: Keys.ShiftPageDown, } result.key = mapping.get(result.key, result.key) # Turn 'Space' into 'ControlSpace' when control was pressed. if ((control_key_state & self.LEFT_CTRL_PRESSED or control_key_state & self.RIGHT_CTRL_PRESSED) and result and result.data == " "): result = KeyPress(Keys.ControlSpace, " ") # Turn Control-Enter into META-Enter. (On a vt100 terminal, we cannot # detect this combination. But it's really practical on Windows.) if ((control_key_state & self.LEFT_CTRL_PRESSED or control_key_state & self.RIGHT_CTRL_PRESSED) and result and result.key == Keys.ControlJ): return [KeyPress(Keys.Escape, ""), result] # Return result. If alt was pressed, prefix the result with an # 'Escape' key, just like unix VT100 terminals do. # NOTE: Only replace the left alt with escape. The right alt key often # acts as altgr and is used in many non US keyboard layouts for # typing some special characters, like a backslash. We don't want # all backslashes to be prefixed with escape. (Esc-\ has a # meaning in E-macs, for instance.) if result: meta_pressed = control_key_state & self.LEFT_ALT_PRESSED if meta_pressed: return [KeyPress(Keys.Escape, ""), result] else: return [result] else: return []