def test_on_feed_key_backspace(self, shell): shell.on_feed_key(KeyPress('x')) assert shell.current_command_key == 'm' shell.on_feed_key(KeyPress(Keys.Backspace)) assert shell.current_command_key == 'i' shell.on_feed_key(KeyPress(Keys.Backspace)) assert shell.current_command_key == 'i'
def test_on_feed_key_backspace(self, shell): shell.on_feed_key(KeyPress("x")) assert shell.current_command_key == "m" shell.on_feed_key(KeyPress(Keys.Backspace)) assert shell.current_command_key == "i" shell.on_feed_key(KeyPress(Keys.Backspace)) assert shell.current_command_key == "i"
def test_on_feed_key_does_not_increment_pos_past_length_of_command( self, make_shell): shell = make_shell(commands=["1+1"], speed=2) shell.on_feed_key(KeyPress("xx")) assert shell.current_command_pos == len("1+1") - 1 shell.on_feed_key(KeyPress("x")) assert shell.current_command_pos == len("1+1") shell.on_feed_key(KeyPress("x")) assert shell.current_command_pos == len("1+1")
def test_on_feed_key_does_not_increment_pos_past_length_of_command( self, make_shell): shell = make_shell(commands=['1+1'], speed=2) shell.on_feed_key(KeyPress('xx')) assert shell.current_command_pos == len('1+1') - 1 shell.on_feed_key(KeyPress('x')) assert shell.current_command_pos == len('1+1') shell.on_feed_key(KeyPress('x')) assert shell.current_command_pos == len('1+1')
def test_common_prefix(self): # Sending Control_X should not yet do anything, because there is # another sequence starting with that as well. self.processor.feed_key(KeyPress(Keys.ControlX, '')) self.assertEqual(self.handlers.called, []) # When another key is pressed, we know that we did not meant the longer # "ControlX ControlC" sequence and the callbacks are called. self.processor.feed_key(KeyPress(Keys.ControlD, '')) self.assertEqual(self.handlers.called, ['control_x', 'control_d'])
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 if ev.AsciiChar == b'\0': if ev.VirtualKeyCode in self.keycodes: result = KeyPress(self.keycodes[ev.VirtualKeyCode], '') else: enc = sys.stdin.encoding if ev.AsciiChar in self.mappings: result = KeyPress(self.mappings[ev.AsciiChar], ev.AsciiChar.decode(enc)) else: result = KeyPress(ev.AsciiChar.decode(enc), ev.AsciiChar.decode(enc)) # 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, ' ') # Return result. If alt was pressed, prefix the result with an # 'Escape' key, just like unix VT100 terminals do. if result: meta_pressed = ev.ControlKeyState & self.LEFT_ALT_PRESSED or \ ev.ControlKeyState & self.RIGHT_ALT_PRESSED if meta_pressed: return [KeyPress(Keys.Escape, ''), result] else: return [result] else: return []
def test_common_prefix(processor, handlers): # Sending Control_X should not yet do anything, because there is # another sequence starting with that as well. processor.feed(KeyPress(Keys.ControlX, '')) processor.process_keys() assert handlers.called == [] # When another key is pressed, we know that we did not meant the longer # "ControlX ControlC" sequence and the callbacks are called. processor.feed(KeyPress(Keys.ControlD, '')) processor.process_keys() assert handlers.called == ['control_x', 'control_d']
def on_feed_key(self, key_press): """Handles the magictyping when a key is pressed""" if key_press.key in {Keys.Escape, Keys.ControlC}: echo(carriage_return=True) raise Abort() if key_press.key == Keys.Backspace: if self.current_command_pos > 0: self.current_command_pos -= 1 return key_press ret = None if key_press.key != Keys.CPRResponse: if self.current_command_pos < len(self.current_command): current_key = self.current_command_key ret = KeyPress(current_key) increment = min([ self.speed, len(self.current_command) - self.current_command_pos ]) self.current_command_pos += increment else: # Command is finished, wait for Enter if key_press.key != Keys.Enter: return None self.current_command_index += 1 self.current_command_pos = 0 ret = key_press return ret
def _handle_keyboard_interrupt(self, e, platform): """Handles keyboard interrupts more gracefully on Mac/Unix/Linux. Allows Mac/Unix/Linux to continue running on keyboard interrupt, as the user might interrupt a long-running AWS command with Control-C while continuing to work with Saws. On Windows, the "Terminate batch job (Y/N)" confirmation makes it tricky to handle this gracefully. Thus, we re-raise KeyboardInterrupt. Args: * e: A KeyboardInterrupt. * platform: A string that denotes platform such as 'Windows', 'Darwin', etc. Returns: None Raises: Exception: A KeyboardInterrupt if running on Windows. """ if platform == 'Windows': raise e else: # Clear the renderer and send a carriage return self.aws_cli.renderer.clear() self.aws_cli.input_processor.feed_key(KeyPress(Keys.ControlM, ''))
def feed(self, data): """ Feed the input stream. :param data: Input string (unicode). """ assert isinstance(data, six.text_type) if _DEBUG_RENDERER_INPUT: self.LOG.write(repr(data).encode('utf-8') + b'\n') self.LOG.flush() # Handle bracketed paste. (We bypass the parser that matches all other # key presses and keep reading input until we see the end mark.) # This is much faster then parsing character by character. if self._in_bracketed_paste: self._paste_buffer += data end_mark = '\x1b[201~' if end_mark in self._paste_buffer: end_index = self._paste_buffer.index(end_mark) # Feed content to key bindings. paste_content = self._paste_buffer[:end_index] self.feed_key_callback( KeyPress(Keys.BracketedPaste, paste_content)) # Quit bracketed paste mode and handle remaining input. self._in_bracketed_paste = False remaining = self._paste_buffer[end_index + len(end_mark):] self._paste_buffer = '' self.feed(remaining) # Handle normal input character by character. else: for i, c in enumerate(data): if self._in_bracketed_paste: # Quit loop and process from this position when the parser # entered bracketed paste. self.feed(data[i:]) break else: # Replace \r by \n. (Some clients send \r instead of \n # when enter is pressed. E.g. telnet and some other # terminals.) # XXX: We should remove this in a future version. It *is* # now possible to recognise the difference. # (We remove ICRNL/INLCR/IGNCR below.) # However, this breaks IPython and maybe other applications, # because they bind ControlJ (\n) for handling the Enter key. # When this is removed, replace Enter=ControlJ by # Enter=ControlM in keys.py. if c == '\r': c = '\n' self._input_parser.send(c)
def prefix_meta(event): """ Metafy the next character typed. This is for keyboards without a meta key. Sometimes people also want to bind other keys to Meta, e.g. 'jj':: registry.add_key_binding('j', 'j', filter=ViInsertMode())(prefix_meta) """ event.cli.input_processor.feed(KeyPress(Keys.Escape))
def test_previous_key_sequence(processor, handlers): """ test whether we receive the correct previous_key_sequence. """ events = [] def handler(event): events.append(event) # Build registry. registry = Registry() registry.add_binding('a', 'a')(handler) registry.add_binding('b', 'b')(handler) processor = InputProcessor(registry, lambda: None) # Create processor and feed keys. processor.feed(KeyPress('a', 'a')) processor.feed(KeyPress('a', 'a')) processor.feed(KeyPress('b', 'b')) processor.feed(KeyPress('b', 'b')) processor.process_keys() # Test. assert len(events) == 2 assert len(events[0].key_sequence) == 2 assert events[0].key_sequence[0].key == 'a' assert events[0].key_sequence[0].data == 'a' assert events[0].key_sequence[1].key == 'a' assert events[0].key_sequence[1].data == 'a' assert events[0].previous_key_sequence == [] assert len(events[1].key_sequence) == 2 assert events[1].key_sequence[0].key == 'b' assert events[1].key_sequence[0].data == 'b' assert events[1].key_sequence[1].key == 'b' assert events[1].key_sequence[1].data == 'b' assert len(events[1].previous_key_sequence) == 2 assert events[1].previous_key_sequence[0].key == 'a' assert events[1].previous_key_sequence[0].data == 'a' assert events[1].previous_key_sequence[1].key == 'a' assert events[1].previous_key_sequence[1].data == 'a'
def _call_handler(self, key, insert_text): """ Callback to handler. """ if isinstance(key, tuple): for k in key: self._call_handler(k, insert_text) else: if key == Keys.BracketedPaste: self._in_bracketed_paste = True self._paste_buffer = '' else: self.feed_key_callback(KeyPress(key, insert_text))
def read(self): """ Return a list of `KeyPress` instances. It won't return anything when there was nothing to read. (This function doesn't block.) http://msdn.microsoft.com/en-us/library/windows/desktop/ms684961(v=vs.85).aspx """ max_count = 2048 # Max events to read at the same time. read = DWORD(0) arrtype = INPUT_RECORD * max_count input_records = arrtype() # Get next batch of input event. windll.kernel32.ReadConsoleInputW(self.handle, pointer(input_records), max_count, pointer(read)) # First, get all the keys from the input buffer, in order to determine # whether we should consider this a paste event or not. all_keys = list(self._get_keys(read, input_records)) if self.recognize_paste and self._is_paste(all_keys): gen = iter(all_keys) for k in gen: # Pasting: if the current key consists of text or \n, turn it # into a BracketedPaste. data = [] while k and (isinstance(k.key, six.text_type) or k.key == Keys.ControlJ): data.append(k.data) try: k = next(gen) except StopIteration: k = None if data: yield KeyPress(Keys.BracketedPaste, ''.join(data)) if k is not None: yield k else: for k in all_keys: yield k
def _handle_mouse(self, ev): """ Handle mouse events. Return a list of KeyPress instances. """ FROM_LEFT_1ST_BUTTON_PRESSED = 0x1 result = [] # Check event type. if ev.ButtonState == FROM_LEFT_1ST_BUTTON_PRESSED: # On a key press, generate both the mouse down and up event. for event_type in [MouseEventType.MOUSE_DOWN, MouseEventType.MOUSE_UP]: data = ';'.join([ event_type, str(ev.MousePosition.X), str(ev.MousePosition.Y) ]) result.append(KeyPress(Keys.WindowsMouseEvent, data)) return result
def test_feed_several(self): # First an unknown key first. self.processor.feed_key(KeyPress(Keys.ControlQ, '')) self.assertEqual(self.handlers.called, []) # Followed by a know key sequence. self.processor.feed_key(KeyPress(Keys.ControlX, '')) self.processor.feed_key(KeyPress(Keys.ControlC, '')) self.assertEqual(self.handlers.called, ['controlx_controlc']) # Followed by another unknown sequence. self.processor.feed_key(KeyPress(Keys.ControlR, '')) self.processor.feed_key(KeyPress(Keys.ControlS, '')) # Followed again by a know key sequence. self.processor.feed_key(KeyPress(Keys.ControlD, '')) self.assertEqual(self.handlers.called, ['controlx_controlc', 'control_d'])
def test_feed_several(processor, handlers): # First an unknown key first. processor.feed(KeyPress(Keys.ControlQ, '')) processor.process_keys() assert handlers.called == [] # Followed by a know key sequence. processor.feed(KeyPress(Keys.ControlX, '')) processor.feed(KeyPress(Keys.ControlC, '')) processor.process_keys() assert handlers.called == ['controlx_controlc'] # Followed by another unknown sequence. processor.feed(KeyPress(Keys.ControlR, '')) processor.feed(KeyPress(Keys.ControlS, '')) # Followed again by a know key sequence. processor.feed(KeyPress(Keys.ControlD, '')) processor.process_keys() assert handlers.called == ['controlx_controlc', 'control_d']
def test_on_feed_key_ctrlc_aborts(self, shell): with pytest.raises(click.Abort): shell.on_feed_key(KeyPress(Keys.ControlC))
def test_on_feed_key_escape_aborts(self, shell): with pytest.raises(click.Abort): shell.on_feed_key(KeyPress(Keys.Escape))
def test_assert_on_feed_key_with_speed(self, make_shell): shell = make_shell(commands=["import math", "1 + 1"], speed=2) assert shell.current_command_key == "im" shell.on_feed_key(KeyPress("x")) assert shell.current_command_key == "po"
def test_on_feed_key_goes_to_next_command_after_enter(self, shell): assert shell.current_command_key == "i" for _ in range(len("import math")): shell.on_feed_key(KeyPress("x")) shell.on_feed_key(KeyPress(Keys.Enter)) assert shell.current_command == "1 + 1"
def test_on_feed_key_backspace_with_speed(self, make_shell): shell = make_shell(commands=["1+1"], speed=2) shell.on_feed_key(KeyPress("x")) assert shell.current_command_key == "1" shell.on_feed_key(KeyPress(Keys.Backspace)) assert shell.current_command_key == "+1"
def test_F2(self): # orig_paginate = self.haxor.paginate_comments self.processor.feed(KeyPress(Keys.F2, u'')) self.processor.process_keys()
def test_feed_simple(processor, handlers): processor.feed(KeyPress(Keys.ControlX, '\x18')) processor.feed(KeyPress(Keys.ControlC, '\x03')) processor.process_keys() assert handlers.called == ['controlx_controlc']
def test_F10(self): with self.assertRaises(EOFError): self.processor.feed(KeyPress(Keys.F10, u'')) self.processor.process_keys()
def test_control_square_closed_any(processor, handlers): processor.feed(KeyPress(Keys.ControlSquareClose, '')) processor.feed(KeyPress('C', 'C')) processor.process_keys() assert handlers.called == ['control_square_close_any']
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 = ev.uChar.AsciiChar if u_char == '\x00': if ev.VirtualKeyCode in self.keycodes: result = KeyPress(self.keycodes[ev.VirtualKeyCode], '') else: if ascii_char in self.mappings: 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. if result: meta_pressed = ev.ControlKeyState & self.LEFT_ALT_PRESSED or \ ev.ControlKeyState & self.RIGHT_ALT_PRESSED if meta_pressed: return [KeyPress(Keys.Escape, ''), result] else: return [result] else: return []
def test_feed_simple(self): self.processor.feed_key(KeyPress(Keys.ControlX, '\x18')) self.processor.feed_key(KeyPress(Keys.ControlC, '\x03')) self.assertEqual(self.handlers.called, ['controlx_controlc'])
def _(event): " Map 'jj' to Escape. " event.cli.input_processor.feed(KeyPress(Keys.Escape))
def test_control_square_closed_any(self): self.processor.feed_key(KeyPress(Keys.ControlSquareClose, '')) self.processor.feed_key(KeyPress('C', 'C')) self.assertEqual(self.handlers.called, ['control_square_close_any'])
def test_on_feed_key(self, shell): assert shell.current_command_key == "i" key_press = KeyPress("x") shell.on_feed_key(key_press) assert shell.current_command_key == "m"
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 = ev.uChar.AsciiChar if u_char == '\x00': if ev.VirtualKeyCode in self.keycodes: result = KeyPress(self.keycodes[ev.VirtualKeyCode], '') else: if ascii_char in self.mappings: 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 []