|
1 // Description: Testing utility for emulating pointer/key input events in X. |
|
2 |
|
3 #include <QApplication> |
|
4 #include <Xlib.h> |
|
5 #include <new> |
|
6 |
|
7 #include "os.h" |
|
8 |
|
9 namespace Java { |
|
10 namespace XlibUtils { |
|
11 typedef enum |
|
12 { |
|
13 NO_ERROR = 0, |
|
14 NO_DISPLAY = 1, |
|
15 NO_FOCUSWINDOW = 2, |
|
16 NO_ROOTWINDOW = 3, |
|
17 NO_MEMORY = 4, |
|
18 SENDEVENT_ERR = 5 |
|
19 } XlibUtilsErr; |
|
20 } |
|
21 } |
|
22 |
|
23 JNIEXPORT jint JNICALL Java_com_nokia_mj_impl_uitestutils_XlibUtils_XSendKeyToFocusWindow |
|
24 ( JNIEnv*, jclass, jint aKeycode, jint aModifiers, jint aPressOrRelease ) |
|
25 { |
|
26 int keycode = static_cast<int>( aKeycode ); |
|
27 int modifiers = static_cast<int>( aModifiers ); |
|
28 bool press = ( aPressOrRelease == 0 ? true : false ); |
|
29 jint retVal = 0; |
|
30 Display* display = NULL; |
|
31 |
|
32 try |
|
33 { |
|
34 display = ::XOpenDisplay( NULL ); |
|
35 if( !display ) |
|
36 { |
|
37 throw Java::XlibUtils::NO_DISPLAY; |
|
38 } |
|
39 |
|
40 Window focusWindow = 0; |
|
41 int focusState = 0; |
|
42 ::XGetInputFocus( display, &focusWindow, &focusState ); |
|
43 |
|
44 Window rootWindow = ::XDefaultRootWindow( display ); |
|
45 |
|
46 if( focusWindow == None ) |
|
47 { |
|
48 throw Java::XlibUtils::NO_FOCUSWINDOW; |
|
49 } |
|
50 else if( rootWindow == None ) |
|
51 { |
|
52 throw Java::XlibUtils::NO_ROOTWINDOW; |
|
53 } |
|
54 else |
|
55 { |
|
56 XKeyEvent* event = new(std::nothrow) XKeyEvent(); |
|
57 if( !event ) |
|
58 { |
|
59 throw Java::XlibUtils::NO_MEMORY; |
|
60 } |
|
61 event->type = ( press ? KeyPress : KeyRelease ); |
|
62 event->serial = None; |
|
63 event->send_event = false; |
|
64 event->display = display; |
|
65 event->window = focusWindow; |
|
66 event->root = rootWindow; |
|
67 event->subwindow = None; |
|
68 event->time = CurrentTime; |
|
69 event->x = 0; |
|
70 event->y = 0; |
|
71 event->x_root = 0; |
|
72 event->y_root = 0; |
|
73 event->state = modifiers; |
|
74 event->keycode = keycode; |
|
75 event->same_screen = True; |
|
76 |
|
77 if( ::XSendEvent( display, |
|
78 event->window, |
|
79 false, |
|
80 0, |
|
81 reinterpret_cast<XEvent*>(event)) == 0 ) |
|
82 { |
|
83 throw Java::XlibUtils::SENDEVENT_ERR; |
|
84 } |
|
85 ::XFlush( display ); |
|
86 } |
|
87 } |
|
88 catch(Java::XlibUtils::XlibUtilsErr e) |
|
89 { |
|
90 retVal = static_cast<jint>( e ); |
|
91 } |
|
92 if( retVal != Java::XlibUtils::NO_DISPLAY ) |
|
93 { |
|
94 ::XCloseDisplay( display ); |
|
95 } |
|
96 return retVal; |
|
97 } |
|
98 |
|
99 JNIEXPORT jint JNICALL Java_com_nokia_mj_impl_uitestutils_XlibUtils_XKeysymToKeycode |
|
100 (JNIEnv*, jclass, jint aKeysym) |
|
101 { |
|
102 int keysym = static_cast<int>(aKeysym); |
|
103 KeyCode keycode = 0; |
|
104 |
|
105 Display* display = ::XOpenDisplay( NULL ); |
|
106 if( display ) |
|
107 { |
|
108 keycode = ::XKeysymToKeycode( display, keysym ); |
|
109 ::XCloseDisplay( display ); |
|
110 } |
|
111 return keycode; |
|
112 } |
|
113 |
|
114 JNIEXPORT jint JNICALL Java_com_nokia_mj_impl_uitestutils_XlibUtils_XSendPointerEvent |
|
115 (JNIEnv*, jclass, jint aX, jint aY, jint aButton, jint aPressOrRelease) |
|
116 { |
|
117 bool press = ( aPressOrRelease == 0 ? true : false ); |
|
118 int x = static_cast<int>(aX); |
|
119 int y = static_cast<int>(aY); |
|
120 jint retVal = 0; |
|
121 Display* display = NULL; |
|
122 int buttonNMask = 1 << (7 + aButton); // Button1Mask, Button2Mask, ..., Button5Mask |
|
123 |
|
124 try |
|
125 { |
|
126 display = ::XOpenDisplay( NULL ); |
|
127 if( !display ) |
|
128 { |
|
129 throw Java::XlibUtils::NO_DISPLAY; |
|
130 } |
|
131 |
|
132 Window rootWindow = ::XDefaultRootWindow( display ); |
|
133 if( rootWindow == None ) |
|
134 { |
|
135 throw Java::XlibUtils::NO_ROOTWINDOW; |
|
136 } |
|
137 |
|
138 // Release events don't seem to work if we do pointer warp. |
|
139 // Pointer is warped only for press events. Releases use the |
|
140 // current cursor position to determine the window where to |
|
141 // send the event to. |
|
142 if( press ) |
|
143 { |
|
144 ::XWarpPointer( display, None, rootWindow, 0, 0, 0, 0, x, y ); |
|
145 } |
|
146 |
|
147 XButtonEvent* event = new(std::nothrow) XButtonEvent(); |
|
148 if( !event ) |
|
149 { |
|
150 throw Java::XlibUtils::NO_MEMORY; |
|
151 } |
|
152 |
|
153 event->type = ( press ? ButtonPress : ButtonRelease ); |
|
154 event->serial = None; |
|
155 event->send_event = False; |
|
156 event->display = display; |
|
157 // event->window = ; |
|
158 // event->root = ; |
|
159 // event->subWindow = ; |
|
160 event->time = CurrentTime; |
|
161 // event->x = ; |
|
162 // event->y = ; |
|
163 // event->x_root = ; |
|
164 // event->y_root = ; |
|
165 // event->state = ; |
|
166 event->button = aButton; |
|
167 event->same_screen = True; |
|
168 |
|
169 ::XQueryPointer( display, |
|
170 rootWindow, |
|
171 &event->root, |
|
172 &event->window, |
|
173 &event->x_root, |
|
174 &event->y_root, |
|
175 &event->x, |
|
176 &event->y, |
|
177 &event->state ); |
|
178 |
|
179 event->subwindow = event->window; |
|
180 event->state = buttonNMask; |
|
181 |
|
182 // Find the top window at cursor position. |
|
183 while( event->subwindow ) |
|
184 { |
|
185 event->window = event->subwindow; |
|
186 |
|
187 ::XQueryPointer( display, |
|
188 event->window, |
|
189 &event->root, |
|
190 &event->subwindow, |
|
191 &event->x_root, |
|
192 &event->y_root, |
|
193 &event->x, |
|
194 &event->y, |
|
195 &event->state ); |
|
196 } |
|
197 |
|
198 // For release event just adjust the coordinates in the event. |
|
199 // Cursor is actually never moved to the release event location. |
|
200 if( !press ) |
|
201 { |
|
202 int delta_x = x - event->x_root; |
|
203 int delta_y = y - event->y_root; |
|
204 |
|
205 event->x += delta_x; |
|
206 event->y += delta_y; |
|
207 event->x_root += delta_x; |
|
208 event->y_root += delta_y; |
|
209 } |
|
210 |
|
211 // Double click interval is set to zero in QApplication to avoid getting |
|
212 // unwanted double-click events. It's common that test cases just keep |
|
213 // clicking in the middle of a widget and tests execute in rapidly. |
|
214 QApplication* app = qApp; |
|
215 if(app) app->setDoubleClickInterval( 0 ); |
|
216 |
|
217 event->time = CurrentTime; |
|
218 event->state = (press ? buttonNMask : 0); |
|
219 |
|
220 // Unless the window is a tooltip or other window which will be ignored |
|
221 // by the window manager, set input focus to make window activate like |
|
222 // clicking with real mouse. |
|
223 XWindowAttributes attr; |
|
224 ::memset(&attr, 0, sizeof(attr)); |
|
225 ::XGetWindowAttributes(display, event->window, &attr); |
|
226 if(attr.override_redirect == False) |
|
227 { |
|
228 ::XSetInputFocus(display, event->window, RevertToNone, CurrentTime); |
|
229 } |
|
230 |
|
231 if( ::XSendEvent( display, |
|
232 PointerWindow, |
|
233 True, |
|
234 0, |
|
235 reinterpret_cast<XEvent*>(event) ) == 0) |
|
236 { |
|
237 throw Java::XlibUtils::SENDEVENT_ERR; |
|
238 } |
|
239 |
|
240 ::XFlush( display ); |
|
241 } |
|
242 catch(Java::XlibUtils::XlibUtilsErr e) |
|
243 { |
|
244 retVal = static_cast<jint>( e ); |
|
245 } |
|
246 |
|
247 if( retVal != Java::XlibUtils::NO_DISPLAY ) |
|
248 { |
|
249 ::XCloseDisplay( display ); |
|
250 } |
|
251 |
|
252 return retVal; |
|
253 } |
|
254 |
|
255 |
|
256 JNIEXPORT jint JNICALL Java_com_nokia_mj_impl_uitestutils_XlibUtils_XSendPointerMoveEvent |
|
257 (JNIEnv *, jclass, jint aX, jint aY, jint aButton) |
|
258 { |
|
259 int x = static_cast<int>(aX); |
|
260 int y = static_cast<int>(aY); |
|
261 jint retVal = 0; |
|
262 Display* display = NULL; |
|
263 int buttonNMask = 1 << (7 + aButton); // Button1Mask, Button2Mask, ..., Button5Mask |
|
264 |
|
265 try |
|
266 { |
|
267 display = ::XOpenDisplay( NULL ); |
|
268 if( !display ) |
|
269 { |
|
270 throw Java::XlibUtils::NO_DISPLAY; |
|
271 } |
|
272 |
|
273 Window rootWindow = ::XDefaultRootWindow( display ); |
|
274 if( rootWindow == None ) |
|
275 { |
|
276 throw Java::XlibUtils::NO_ROOTWINDOW; |
|
277 } |
|
278 |
|
279 XMotionEvent* event = new(std::nothrow) XMotionEvent(); |
|
280 if( !event ) |
|
281 { |
|
282 throw Java::XlibUtils::NO_MEMORY; |
|
283 } |
|
284 |
|
285 event->type = MotionNotify; |
|
286 event->serial = None; |
|
287 event->send_event = False; |
|
288 event->display = display; |
|
289 // event->window = ; |
|
290 // event->root = ; |
|
291 // event->subWindow = ; |
|
292 event->time = CurrentTime; |
|
293 // event->x = ; |
|
294 // event->y = ; |
|
295 // event->x_root = ; |
|
296 // event->y_root = ; |
|
297 // event->state = ; |
|
298 event->is_hint = NotifyNormal; |
|
299 event->same_screen = True; |
|
300 |
|
301 ::XQueryPointer( display, |
|
302 rootWindow, |
|
303 &event->root, |
|
304 &event->window, |
|
305 &event->x_root, |
|
306 &event->y_root, |
|
307 &event->x, |
|
308 &event->y, |
|
309 &event->state ); |
|
310 |
|
311 event->subwindow = event->window; |
|
312 event->state = buttonNMask; |
|
313 |
|
314 // Find the top window at cursor position. |
|
315 while( event->subwindow ) |
|
316 { |
|
317 event->window = event->subwindow; |
|
318 |
|
319 ::XQueryPointer( display, |
|
320 event->window, |
|
321 &event->root, |
|
322 &event->subwindow, |
|
323 &event->x_root, |
|
324 &event->y_root, |
|
325 &event->x, |
|
326 &event->y, |
|
327 &event->state ); |
|
328 } |
|
329 |
|
330 // For motion event just adjust the coordinates in the event. |
|
331 // Cursor is actually never moved to the motion event location. |
|
332 int delta_x = x - event->x_root; |
|
333 int delta_y = y - event->y_root; |
|
334 |
|
335 event->x += delta_x; |
|
336 event->y += delta_y; |
|
337 event->x_root += delta_x; |
|
338 event->y_root += delta_y; |
|
339 |
|
340 event->state = buttonNMask; |
|
341 |
|
342 if( ::XSendEvent( display, |
|
343 PointerWindow, |
|
344 True, |
|
345 0, |
|
346 reinterpret_cast<XEvent*>(event) ) == 0) |
|
347 { |
|
348 throw Java::XlibUtils::SENDEVENT_ERR; |
|
349 } |
|
350 |
|
351 ::XFlush( display ); |
|
352 } |
|
353 catch(Java::XlibUtils::XlibUtilsErr e) |
|
354 { |
|
355 retVal = static_cast<jint>( e ); |
|
356 } |
|
357 |
|
358 if( retVal != Java::XlibUtils::NO_DISPLAY ) |
|
359 { |
|
360 ::XCloseDisplay( display ); |
|
361 } |
|
362 |
|
363 return retVal; |
|
364 } |
|
365 |