1
# -*- Mode: Python; coding: utf-8; indent-tabs-mode: nil; tab-width: 4 -*-
2
# Copyright 2010 Canonical
5
# This program is free software: you can redistribute it and/or modify it
6
# under the terms of the GNU General Public License version 3, as published
7
# by the Free Software Foundation.
9
# This script is designed to run unity in a test drive manner. It will drive
10
# X and test the GL calls that Unity makes, so that we can easily find out if
11
# we are triggering graphics driver/X bugs.
14
A collection of emulators for X11 - namely keyboards and mice. In the future we may
15
also need other devices.
19
from time import sleep
23
from Xlib.display import Display
24
from Xlib.ext.xtest import fake_input
26
class Keyboard(object):
27
'''Wrapper around xlib to make faking keyboard input possible'''
28
_lame_hardcoded_keycodes = {
37
_special_X_keysyms = {
40
'\n' : "Return", # for some reason this needs to be cr, not lf
78
self._display = Display()
80
def press(self, keys):
82
Send key press events for every key in the 'keys' string.
84
self.__perform_on_keys(keys, X.KeyPress)
87
def release(self, keys):
89
Send key release events for every key in the 'keys' string.
91
self.__perform_on_keys(keys, X.KeyRelease)
94
def press_and_release(self, keys):
96
Send key press events for every key in the 'keys' string, then send
97
key release events for every key in the 'keys' string.
99
This method is not appropriate for simulating a user typing a string
100
of text, since it presses all the keys, and then releases them all.
105
def type(self, keys):
107
Simulate a user typing the keys specified in 'keys'.
109
Each key will be pressed and released before the next key is processed. If
110
you need to simulate multiple keys being pressed at the same time, use the
111
'press_and_release' method above.
117
def __perform_on_keys(self, keys, event):
122
for index in range(len(keys)):
125
keycode = self._lame_hardcoded_keycodes[key]
128
elif index < len(keys) and key == '^' and keys[index+1] in self._lame_hardcoded_keycodes:
132
keycode, shift_mask = self.__char_to_keycode(key)
135
fake_input(self._display, event, 50)
137
fake_input(self._display, event, keycode)
140
def __get_keysym(self, key) :
141
keysym = XK.string_to_keysym(key)
143
# Unfortunately, although this works to get the correct keysym
144
# i.e. keysym for '#' is returned as "numbersign"
145
# the subsequent display.keysym_to_keycode("numbersign") is 0.
146
keysym = XK.string_to_keysym(self._special_X_keysyms[key])
149
def __is_shifted(self, key) :
152
if "~!@#$%^&*()_+{}|:\"<>?".find(key) >= 0 :
156
def __char_to_keycode(self, key) :
157
keysym = self.__get_keysym(key)
158
keycode = self._display.keysym_to_keycode(keysym)
160
print "Sorry, can't map", key
162
if (self.__is_shifted(key)) :
163
shift_mask = X.ShiftMask
167
return keycode, shift_mask
170
'''Wrapper around xlib to make moving the mouse easier'''
173
self._display = Display()
175
def press(self, button=1):
176
'''Press mouse button at current mouse location'''
177
fake_input(self._display, X.ButtonPress, button)
180
def release(self, button=1):
181
'''Releases mouse button at current mouse location'''
182
fake_input(self._display, X.ButtonRelease, button)
185
def click(self, button=1):
186
'''Click mouse at current location'''
191
def move(self, x, y, animate=True):
192
'''Moves mouse to location (x, y)'''
193
def perform_move(x, y):
194
fake_input(self._display, X.MotionNotify, x=x, y=y)
201
dest_x, dest_y = x, y
202
curr_x, curr_y = self.position()
204
# calculate a path from our current position to our destination
205
dy = float(curr_y - dest_y)
206
dx = float(curr_x - dest_x)
207
slope = dy/dx if dx > 0 else 0
208
yint = curr_y - (slope * curr_x)
209
xscale = 1 if dest_x > curr_x else -1
211
while (int(curr_x) != dest_x):
213
curr_y = int(slope * curr_x + yint) if curr_y > 0 else dest_y
215
perform_move(curr_x, curr_y)
217
if (curr_y != dest_y):
218
yscale = 1 if dest_y > curr_y else -1
219
while (curr_y != dest_y):
221
perform_move(curr_x, curr_y)
224
'''Returns the current position of the mouse pointer'''
225
coord = self._display.screen().root.query_pointer()._data
226
x, y = coord["root_x"], coord["root_y"]
230
self.move(16, 13, animate=False)
232
self.move(800, 500, animate=False)