def _curses_screen_get_event(self, ): """ Check for an event without waiting. This monkey patch adds support for the mouse scroll """ import curses # Spin through notifications until we find something we want. key = 0 while key != -1: # Get the next key key = self.screen._screen.getch() if key == curses.KEY_RESIZE: # Handle screen resize self.screen._re_sized = True elif key == curses.KEY_MOUSE: # Handle a mouse event _, x, y, _, bstate = curses.getmouse() buttons = 0 # Some Linux modes only report clicks, so check for any # button down or click events. if (bstate & curses.BUTTON1_PRESSED != 0 or bstate & curses.BUTTON1_CLICKED != 0): buttons |= MouseEvent.LEFT_CLICK if (bstate & curses.BUTTON3_PRESSED != 0 or bstate & curses.BUTTON3_CLICKED != 0): buttons |= MouseEvent.RIGHT_CLICK if bstate & curses.BUTTON1_DOUBLE_CLICKED != 0: buttons |= MouseEvent.DOUBLE_CLICK if (bstate & curses.A_LOW != 0 or bstate & curses.A_LOW != 0): # scroll down buttons |= DOMMouseEvent.MOUSE_SCROLL_DOWN if (bstate & curses.BUTTON4_PRESSED != 0 or bstate & curses.BUTTON4_CLICKED != 0): # scroll up buttons |= DOMMouseEvent.MOUSE_SCROLL_UP return MouseEvent(x, y, buttons) elif key != -1: # Handle any byte streams first if self.screen._unicode_aware and key > 0: if key & 0xC0 == 0xC0: self.screen._bytes_to_return = struct.pack(b"B", key) self.screen._bytes_to_read = bin(key)[2:].index("0") - 1 continue elif self.screen._bytes_to_read > 0: self.screen._bytes_to_return += struct.pack(b"B", key) self.screen._bytes_to_read -= 1 if self.screen._bytes_to_read > 0: continue else: key = ord(self.screen._bytes_to_return.decode("utf-8")) # Handle a genuine key press. if key in self.screen._KEY_MAP: return KeyboardEvent(self.screen._KEY_MAP[key]) elif key != -1: return KeyboardEvent(key) return None
def my_get_event(self): """ Check for any event without waiting. """ # Look for a new event and consume it if there is one. key = 0 while key != -1: # Get the next key key = self._screen.getch() if key == curses.KEY_RESIZE: # Handle screen resize self._re_sized = True elif key == curses.KEY_MOUSE: # Translate into a MouseEvent object. _, x, y, _, bstate = curses.getmouse() buttons = 0 # Some Linux modes only report clicks, so check for any # button down or click events. if (bstate & curses.BUTTON1_PRESSED != 0 or bstate & curses.BUTTON1_CLICKED != 0): buttons = MouseEvent.LEFT_CLICK elif (bstate & curses.BUTTON3_PRESSED != 0 or bstate & curses.BUTTON3_CLICKED != 0): buttons = MouseEvent.RIGHT_CLICK elif bstate & curses.BUTTON1_DOUBLE_CLICKED != 0: buttons = MouseEvent.DOUBLE_CLICK buttons = (bstate if type(bstate) == int and buttons == 0 else buttons) buttons = 0 if buttons not in [0, 1, 2, 4] else buttons return MouseEvent(x, y, buttons) elif key != -1: # Handle any byte streams first logger.debug("Processing key: %x", key) if self._unicode_aware and key > 0: if key & 0xC0 == 0xC0: self._bytes_to_return = struct.pack(b"B", key) self._bytes_to_read = bin(key)[2:].index("0") - 1 logger.debug("Byte stream: %d bytes left", self._bytes_to_read) continue elif self._bytes_to_read > 0: self._bytes_to_return += struct.pack(b"B", key) self._bytes_to_read -= 1 if self._bytes_to_read > 0: continue else: key = ord(self._bytes_to_return.decode("utf-8")) # Handle a genuine key press. logger.debug("Returning key: %x", key) if key in self._KEY_MAP: return KeyboardEvent(self._KEY_MAP[key]) elif key != -1: return KeyboardEvent(key) # If we get here, we've fully processed the event queue and found # nothing interesting. return None
def test_events(self): """ Check event processing is queued correctly. """ # Check that the scene passes events through to the effects effect1 = MockEffect() effect2 = MockEffect() scene = Scene([effect1, effect2], duration=10) scene.process_event(MouseEvent(10, 5, 0)) self.assertTrue(effect1.event_called) self.assertTrue(effect2.event_called) # Check that the scene passes stops event processing when required effect1 = MockEffect() effect2 = MockEffect(swallow=True) scene = Scene([effect1, effect2], duration=10) scene.process_event(MouseEvent(10, 5, 0)) self.assertFalse(effect1.event_called) self.assertTrue(effect2.event_called)
def test_click_row(tmp_path, port, monkeypatch): with Aria2Server(tmp_path, port, session="2-dls-paused.txt") as server: interface = run_interface(monkeypatch, server.api, events=[ Event.pass_frame, MouseEvent(x=10, y=2, buttons=MouseEvent.LEFT_CLICK) ]) assert interface.focused == 1
def test_click_row(monkeypatch): with Aria2Server(port=7619, session=SESSIONS_DIR / "2-dl-in-queue.txt") as server: interface = run_interface(monkeypatch, server.api, events=[ Event.pass_frame, MouseEvent(x=10, y=2, buttons=MouseEvent.LEFT_CLICK) ]) assert interface.focused == 1
def test_mouse_event(self): """ Check Mouse event is consistent. """ x = 1 y = 2 buttons = MouseEvent.DOUBLE_CLICK event = MouseEvent(x, y, buttons) self.assertEqual(event.x, x) self.assertEqual(event.y, y) self.assertEqual(event.buttons, buttons) self.assertIn("({}, {})".format(x, y), str(event)) self.assertIn(str(buttons), str(event))
def test_mouse_event(tmp_path, port, monkeypatch): reverse = tui.Interface.reverse with Aria2Server(tmp_path, port, session="3-magnets.txt") as server: interface = run_interface( monkeypatch, server.api, events=[ MouseEvent(x=tui.Interface.x_offset, y=tui.Interface.y_offset, buttons=MouseEvent.LEFT_CLICK) ] * 2, ) assert interface.sort == 0 assert interface.reverse is not reverse
def test_empty_frame(self): """ Check empty Frames still work. """ screen = MagicMock(spec=Screen, colours=8, unicode_aware=False) canvas = Canvas(screen, 10, 40, 0, 0) scene = MagicMock(spec=Scene) form = TestFrame3(canvas) form.register_scene(scene) form.reset() # Check all keyboard events get swallowed self.assertIsNone(form.process_event(KeyboardEvent(ord("A")))) # Check Mouse events over the Frame are swallowed and others allowed # to bubble down the input stack. self.assertIsNone( form.process_event(MouseEvent(20, 5, MouseEvent.LEFT_CLICK))) self.assertIsNotNone( form.process_event(MouseEvent(5, 5, MouseEvent.LEFT_CLICK))) # Check form data is empty. form.save() self.assertEqual(form.data, {})
def test_click_out_bounds(server, monkeypatch): run_interface(monkeypatch, server.api, events=[ Event.pass_frame, MouseEvent(x=1000, y=0, buttons=MouseEvent.LEFT_CLICK) ]) with open( Path("tests") / "logs" / "test_interface" / "test_click_out_bounds.log") as log_file: lines = log_file.readlines() error_line = None for line in lines: if "ERROR" in line: error_line = line break assert error_line assert "clicked outside of boundaries" in error_line
def test_dynamic_path(self): """ Check a dynamic path works as expected. """ class TestPath(DynamicPath): def process_event(self, event): # Assume that we're always passing in a MouseEvent. self._x = event.x self._y = event.y # Initial path should start at specified location. path = TestPath(None, 0, 0) self.assertEqual(path.next_pos(), (0, 0)) self.assertFalse(path.is_finished()) # Process event should move location. path.process_event(MouseEvent(10, 5, 0)) self.assertEqual(path.next_pos(), (10, 5)) # Reset should return to original location. path.reset() self.assertEqual(path.next_pos(), (0, 0))
def process_mouse(form, values): """ Inject a set of mouse events. """ for x, y, buttons in values: form.process_event(MouseEvent(x, y, buttons))
def my_get_event(self): """ Check for any event without waiting. """ # Look for a new event and consume it if there is one. while len(self._stdin.PeekConsoleInput(1)) > 0: event = self._stdin.ReadConsoleInput(1)[0] if event.EventType == win32console.KEY_EVENT: # Pasting unicode text appears to just generate key-up # events (as if you had pressed the Alt keys plus the # keypad code for the character), but the rest of the # console input simply doesn't # work with key up events - e.g. misses keyboard repeats. # # We therefore allow any key press (i.e. KeyDown) event and # _any_ event that appears to have popped up from nowhere # as long as the Alt key is present. key_code = ord(event.Char) if (event.KeyDown or (key_code > 0 and key_code not in self._keys and event.VirtualKeyCode == win32con.VK_MENU)): # Record any keys that were pressed. if event.KeyDown: self._keys.add(key_code) # Translate keys into a KeyboardEvent object. if event.VirtualKeyCode in self._KEY_MAP: key_code = self._KEY_MAP[event.VirtualKeyCode] # Sadly, we are limited to Linux terminal input and so # can't return modifier states in a cross-platform way. # If the user decided not to be cross-platform, so be # it, otherwise map some standard bindings for extended # keys. if (self._map_all and event.VirtualKeyCode in self._EXTRA_KEY_MAP): key_code = self._EXTRA_KEY_MAP[event.VirtualKeyCode] else: if (event.VirtualKeyCode == win32con.VK_TAB and event.ControlKeyState & win32con.SHIFT_PRESSED): key_code = Screen.KEY_BACK_TAB # Don't return anything if we didn't have a valid # mapping. if key_code: return KeyboardEvent(key_code) else: # Tidy up any key that was previously pressed. At # start-up, we may be mid-key, so can't assume this must # always match up. if key_code in self._keys: self._keys.remove(key_code) elif event.EventType == win32console.MOUSE_EVENT: # Translate into a MouseEvent object. button = 0 print(event.ButtonState, end=" ") if event.EventFlags == 0: # Button pressed - translate it. if (event.ButtonState & win32con.FROM_LEFT_1ST_BUTTON_PRESSED != 0): button |= MouseEvent.LEFT_CLICK if (event.ButtonState & win32con.RIGHTMOST_BUTTON_PRESSED != 0): button |= MouseEvent.RIGHT_CLICK elif event.EventFlags & win32con.DOUBLE_CLICK != 0: button |= MouseEvent.DOUBLE_CLICK button = (event.ButtonState if type(event.ButtonState) == int and button == 0 else button) return MouseEvent(event.MousePosition.X, event.MousePosition.Y, button) # If we get here, we've fully processed the event queue and found # nothing interesting. return None