| #!/usr/bin/env python |
| # Copyright (c) 2011 The Chromium Authors. All rights reserved. |
| # Use of this source code is governed by a BSD-style license that can be |
| # found in the LICENSE file. |
| |
| """SiteCompare module for simulating mouse input. |
| |
| This module contains functions that can be used to simulate a user |
| navigating using a pointing device. This includes mouse movement, |
| clicking with any button, and dragging. |
| """ |
| |
| import time # for sleep |
| |
| import win32api # for mouse_event |
| import win32con # Windows constants |
| import win32gui # for window functions |
| |
| |
| def ScreenToMouse(pt): |
| """Convert a value in screen coordinates to mouse coordinates. |
| |
| Mouse coordinates are specified as a percentage of screen dimensions, |
| normalized to 16 bits. 0 represents the far left/top of the screen, |
| 65535 represents the far right/bottom. This function assumes that |
| the size of the screen is fixed at module load time and does not change |
| |
| Args: |
| pt: the point of the coords to convert |
| |
| Returns: |
| the converted point |
| """ |
| |
| # Initialize the screen dimensions on first execution. Note that this |
| # function assumes that the screen dimensions do not change during run. |
| if not ScreenToMouse._SCREEN_DIMENSIONS: |
| desktop = win32gui.GetClientRect(win32gui.GetDesktopWindow()) |
| ScreenToMouse._SCREEN_DIMENSIONS = (desktop[2], desktop[3]) |
| |
| return ((65535 * pt[0]) / ScreenToMouse._SCREEN_DIMENSIONS[0], |
| (65535 * pt[1]) / ScreenToMouse._SCREEN_DIMENSIONS[1]) |
| |
| ScreenToMouse._SCREEN_DIMENSIONS = None |
| |
| |
| def PressButton(down, button='left'): |
| """Simulate a mouse button press or release at the current mouse location. |
| |
| Args: |
| down: whether the button is pressed or released |
| button: which button is pressed |
| |
| Returns: |
| None |
| """ |
| |
| # Put the mouse_event flags in a convenient dictionary by button |
| flags = { |
| 'left': (win32con.MOUSEEVENTF_LEFTUP, win32con.MOUSEEVENTF_LEFTDOWN), |
| 'middle': (win32con.MOUSEEVENTF_MIDDLEUP, win32con.MOUSEEVENTF_MIDDLEDOWN), |
| 'right': (win32con.MOUSEEVENTF_RIGHTUP, win32con.MOUSEEVENTF_RIGHTDOWN) |
| } |
| |
| # hit the button |
| win32api.mouse_event(flags[button][down], 0, 0) |
| |
| |
| def ClickButton(button='left', click_time=0): |
| """Press and release a mouse button at the current mouse location. |
| |
| Args: |
| button: which button to click |
| click_time: duration between press and release |
| |
| Returns: |
| None |
| """ |
| PressButton(True, button) |
| time.sleep(click_time) |
| PressButton(False, button) |
| |
| |
| def DoubleClickButton(button='left', click_time=0, time_between_clicks=0): |
| """Double-click a mouse button at the current mouse location. |
| |
| Args: |
| button: which button to click |
| click_time: duration between press and release |
| time_between_clicks: time to pause between clicks |
| |
| Returns: |
| None |
| """ |
| ClickButton(button, click_time) |
| time.sleep(time_between_clicks) |
| ClickButton(button, click_time) |
| |
| |
| def MoveToLocation(pos, duration=0, tick=0.01): |
| """Move the mouse cursor to a specified location, taking the specified time. |
| |
| Args: |
| pos: position (in screen coordinates) to move to |
| duration: amount of time the move should take |
| tick: amount of time between successive moves of the mouse |
| |
| Returns: |
| None |
| """ |
| # calculate the number of moves to reach the destination |
| num_steps = (duration/tick)+1 |
| |
| # get the current and final mouse position in mouse coords |
| current_location = ScreenToMouse(win32gui.GetCursorPos()) |
| end_location = ScreenToMouse(pos) |
| |
| # Calculate the step size |
| step_size = ((end_location[0]-current_location[0])/num_steps, |
| (end_location[1]-current_location[1])/num_steps) |
| step = 0 |
| |
| while step < num_steps: |
| # Move the mouse one step |
| current_location = (current_location[0]+step_size[0], |
| current_location[1]+step_size[1]) |
| |
| # Coerce the coords to int to avoid a warning from pywin32 |
| win32api.mouse_event( |
| win32con.MOUSEEVENTF_MOVE|win32con.MOUSEEVENTF_ABSOLUTE, |
| int(current_location[0]), int(current_location[1])) |
| |
| step += 1 |
| time.sleep(tick) |
| |
| |
| def ClickAtLocation(pos, button='left', click_time=0): |
| """Simulate a mouse click in a particular location, in screen coordinates. |
| |
| Args: |
| pos: position in screen coordinates (x,y) |
| button: which button to click |
| click_time: duration of the click |
| |
| Returns: |
| None |
| """ |
| MoveToLocation(pos) |
| ClickButton(button, click_time) |
| |
| |
| def ClickInWindow(hwnd, offset=None, button='left', click_time=0): |
| """Simulate a user mouse click in the center of a window. |
| |
| Args: |
| hwnd: handle of the window to click in |
| offset: where to click, defaults to dead center |
| button: which button to click |
| click_time: duration of the click |
| |
| Returns: |
| Nothing |
| """ |
| |
| rect = win32gui.GetClientRect(hwnd) |
| if offset is None: offset = (rect[2]/2, rect[3]/2) |
| |
| # get the screen coordinates of the window's center |
| pos = win32gui.ClientToScreen(hwnd, offset) |
| |
| ClickAtLocation(pos, button, click_time) |
| |
| |
| def DoubleClickInWindow( |
| hwnd, offset=None, button='left', click_time=0, time_between_clicks=0.1): |
| """Simulate a user mouse double click in the center of a window. |
| |
| Args: |
| hwnd: handle of the window to click in |
| offset: where to click, defaults to dead center |
| button: which button to click |
| click_time: duration of the clicks |
| time_between_clicks: length of time to pause between clicks |
| |
| Returns: |
| Nothing |
| """ |
| ClickInWindow(hwnd, offset, button, click_time) |
| time.sleep(time_between_clicks) |
| ClickInWindow(hwnd, offset, button, click_time) |
| |
| |
| def main(): |
| # We're being invoked rather than imported. Let's do some tests |
| |
| screen_size = win32gui.GetClientRect(win32gui.GetDesktopWindow()) |
| screen_size = (screen_size[2], screen_size[3]) |
| |
| # move the mouse (instantly) to the upper right corner |
| MoveToLocation((screen_size[0], 0)) |
| |
| # move the mouse (over five seconds) to the lower left corner |
| MoveToLocation((0, screen_size[1]), 5) |
| |
| # click the left mouse button. This will open up the Start menu |
| # if the taskbar is at the bottom |
| |
| ClickButton() |
| |
| # wait a bit, then click the right button to open the context menu |
| time.sleep(3) |
| ClickButton('right') |
| |
| # move the mouse away and then click the left button to dismiss the |
| # context menu |
| MoveToLocation((screen_size[0]/2, screen_size[1]/2), 3) |
| MoveToLocation((0, 0), 3) |
| ClickButton() |
| |
| |
| if __name__ == "__main__": |
| sys.exit(main()) |