summaryrefslogtreecommitdiffstats
path: root/tools/site_compare/drivers/win32/mouse.py
blob: afdb2eaf4bdbe7869f990a7d339afc8b8c8cbf97 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
#!/usr/bin/python2.4
# Copyright (c) 2006-2008 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)

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()