3 * Copyright (c) 2002 Steve Slaven, All Rights Reserved.
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU General Public License as
7 * published by the Free Software Foundation; either version 2 of
8 * the License, or (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
22 /* Generates an X event, like keypress/mouseclick/move/etc
23 like a little man in your computer. :) */
26 #define X_H /* make sure we aren't using symbols from X.h */
27 #include <X11/XCB/xcb.h>
28 #include <X11/XCB/xcb_keysyms.h>
29 #include <X11/XCB/xtest.h>
34 /*#include "debug.h"*/
37 #define IS_CMD( x, y ) strncmp( x, y, strlen( y ) ) == 0
39 /* NOTE: demo only supports US keyboards, but could also support German; */
40 /* see original configure.in */
44 /* TODO: this is normally defined in configure.in */
45 #define VERSION "0.97"
47 #define XK_Shift_L 0xffe1 /* Left shift */
49 XCBKeySymbols *syms = NULL;
51 BYTE thing_to_keycode( XCBConnection *c, char *thing ) {
55 #if 0 /* There is no XCB equivalent to XStringToKeysym */
56 ks = XStringToKeysym( thing );
58 fprintf( stderr, "Unable to resolve keysym for '%s'\n", thing );
59 return( thing_to_keycode( c, "space" ) );
62 /* For now, assume thing[0] == Latin-1 keysym */
63 ks.id = (BYTE)thing[0];
66 kc = XCBKeySymbolsGetKeycode( syms, ks );
68 dmsg( 1, "String '%s' maps to keysym '%d'\n", thing, ks );
69 dmsg( 1, "String '%s' maps to keycode '%d'\n", thing, kc );
74 /* XCBTestFakeInput(type,detail,time,window,x,y,device) */
77 fake_input(XCBConnection *c, BYTE type, BYTE detail)
79 XCBWINDOW none = { XCBNone };
81 XCBTestFakeInput( c, type, detail, 0, none, 0, 0, 0 );
85 fake_motion(XCBConnection *c, BOOL relative, CARD16 x, CARD16 y)
87 XCBWINDOW window = { XCBNone };
90 window = XCBSetupRootsIter(XCBGetSetup(c)).data->root;
92 XCBTestFakeInput( c, XCBMotionNotify, relative, 0, window, x, y, 0 );
95 void send_key( XCBConnection *c, char *thing ) {
96 static XCBKEYSYM shift = { XK_Shift_L };
97 BYTE code, wrap_code = 0;
99 dmsg( 1, "Sending key '%s'\n", thing );
103 /* Catch some common problem characters (thanks Martin Pirker) */
104 for( probidx = 0; problems[ probidx ] != NULL; probidx += 3 ) {
105 if( strcmp( thing, problems[ probidx ] ) == 0 ) {
106 /*wrap_key = problems[ probidx + 1 ]; */
107 if (problems[ probidx + 1 ] != NULL) {
108 wrap_code = XCBKeySymbolsGetKeycode( syms, shift ).id;
110 thing = problems[ probidx + 2 ];
115 /* no XStringToKeysym support: do by hand */
116 /*const char *low = "`1234567890-=[]\\;',./";*/
117 const char *cap = "~!@#$%^&*()_+{}|:\"<>?";
119 if (thing[0] >= 'A' && thing[0] <= 'Z')
120 wrap_code = XCBKeySymbolsGetKeycode( syms, shift ).id;
121 else if (strchr(cap, thing[0]) != NULL)
122 wrap_code = XCBKeySymbolsGetKeycode( syms, shift ).id;
124 code = thing_to_keycode( c, thing );
127 fake_input( c, XCBKeyPress, wrap_code );
129 fake_input( c, XCBKeyPress, code );
130 fake_input( c, XCBKeyRelease, code );
133 fake_input( c, XCBKeyRelease, wrap_code );
136 void mouse_click( XCBConnection *c, int button ) {
137 dmsg( 1, "Clicking mouse button %d\n", button );
138 fake_input( c, XCBButtonPress, button );
139 fake_input( c, XCBButtonRelease, button );
142 void mouse_move( XCBConnection *c, int x, int y ) {
143 dmsg( 1, "Moving mouse to %c,%d\n", x, y );
144 fake_motion( c, 0, x, y );
147 void mouse_rel_move( XCBConnection *c, int x, int y ) {
148 dmsg( 1, "Moving mouse relatively by %c,%d\n", x, y );
149 fake_motion( c, 1, x, y );
152 void process_command( XCBConnection *c, const char *cmd ) {
153 /* Process a command */
158 if( IS_CMD( cmd, "mouseclick " ) ) {
159 sscanf( cmd, "mouseclick %d", &tmpx );
160 tmpx = tmpx<1 ? 1 : (tmpx>5 ? 5 : tmpx);
161 mouse_click( c, tmpx );
162 }else if( IS_CMD( cmd, "key " ) ) {
163 strncpy( str, &cmd[ 4 ], 128 );
165 }else if( IS_CMD( cmd, "keydown " ) ) {
166 strncpy( str, &cmd[ 8 ], 128 );
167 fake_input( c, XCBKeyPress, thing_to_keycode( c, str ) );
168 }else if( IS_CMD( cmd, "keyup " ) ) {
169 strncpy( str, &cmd[ 6 ], 128 );
170 fake_input( c, XCBKeyRelease, thing_to_keycode( c, str ) );
171 }else if( IS_CMD( cmd, "mousemove " ) ) {
172 sscanf( cmd, "mousemove %d %d", &tmpx, &tmpy );
173 mouse_move( c, tmpx, tmpy );
174 }else if( IS_CMD( cmd, "mousermove " ) ) {
175 sscanf( cmd, "mousermove %d %d", &tmpx, &tmpy );
176 mouse_rel_move( c, tmpx, tmpy );
177 }else if( IS_CMD( cmd, "sleep " ) ) {
178 sscanf( cmd, "sleep %d", &tmpx );
179 dmsg( 1, "sleep %d\n", tmpx );
181 }else if( IS_CMD( cmd, "usleep " ) ) {
182 sscanf( cmd, "usleep %d", &tmpx );
183 dmsg( 1, "usleep %d\n", tmpx );
185 }else if( IS_CMD( cmd, "mousedown " ) ) {
186 sscanf( cmd, "mousedown %d", &tmpx );
187 tmpx = tmpx<1 ? 1 : (tmpx>5 ? 5 : tmpx);
188 fake_input( c, XCBButtonPress, tmpx );
189 }else if( IS_CMD( cmd, "mouseup " ) ) {
190 sscanf( cmd, "mouseup %d", &tmpx );
191 tmpx = tmpx<1 ? 1 : (tmpx>5 ? 5 : tmpx);
192 fake_input( c, XCBButtonRelease, tmpx );
193 }else if( IS_CMD( cmd, "str " ) ) {
195 while( cmd[ 0 ] != 0 ) {
200 /* in the absence of XStringToKeysym, allow sending hex syms directly */
201 }else if( IS_CMD( cmd, "sym " ) ) {
204 sscanf( str, "sym %x", &sym.id );
205 code = XCBKeySymbolsGetKeycode( syms, sym );
206 fake_input( c, XCBKeyPress, code.id );
207 fake_input( c, XCBKeyRelease, code.id );
208 }else if( IS_CMD( cmd, "symdown " ) ) {
210 sscanf( str, "symdown %x", &sym.id );
211 fake_input( c, XCBKeyPress, XCBKeySymbolsGetKeycode( syms, sym ).id );
212 }else if( IS_CMD( cmd, "symup " ) ) {
214 sscanf( str, "symup %x", &sym.id );
215 fake_input( c, XCBKeyRelease, XCBKeySymbolsGetKeycode( syms, sym ).id );
217 fprintf( stderr, "Unknown command '%s'\n", cmd );
223 int main( int argc, char *argv[] ) {
224 XCBConnection *c = NULL;
225 int cnt; /*, tmp_i; */
226 char *buf, *display = NULL;
229 while( ( opt = getopt( argc, argv, "hx:" ) ) != EOF ) { /* "hd:x: */
232 printf( "xte v" VERSION "\n"
233 "Generates fake input using the XTest extension, more reliable than xse\n"
234 "Author: Steve Slaven - http://hoopajoo.net\n"
235 "Ported to XCB: Ian Osgood\n"
236 "Current keyboard map: " KBDMAP "\n"
238 "usage: %s [-h] [-x display] [arg ..]\n"
241 " -x send commands to remote X server. Note that some commands\n"
242 " may not work correctly unless the display is on the console,\n"
243 " e.g. the display is currently controlled by the keyboard and\n"
244 " mouse and not in the background. This seems to be a limitation\n"
245 " of the XTest extension.\n"
246 " arg args instructing the little man on what to do (see below)\n"
247 " if no args are passec, commands are read from stdin separated\n"
248 " by newlines, to allow a batch mode\n"
251 " key k Press and release key k\n"
252 " keydown k Press key k down\n"
253 " keyup k Release key k\n"
254 " str string Do a bunch of key X events for each char in string\n"
255 " mouseclick i Click mouse button i\n"
256 " mousemove x y Move mouse to screen position x,y\n"
257 " mousermove x y Move mouse relative from current location by x,y\n"
258 " mousedown i Press mouse button i down\n"
259 " mouseup i Release mouse button i\n"
260 " sleep x Sleep x seconds\n"
261 " usleep x uSleep x microseconds\n"
263 "Some useful keys (case sensitive)\n"
286 "Sample, drag from 100,100 to 200,200 using mouse1:\n"
287 " xte 'mousemove 100 100' 'mousedown 1' 'mousemove 200 200' 'mouseup 1'\n"
294 sscanf( optarg, "%d", &tmp_i );
295 dmsg( 2, "Debug set to %d\n", tmp_i );
296 debug_level( tmp_i );
304 fprintf( stderr, "Unknown option '%c'\n", optopt );
308 fprintf( stderr, "Unhandled option '%c'\n", opt );
313 c = XCBConnect( display, NULL );
315 fprintf( stderr, "Unable to open display '%s'\n", display == NULL ? "default" : display );
319 /* do XTest init and version check (need 2.1) */
320 /* XCBTestInit( c ); required? none of the other extension demos do this */
322 XCBTestGetVersionCookie cookie = XCBTestGetVersion( c, 2, 1 );
324 XCBGenericError *e = NULL;
325 XCBTestGetVersionRep *xtest_reply = XCBTestGetVersionReply ( c, cookie, &e );
327 fprintf( stderr, "XTest version %u.%u\n",
328 (unsigned int)xtest_reply->major_version,
329 (unsigned int)xtest_reply->minor_version );
333 fprintf( stderr, "XTest version error: %d", (int)e->error_code );
338 /* prep for keysym-->keycode conversion */
339 syms = XCBKeySymbolsAlloc( c );
341 if( argc - optind >= 1 ) {
343 for( cnt = optind; cnt < argc; cnt++ ) {
344 process_command( c, argv[ cnt ] );
348 buf = (char *)malloc( 128 );
349 while( fgets( buf, 128, stdin ) ) {
350 buf[ strlen( buf ) - 1 ] = 0; /* Chop \n */
351 process_command( c, buf );
355 XCBKeySymbolsFree( syms );