189
193
raise TypeError("'keys' argument must be a string.")
190
194
logger.debug("Typing text %r", string)
191
195
for key in string:
192
# Don't call press or release here, as they translate keys to keysyms.
196
# Don't call press or release here, as they translate keys to
193
198
self.__perform_on_key(key, X.KeyPress)
195
200
self.__perform_on_key(key, X.KeyRelease)
199
204
def on_test_end(cls, test_instance):
200
205
"""Generate KeyRelease events for any un-released keys.
202
.. important:: Ensure you call this at the end of any test to release any
203
keys that were pressed and not released.
207
.. important:: Ensure you call this at the end of any test to release
208
any keys that were pressed and not released.
206
211
global _PRESSED_KEYS
207
212
for keycode in _PRESSED_KEYS:
208
logger.warning("Releasing key %r as part of cleanup call.", keycode)
214
"Releasing key %r as part of cleanup call.", keycode)
209
215
fake_input(get_display(), X.KeyRelease, keycode)
210
216
_PRESSED_KEYS = []
229
235
if keycode in _PRESSED_KEYS:
230
236
_PRESSED_KEYS.remove(keycode)
232
logger.warning("Generating release event for keycode %d that was not pressed.", keycode)
239
"Generating release event for keycode %d that was not "
234
242
fake_input(get_display(), event, keycode)
235
243
get_display().sync()
246
254
def __is_shifted(self, key):
247
255
return len(key) == 1 and ord(key) in self.shifted_keys and key != '<'
249
def __char_to_keycode(self, key) :
257
def __char_to_keycode(self, key):
250
258
keysym = self.__get_keysym(key)
251
259
keycode = get_display().keysym_to_keycode(keysym)
253
261
logger.warning("Sorry, can't map '%s'", key)
255
if (self.__is_shifted(key)) :
263
if (self.__is_shifted(key)):
256
264
shift_mask = X.ShiftMask
260
268
return keycode, shift_mask
262
270
def __translate_keys(self, key_string):
263
271
if len(key_string) > 1:
264
return [self._keysym_translations.get(k, k) for k in key_string.split('+')]
272
return [self._keysym_translations.get(k, k)
273
for k in key_string.split('+')]
266
275
# workaround that lets us press_and_release '+' by itself.
267
276
return [self._keysym_translations.get(key_string, key_string)]
298
307
if button in _PRESSED_MOUSE_BUTTONS:
299
308
_PRESSED_MOUSE_BUTTONS.remove(button)
301
logger.warning("Generating button release event or button %d that was not pressed.", button)
311
"Generating button release event or button %d that was not "
302
313
fake_input(get_display(), X.ButtonRelease, button)
303
314
get_display().sync()
315
326
parameters unless they need a specific rate of movement.
318
logger.debug("Moving mouse to position %d,%d %s animation.", x, y,
319
"with" if animate else "without")
321
329
def perform_move(x, y, sync):
322
fake_input(get_display(), X.MotionNotify, sync, X.CurrentTime, X.NONE, x=x, y=y)
323
338
get_display().sync()
324
339
sleep(time_between_events)
341
dest_x, dest_y = int(x), int(y)
343
"Moving mouse to position %d,%d %s animation.", dest_x, dest_y,
344
"with" if animate else "without")
327
perform_move(x, y, False)
347
perform_move(dest_x, dest_y, False)
330
dest_x, dest_y = x, y
331
350
curr_x, curr_y = self.position()
332
coordinate_valid = is_point_on_any_screen((x,y))
351
coordinate_valid = is_point_on_any_screen((dest_x, dest_y))
333
352
if x < -1000 or y < -1000:
334
raise ValueError("Invalid mouse coordinates: %d, %d" % (x, y))
354
"Invalid mouse coordinates: %d, %d" % (dest_x, dest_y))
336
356
while curr_x != dest_x or curr_y != dest_y:
337
357
dx = abs(dest_x - curr_x)
373
x,y,w,h = object_proxy.globalRect
393
x, y, w, h = object_proxy.globalRect
374
394
logger.debug("Moving to object's globalRect coordinates.")
375
395
self.move(x+w/2, y+h/2)
377
397
except AttributeError:
379
399
except (TypeError, ValueError):
380
raise ValueError("Object '%r' has globalRect attribute, but it is not of the correct type" % object_proxy)
401
"Object '%r' has globalRect attribute, but it is not of the "
402
"correct type" % object_proxy)
383
x,y = object_proxy.center_x, object_proxy.center_y
405
x, y = object_proxy.center_x, object_proxy.center_y
384
406
logger.debug("Moving to object's center_x, center_y coordinates.")
387
409
except AttributeError:
389
411
except (TypeError, ValueError):
390
raise ValueError("Object '%r' has center_x, center_y attributes, but they are not of the correct type" % object_proxy)
413
"Object '%r' has center_x, center_y attributes, but they are "
414
"not of the correct type" % object_proxy)
393
x,y,w,h = object_proxy.x, object_proxy.y, object_proxy.w, object_proxy.h
394
logger.debug("Moving to object's center point calculated from x,y,w,h attributes.")
395
self.move(x+w/2,y+h/2)
418
object_proxy.x, object_proxy.y, object_proxy.w, object_proxy.h)
420
"Moving to object's center point calculated from x,y,w,h "
422
self.move(x+w/2, y+h/2)
397
424
except AttributeError:
398
raise ValueError("Object '%r' does not have any recognised position attributes" % object_proxy)
426
"Object '%r' does not have any recognised position "
427
"attributes" % object_proxy)
399
428
except (TypeError, ValueError):
400
raise ValueError("Object '%r' has x,y attribute, but they are not of the correct type" % object_proxy)
430
"Object '%r' has x,y attribute, but they are not of the "
431
"correct type" % object_proxy)
402
433
def position(self):
413
444
def drag(self, x1, y1, x2, y2):
414
"""Performs a press, move and release
415
This is to keep a common API between Mouse and Finger as long as possible"""
445
"""Performs a press, move and release.
447
This is to keep a common API between Mouse and Finger as long as
416
451
self.move(x1, y1)
418
453
self.move(x2, y2)
457
def on_test_end(cls, test_instance):
423
458
"""Put mouse in a known safe state."""
424
459
global _PRESSED_MOUSE_BUTTONS
425
460
for btn in _PRESSED_MOUSE_BUTTONS: