2 # Copyright (c) 2011 The Chromium Authors. All rights reserved.
3 # Use of this source code is governed by a BSD-style license that can be
4 # found in the LICENSE file.
6 """SiteCompare module for simulating mouse input.
8 This module contains functions that can be used to simulate a user
9 navigating using a pointing device. This includes mouse movement,
10 clicking with any button, and dragging.
13 import time
# for sleep
15 import win32api
# for mouse_event
16 import win32con
# Windows constants
17 import win32gui
# for window functions
20 def ScreenToMouse(pt
):
21 """Convert a value in screen coordinates to mouse coordinates.
23 Mouse coordinates are specified as a percentage of screen dimensions,
24 normalized to 16 bits. 0 represents the far left/top of the screen,
25 65535 represents the far right/bottom. This function assumes that
26 the size of the screen is fixed at module load time and does not change
29 pt: the point of the coords to convert
35 # Initialize the screen dimensions on first execution. Note that this
36 # function assumes that the screen dimensions do not change during run.
37 if not ScreenToMouse
._SCREEN
_DIMENSIONS
:
38 desktop
= win32gui
.GetClientRect(win32gui
.GetDesktopWindow())
39 ScreenToMouse
._SCREEN
_DIMENSIONS
= (desktop
[2], desktop
[3])
41 return ((65535 * pt
[0]) / ScreenToMouse
._SCREEN
_DIMENSIONS
[0],
42 (65535 * pt
[1]) / ScreenToMouse
._SCREEN
_DIMENSIONS
[1])
44 ScreenToMouse
._SCREEN
_DIMENSIONS
= None
47 def PressButton(down
, button
='left'):
48 """Simulate a mouse button press or release at the current mouse location.
51 down: whether the button is pressed or released
52 button: which button is pressed
58 # Put the mouse_event flags in a convenient dictionary by button
60 'left': (win32con
.MOUSEEVENTF_LEFTUP
, win32con
.MOUSEEVENTF_LEFTDOWN
),
61 'middle': (win32con
.MOUSEEVENTF_MIDDLEUP
, win32con
.MOUSEEVENTF_MIDDLEDOWN
),
62 'right': (win32con
.MOUSEEVENTF_RIGHTUP
, win32con
.MOUSEEVENTF_RIGHTDOWN
)
66 win32api
.mouse_event(flags
[button
][down
], 0, 0)
69 def ClickButton(button
='left', click_time
=0):
70 """Press and release a mouse button at the current mouse location.
73 button: which button to click
74 click_time: duration between press and release
79 PressButton(True, button
)
80 time
.sleep(click_time
)
81 PressButton(False, button
)
84 def DoubleClickButton(button
='left', click_time
=0, time_between_clicks
=0):
85 """Double-click a mouse button at the current mouse location.
88 button: which button to click
89 click_time: duration between press and release
90 time_between_clicks: time to pause between clicks
95 ClickButton(button
, click_time
)
96 time
.sleep(time_between_clicks
)
97 ClickButton(button
, click_time
)
100 def MoveToLocation(pos
, duration
=0, tick
=0.01):
101 """Move the mouse cursor to a specified location, taking the specified time.
104 pos: position (in screen coordinates) to move to
105 duration: amount of time the move should take
106 tick: amount of time between successive moves of the mouse
111 # calculate the number of moves to reach the destination
112 num_steps
= (duration
/tick
)+1
114 # get the current and final mouse position in mouse coords
115 current_location
= ScreenToMouse(win32gui
.GetCursorPos())
116 end_location
= ScreenToMouse(pos
)
118 # Calculate the step size
119 step_size
= ((end_location
[0]-current_location
[0])/num_steps
,
120 (end_location
[1]-current_location
[1])/num_steps
)
123 while step
< num_steps
:
124 # Move the mouse one step
125 current_location
= (current_location
[0]+step_size
[0],
126 current_location
[1]+step_size
[1])
128 # Coerce the coords to int to avoid a warning from pywin32
129 win32api
.mouse_event(
130 win32con
.MOUSEEVENTF_MOVE|win32con
.MOUSEEVENTF_ABSOLUTE
,
131 int(current_location
[0]), int(current_location
[1]))
137 def ClickAtLocation(pos
, button
='left', click_time
=0):
138 """Simulate a mouse click in a particular location, in screen coordinates.
141 pos: position in screen coordinates (x,y)
142 button: which button to click
143 click_time: duration of the click
149 ClickButton(button
, click_time
)
152 def ClickInWindow(hwnd
, offset
=None, button
='left', click_time
=0):
153 """Simulate a user mouse click in the center of a window.
156 hwnd: handle of the window to click in
157 offset: where to click, defaults to dead center
158 button: which button to click
159 click_time: duration of the click
165 rect
= win32gui
.GetClientRect(hwnd
)
166 if offset
is None: offset
= (rect
[2]/2, rect
[3]/2)
168 # get the screen coordinates of the window's center
169 pos
= win32gui
.ClientToScreen(hwnd
, offset
)
171 ClickAtLocation(pos
, button
, click_time
)
174 def DoubleClickInWindow(
175 hwnd
, offset
=None, button
='left', click_time
=0, time_between_clicks
=0.1):
176 """Simulate a user mouse double click in the center of a window.
179 hwnd: handle of the window to click in
180 offset: where to click, defaults to dead center
181 button: which button to click
182 click_time: duration of the clicks
183 time_between_clicks: length of time to pause between clicks
188 ClickInWindow(hwnd
, offset
, button
, click_time
)
189 time
.sleep(time_between_clicks
)
190 ClickInWindow(hwnd
, offset
, button
, click_time
)
194 # We're being invoked rather than imported. Let's do some tests
196 screen_size
= win32gui
.GetClientRect(win32gui
.GetDesktopWindow())
197 screen_size
= (screen_size
[2], screen_size
[3])
199 # move the mouse (instantly) to the upper right corner
200 MoveToLocation((screen_size
[0], 0))
202 # move the mouse (over five seconds) to the lower left corner
203 MoveToLocation((0, screen_size
[1]), 5)
205 # click the left mouse button. This will open up the Start menu
206 # if the taskbar is at the bottom
210 # wait a bit, then click the right button to open the context menu
214 # move the mouse away and then click the left button to dismiss the
216 MoveToLocation((screen_size
[0]/2, screen_size
[1]/2), 3)
217 MoveToLocation((0, 0), 3)
221 if __name__
== "__main__":