diff options
Diffstat (limited to 'tools/site_compare/drivers/win32/mouse.py')
-rw-r--r-- | tools/site_compare/drivers/win32/mouse.py | 243 |
1 files changed, 243 insertions, 0 deletions
diff --git a/tools/site_compare/drivers/win32/mouse.py b/tools/site_compare/drivers/win32/mouse.py new file mode 100644 index 0000000..9475f2d --- /dev/null +++ b/tools/site_compare/drivers/win32/mouse.py @@ -0,0 +1,243 @@ +#!/usr/bin/python2.4 +# Copyright 2008, Google Inc. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are +# met: +# +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above +# copyright notice, this list of conditions and the following disclaimer +# in the documentation and/or other materials provided with the +# distribution. +# * Neither the name of Google Inc. nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +"""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) + +if __name__ == "__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() +
\ No newline at end of file |