class TestMouse(TestCase): def setUp(self) -> None: self.ahk = AHK() self.original_position = self.ahk.mouse_position self.notepad_process = None def tearDown(self) -> None: self.ahk.mouse_move(*self.original_position) if self.notepad_process is not None: self.notepad_process.terminate() def test_mouse_move(self): x, y = self.ahk.mouse_position self.ahk.mouse_move(10, 10, relative=True) assert self.ahk.mouse_position == (x + 10, y + 10) def test_mouse_move_absolute(self): original_x, original_y = self.original_position new_x = original_x + 10 new_y = original_y + 10 self.ahk.mouse_move(new_x, new_y) assert self.ahk.mouse_position == (new_x, new_y) def test_mouse_move_callable_speed(self): x, y = self.ahk.mouse_position self.ahk.mouse_move(10, 10, relative=True, speed=lambda: 10) assert self.ahk.mouse_position == (x + 10, y + 10) def test_mouse_drag(self): self.notepad_process = subprocess.Popen('notepad') time.sleep(0.5) notepad = self.ahk.find_window(title=b'Untitled - Notepad') win_width = notepad.width win_height = notepad.height print(*notepad.position) self.ahk.mouse_move(*notepad.position) time.sleep(1) # moving the mouse to the window position puts it in a position where it can be resized by dragging ↖ ↘ # after this, we expect the window height/width to shrink by 10px self.ahk.mouse_drag(10, 10, relative=True) assert notepad.width == win_width - 10 assert notepad.height == win_height - 10
class WindowControl: def __init__(self, window_title: str) -> "WindowControl": self.autohotkey = AHK() self.window = self.autohotkey.find_window(title=window_title.encode("utf-8")) if not self.window: settings.LOGGER.error(f"Window {window_title} not found") def activate(self) -> None: """ Activate window i.e. bring it to front. """ if self.window: self.window.activate() def send_click( self, click_position_x_percentage_from_origin: Union[int, float], click_position_y_percentage_from_origin: Union[int, float], ) -> bool: """ :param click_position_x_percentage_from_origin: X position as percentage from window origin that should be clicked :param click_position_y_percentage_from_origin: Y position as percentage from window origin that should be clicked :return: True if click was sent to the window """ if self.window: self.activate() if ( click_position_x_percentage_from_origin is not None and click_position_y_percentage_from_origin is not None ): click_x, click_y = self._click_window_position( click_position_x_percentage_from_origin, click_position_y_percentage_from_origin, ) settings.LOGGER.warning( f"Clicked {click_x}, {click_y} of window {self.window.title}" ) return True return False def send_drag( self, from_position_x_percentage_from_origin: Union[int, float], from_position_y_percentage_from_origin: Union[int, float], to_position_x_percentage_from_origin: Union[int, float], to_position_y_percentage_from_origin: Union[int, float], ) -> bool: """ Drag mouse over window. :param from_position_x_percentage_from_origin: X position as percentage from window origin from where the mouse drag should start :param from_position_y_percentage_from_origin: Y position as percentage from window origin from where the mouse drag should start :param from_position_x_percentage_from_origin: X position as percentage from window origin to where the mouse drag should end :param from_position_y_percentage_from_origin: Y position as percentage from window origin to where the mouse drag should end :return: True if mouse drag was sent to the window """ if self.window: self.activate() if ( from_position_x_percentage_from_origin is not None and from_position_y_percentage_from_origin is not None and to_position_x_percentage_from_origin is not None and to_position_y_percentage_from_origin is not None ): from_x, from_y, to_x, to_y = self._drag_mouse_inside_window( from_position_x_percentage_from_origin, from_position_y_percentage_from_origin, to_position_x_percentage_from_origin, to_position_y_percentage_from_origin, ) settings.LOGGER.warning( f"Dragged mouse from {from_x}, {from_y} to {to_x}, {to_y} inside window {self.window.title}" ) return True return False def send_key( self, command: str, click_position_x_percentage_from_origin: int, click_position_y_percentage_from_origin: int, ) -> bool: """ Send given command (keys) :param command: keys to send :param click_position_x_percentage_from_origin: X position as percentage from window origin that should be clicked :param click_position_y_percentage_from_origin: Y position as percentage from window origin that should be clicked :return: True if keys were sent to the window """ if self.window: self.activate() if ( click_position_x_percentage_from_origin is not None and click_position_y_percentage_from_origin is not None ): self._click_window_position( click_position_x_percentage_from_origin, click_position_y_percentage_from_origin, ) self._send_key(command) settings.LOGGER.warning(f"Sent {command} to window {self.window.title}") return True return False def _calculate_click_position( self, x: int, y: int, width: int, height: int, click_position_x_percentage_from_origin: Union[int, float] = 0, click_position_y_percentage_from_origin: Union[int, float] = 0, ) -> Tuple[Union[int, float], Union[int, float]]: """ Calculate a screen position (x, y) that is going to be clicked. :param x: X position of window :param y: Y position of window :param width: Window width :param height: Window height :param click_position_x_percentage_from_origin: X position as percentage from window XY origin that should be clicked, defaults to 0 :param click_position_y_percentage_from_origin: Y position as percentage from window XY origin that should be clicked, defaults to 0 :return: x, y position in screen to click as tuple :raises ValueError: x or y position can't be converted to float or is nan """ return ( float_or_raise(x + width * click_position_x_percentage_from_origin / 100), float_or_raise( y + (height - height * click_position_y_percentage_from_origin / 100) ), ) def _click_window_position( self, click_position_x_percentage_from_origin: Union[int, float] = 0, click_position_y_percentage_from_origin: Union[int, float] = 0, ) -> Tuple[Union[int, float], Union[int, float]]: """ Click a position (x, y from origin) in the window. :param click_position_x_percentage_from_origin: X position as percentage from window XY origin that should be clicked, defaults to 0 :param click_position_y_percentage_from_origin: Y position as percentage from window XY origin that should be clicked, defaults to 0 :return: x, y position in screen that was clicked as tuple """ click_x, click_y = self._calculate_click_position( *self.window.rect, click_position_x_percentage_from_origin, click_position_y_percentage_from_origin, ) settings.LOGGER.warning( f"Moving mouse and clicking to {click_x}, {click_y} inside window {self.window.title}" ) self.autohotkey.click(click_x, click_y, blocking=True) return (click_x, click_y) def _drag_mouse_inside_window( self, from_position_x_percentage_from_origin: Union[int, float], from_position_y_percentage_from_origin: Union[int, float], to_position_x_percentage_from_origin: Union[int, float], to_position_y_percentage_from_origin: Union[int, float], ) -> Tuple[ Union[int, float], Union[int, float], Union[int, float], Union[int, float] ]: """ Drag mouse over window. :param from_position_x_percentage_from_origin: X position as percentage from window origin from where the mouse drag should start :param from_position_y_percentage_from_origin: Y position as percentage from window origin from where the mouse drag should start :param from_position_x_percentage_from_origin: X position as percentage from window origin to where the mouse drag should end :param from_position_y_percentage_from_origin: Y position as percentage from window origin to where the mouse drag should end :return: drag position from x, y to x, y as tuple """ rect = self.window.rect from_x, from_y = self._calculate_click_position( *rect, from_position_x_percentage_from_origin, from_position_y_percentage_from_origin, ) to_x, to_y = self._calculate_click_position( *rect, to_position_x_percentage_from_origin, to_position_y_percentage_from_origin, ) settings.LOGGER.warning( f"Dragging mouse from {from_x}, {from_y} to {to_x}, {to_y} inside window {self.window.title}" ) self.autohotkey.mouse_drag( to_x, to_y, from_position=(from_x, from_y), blocking=True ) return (from_x, from_y, to_x, to_y) def _send_key(self, command) -> None: """ Send given keys to window. """ self.window.send(command, blocking=True)
def inventory(foo, argu1): ahk = AHK() if "active" not in target: if "tog" not in foo: if "a1" in foo: op = 2586, 589 elif "a2" in foo: op = 2664, 593 elif "a3" in foo: op = 2734, 591 elif "a4" in foo: op = 2806, 583 elif "a5" in foo: op = 2898, 583 elif "a6" in foo: op = 2950, 577 elif "a7" in foo: op = 3030, 580 elif "a8" in foo: op = 3171, 586 elif "a9" in foo: op = 3171, 586 elif "b1" in foo: op = 2591, 646 elif "b2" in foo: op = 2664, 645 elif "b3" in foo: op = 2735, 647 elif "b4" in foo: op = 2809, 645 elif "b5" in foo: op = 2880, 646 elif "b6" in foo: op = 2955, 646 elif "b7" in foo: op = 3024, 646 elif "b8" in foo: op = 3099, 647 elif "b9" in foo: op = 3168, 646 elif "c1" in foo: op = 2591, 719 elif "c2" in foo: op = 2663, 717 elif "c3" in foo: op = 2737, 717 elif "c4" in foo: op = 2806, 717 elif "c5" in foo: op = 2881, 718 elif "c6" in foo: op = 2952, 717 elif "c7" in foo: op = 3025, 717 elif "c8" in foo: op = 3096, 720 elif "c9" in foo: op = 3169, 720 else: None if argu1 == "1": po = 1 if argu1 == "2": po = 2 if argu1 == "3": po = 3 if argu1 == "4": po = 4 if argu1 == "5": po = 5 if argu1 == "6": po = 6 if argu1 == "7": po = 7 if argu1 == "8": po = 8 if argu1 == "9": po = 9 ahk.key_press('e') ahk.mouse_move(2121, 241) ahk.mouse_drag(op) ahk.key_press(str(po)) ahk.key_press('e') else: ahk.key_press('e') target.append('active') print(target) else: if "active" in target: ahk.key_press('e') target.clear() print(target)