[Xcb-commit] xcb-demo xcb-proto
Ian Osgood
iano at kemper.freedesktop.org
Mon Apr 24 14:17:01 PDT 2006
xcb-demo/app/xte/.gitignore | 2
xcb-demo/app/xte/Makefile | 6
xcb-demo/app/xte/xte.c | 359 +++++++++++++++++++++++++++++++++++++
xcb-proto/src/extensions/xtest.xml | 104 ++++++++++
4 files changed, 471 insertions(+)
New commits:
diff-tree c594a35cbd79d79856abca36f2da3c60d3005a35 (from 71cfc1e761815fe6f4e87c103df39a4d4363f729)
Author: Ian Osgood <iano at quirkster.com>
Date: Mon Apr 24 14:16:38 2006 -0700
Implement XTest extension and xte demo
diff --git a/xcb-demo/app/xte/.gitignore b/xcb-demo/app/xte/.gitignore
new file mode 100644
index 0000000..8bca2cc
--- /dev/null
+++ b/xcb-demo/app/xte/.gitignore
@@ -0,0 +1,2 @@
+xte
+!Makefile
diff --git a/xcb-demo/app/xte/Makefile b/xcb-demo/app/xte/Makefile
new file mode 100644
index 0000000..b602e80
--- /dev/null
+++ b/xcb-demo/app/xte/Makefile
@@ -0,0 +1,6 @@
+pkgs = xcb xcb-keysyms
+CFLAGS = `pkg-config --cflags $(pkgs)` -g -Wall -Wpointer-arith -Wstrict-prototypes
+LIBS = `pkg-config --libs $(pkgs)` -lXCBxtest
+
+xte: xte.c
+ $(CC) $(CFLAGS) xte.c $(LIBS) -o xte
diff --git a/xcb-demo/app/xte/xte.c b/xcb-demo/app/xte/xte.c
new file mode 100644
index 0000000..6dfbb5f
--- /dev/null
+++ b/xcb-demo/app/xte/xte.c
@@ -0,0 +1,359 @@
+/*
+ *
+ * Copyright (c) 2002 Steve Slaven, All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ *
+*/
+
+/* Generates an X event, like keypress/mouseclick/move/etc
+ like a little man in your computer. :) */
+
+#include <stdio.h>
+#define X_H /* make sure we aren't using symbols from X.h */
+#include <X11/XCB/xcb.h>
+#include <X11/XCB/xcb_keysyms.h>
+#include <X11/XCB/xtest.h>
+#include <unistd.h>
+#include <string.h>
+#include <stdlib.h>
+
+/*#include "debug.h"*/
+#define dmsg(a,b,...)
+
+#define IS_CMD( x, y ) strncmp( x, y, strlen( y ) ) == 0
+
+/* NOTE: demo only supports US keyboards, but could also support German; */
+/* see original configure.in */
+/*#include "kbd.h"*/
+#define KBDMAP "us"
+
+/* TODO: this is normally defined in configure.in */
+#define VERSION "0.97"
+
+#define XK_Shift_L 0xffe1 /* Left shift */
+
+XCBKeySymbols *syms = NULL;
+
+BYTE thing_to_keycode( XCBConnection *c, char *thing ) {
+ XCBKEYCODE kc;
+ XCBKEYSYM ks;
+
+#if 0 /* There is no XCB equivalent to XStringToKeysym */
+ ks = XStringToKeysym( thing );
+ if( ks == NoSymbol ){
+ fprintf( stderr, "Unable to resolve keysym for '%s'\n", thing );
+ return( thing_to_keycode( c, "space" ) );
+ }
+#else
+ /* For now, assume thing[0] == Latin-1 keysym */
+ ks.id = (BYTE)thing[0];
+#endif
+
+ kc = XCBKeySymbolsGetKeycode( syms, ks );
+
+ dmsg( 1, "String '%s' maps to keysym '%d'\n", thing, ks );
+ dmsg( 1, "String '%s' maps to keycode '%d'\n", thing, kc );
+
+ return( kc.id );
+}
+
+/* XCBTestFakeInput(type,detail,time,window,x,y,device) */
+
+static void
+fake_input(XCBConnection *c, BYTE type, BYTE detail)
+{
+ XCBWINDOW none = { XCBNone };
+
+ XCBTestFakeInput( c, type, detail, 0, none, 0, 0, 0 );
+}
+
+static void
+fake_motion(XCBConnection *c, BOOL relative, CARD16 x, CARD16 y)
+{
+ XCBWINDOW window = { XCBNone };
+
+ if (!relative) {
+ window = XCBConnSetupSuccessRepRootsIter(XCBGetSetup(c)).data->root;
+ }
+ XCBTestFakeInput( c, XCBMotionNotify, relative, 0, window, x, y, 0 );
+}
+
+void send_key( XCBConnection *c, char *thing ) {
+ static XCBKEYSYM shift = { XK_Shift_L };
+ BYTE code, wrap_code = 0;
+
+ dmsg( 1, "Sending key '%s'\n", thing );
+
+#if 0
+ int probidx;
+ /* Catch some common problem characters (thanks Martin Pirker) */
+ for( probidx = 0; problems[ probidx ] != NULL; probidx += 3 ) {
+ if( strcmp( thing, problems[ probidx ] ) == 0 ) {
+ /*wrap_key = problems[ probidx + 1 ]; */
+ if (problems[ probidx + 1 ] != NULL) {
+ wrap_code = XCBKeySymbolsGetKeycode( syms, shift ).id;
+ }
+ thing = problems[ probidx + 2 ];
+ break;
+ }
+ }
+#else
+ /* no XStringToKeysym support: do by hand */
+/*const char *low = "`1234567890-=[]\\;',./";*/
+ const char *cap = "~!@#$%^&*()_+{}|:\"<>?";
+
+ if (thing[0] >= 'A' && thing[0] <= 'Z')
+ wrap_code = XCBKeySymbolsGetKeycode( syms, shift ).id;
+ else if (strchr(cap, thing[0]) != NULL)
+ wrap_code = XCBKeySymbolsGetKeycode( syms, shift ).id;
+#endif
+ code = thing_to_keycode( c, thing );
+
+ if( wrap_code )
+ fake_input( c, XCBKeyPress, wrap_code );
+
+ fake_input( c, XCBKeyPress, code );
+ fake_input( c, XCBKeyRelease, code );
+
+ if( wrap_code )
+ fake_input( c, XCBKeyRelease, wrap_code );
+}
+
+void mouse_click( XCBConnection *c, int button ) {
+ dmsg( 1, "Clicking mouse button %d\n", button );
+ fake_input( c, XCBButtonPress, button );
+ fake_input( c, XCBButtonRelease, button );
+}
+
+void mouse_move( XCBConnection *c, int x, int y ) {
+ dmsg( 1, "Moving mouse to %c,%d\n", x, y );
+ fake_motion( c, 0, x, y );
+}
+
+void mouse_rel_move( XCBConnection *c, int x, int y ) {
+ dmsg( 1, "Moving mouse relatively by %c,%d\n", x, y );
+ fake_motion( c, 1, x, y );
+}
+
+void process_command( XCBConnection *c, const char *cmd ) {
+ /* Process a command */
+ int tmpx,tmpy;
+ char str[ 128 ];
+
+ bzero( str, 128 );
+ if( IS_CMD( cmd, "mouseclick " ) ) {
+ sscanf( cmd, "mouseclick %d", &tmpx );
+ tmpx = tmpx<1 ? 1 : (tmpx>5 ? 5 : tmpx);
+ mouse_click( c, tmpx );
+ }else if( IS_CMD( cmd, "key " ) ) {
+ strncpy( str, &cmd[ 4 ], 128 );
+ send_key( c, str );
+ }else if( IS_CMD( cmd, "keydown " ) ) {
+ strncpy( str, &cmd[ 8 ], 128 );
+ fake_input( c, XCBKeyPress, thing_to_keycode( c, str ) );
+ }else if( IS_CMD( cmd, "keyup " ) ) {
+ strncpy( str, &cmd[ 6 ], 128 );
+ fake_input( c, XCBKeyRelease, thing_to_keycode( c, str ) );
+ }else if( IS_CMD( cmd, "mousemove " ) ) {
+ sscanf( cmd, "mousemove %d %d", &tmpx, &tmpy );
+ mouse_move( c, tmpx, tmpy );
+ }else if( IS_CMD( cmd, "mousermove " ) ) {
+ sscanf( cmd, "mousermove %d %d", &tmpx, &tmpy );
+ mouse_rel_move( c, tmpx, tmpy );
+ }else if( IS_CMD( cmd, "sleep " ) ) {
+ sscanf( cmd, "sleep %d", &tmpx );
+ dmsg( 1, "sleep %d\n", tmpx );
+ sleep( tmpx );
+ }else if( IS_CMD( cmd, "usleep " ) ) {
+ sscanf( cmd, "usleep %d", &tmpx );
+ dmsg( 1, "usleep %d\n", tmpx );
+ usleep( tmpx );
+ }else if( IS_CMD( cmd, "mousedown " ) ) {
+ sscanf( cmd, "mousedown %d", &tmpx );
+ tmpx = tmpx<1 ? 1 : (tmpx>5 ? 5 : tmpx);
+ fake_input( c, XCBButtonPress, tmpx );
+ }else if( IS_CMD( cmd, "mouseup " ) ) {
+ sscanf( cmd, "mouseup %d", &tmpx );
+ tmpx = tmpx<1 ? 1 : (tmpx>5 ? 5 : tmpx);
+ fake_input( c, XCBButtonRelease, tmpx );
+ }else if( IS_CMD( cmd, "str " ) ) {
+ cmd += 4;
+ while( cmd[ 0 ] != 0 ) {
+ str[ 0 ] = cmd[ 0 ];
+ send_key( c, str );
+ cmd++;
+ }
+ /* in the absence of XStringToKeysym, allow sending hex syms directly */
+ }else if( IS_CMD( cmd, "sym " ) ) {
+ XCBKEYSYM sym;
+ XCBKEYCODE code;
+ sscanf( str, "sym %x", &sym.id );
+ code = XCBKeySymbolsGetKeycode( syms, sym );
+ fake_input( c, XCBKeyPress, code.id );
+ fake_input( c, XCBKeyRelease, code.id );
+ }else if( IS_CMD( cmd, "symdown " ) ) {
+ XCBKEYSYM sym;
+ sscanf( str, "symdown %x", &sym.id );
+ fake_input( c, XCBKeyPress, XCBKeySymbolsGetKeycode( syms, sym ).id );
+ }else if( IS_CMD( cmd, "symup " ) ) {
+ XCBKEYSYM sym;
+ sscanf( str, "symup %x", &sym.id );
+ fake_input( c, XCBKeyRelease, XCBKeySymbolsGetKeycode( syms, sym ).id );
+ }else{
+ fprintf( stderr, "Unknown command '%s'\n", cmd );
+ }
+
+ XCBFlush( c );
+}
+
+int main( int argc, char *argv[] ) {
+ XCBConnection *c = NULL;
+ int cnt; /*, tmp_i; */
+ char *buf, *display = NULL;
+ int opt;
+
+ while( ( opt = getopt( argc, argv, "hx:" ) ) != EOF ) { /* "hd:x: */
+ switch( opt ) {
+ case 'h':
+ printf( "xte v" VERSION "\n"
+ "Generates fake input using the XTest extension, more reliable than xse\n"
+ "Author: Steve Slaven - http://hoopajoo.net\n"
+ "Ported to XCB: Ian Osgood\n"
+ "Current keyboard map: " KBDMAP "\n"
+ "\n"
+ "usage: %s [-h] [-x display] [arg ..]\n"
+ "\n"
+ " -h this help\n"
+ " -x send commands to remote X server. Note that some commands\n"
+ " may not work correctly unless the display is on the console,\n"
+ " e.g. the display is currently controlled by the keyboard and\n"
+ " mouse and not in the background. This seems to be a limitation\n"
+ " of the XTest extension.\n"
+ " arg args instructing the little man on what to do (see below)\n"
+ " if no args are passec, commands are read from stdin separated\n"
+ " by newlines, to allow a batch mode\n"
+ "\n"
+ " Commands:\n"
+ " key k Press and release key k\n"
+ " keydown k Press key k down\n"
+ " keyup k Release key k\n"
+ " str string Do a bunch of key X events for each char in string\n"
+ " mouseclick i Click mouse button i\n"
+ " mousemove x y Move mouse to screen position x,y\n"
+ " mousermove x y Move mouse relative from current location by x,y\n"
+ " mousedown i Press mouse button i down\n"
+ " mouseup i Release mouse button i\n"
+ " sleep x Sleep x seconds\n"
+ " usleep x uSleep x microseconds\n"
+ "\n"
+ "Some useful keys (case sensitive)\n"
+ " Home\n"
+ " Left\n"
+ " Up\n"
+ " Right\n"
+ " Down\n"
+ " Page_Up\n"
+ " Page_Down\n"
+ " End\n"
+ " Return\n"
+ " Backspace\n"
+ " Tab\n"
+ " Escape\n"
+ " Delete\n"
+ " Shift_L\n"
+ " Shift_R\n"
+ " Control_L\n"
+ " Control_R\n"
+ " Meta_L\n"
+ " Meta_R\n"
+ " Alt_L\n"
+ " Alt_R\n"
+ "\n"
+ "Sample, drag from 100,100 to 200,200 using mouse1:\n"
+ " xte 'mousemove 100 100' 'mousedown 1' 'mousemove 200 200' 'mouseup 1'\n"
+ "\n"
+ , argv[ 0 ] );
+ exit( 0 );
+ break;
+#if 0
+ case 'd':
+ sscanf( optarg, "%d", &tmp_i );
+ dmsg( 2, "Debug set to %d\n", tmp_i );
+ debug_level( tmp_i );
+ break;
+#endif
+ case 'x':
+ display = optarg;
+ break;
+
+ case '?':
+ fprintf( stderr, "Unknown option '%c'\n", optopt );
+ break;
+
+ default:
+ fprintf( stderr, "Unhandled option '%c'\n", opt );
+ break;
+ }
+ }
+
+ c = XCBConnect( display, NULL );
+ if( c == NULL ) {
+ fprintf( stderr, "Unable to open display '%s'\n", display == NULL ? "default" : display );
+ exit( 1 );
+ }
+
+ /* do XTest init and version check (need 2.1) */
+ /* XCBTestInit( c ); required? none of the other extension demos do this */
+
+ XCBTestGetVersionCookie cookie = XCBTestGetVersion( c, 2, 1 );
+
+ XCBGenericError *e = NULL;
+ XCBTestGetVersionRep *xtest_reply = XCBTestGetVersionReply ( c, cookie, &e );
+ if (xtest_reply) {
+ fprintf( stderr, "XTest version %u.%u\n",
+ (unsigned int)xtest_reply->major_version,
+ (unsigned int)xtest_reply->minor_version );
+ free(xtest_reply);
+ }
+ if (e) {
+ fprintf( stderr, "XTest version error: %d", (int)e->error_code );
+ free(e);
+ }
+
+
+ /* prep for keysym-->keycode conversion */
+ syms = XCBKeySymbolsAlloc( c );
+
+ if( argc - optind >= 1 ) {
+ /* Arg mode */
+ for( cnt = optind; cnt < argc; cnt++ ) {
+ process_command( c, argv[ cnt ] );
+ }
+ }else{
+ /* STDIN mode */
+ buf = (char *)malloc( 128 );
+ while( fgets( buf, 128, stdin ) ) {
+ buf[ strlen( buf ) - 1 ] = 0; /* Chop \n */
+ process_command( c, buf );
+ }
+ }
+
+ XCBKeySymbolsFree( syms );
+
+ XCBDisconnect( c );
+ exit( 0 );
+}
diff --git a/xcb-proto/src/extensions/xtest.xml b/xcb-proto/src/extensions/xtest.xml
new file mode 100644
index 0000000..3ec0204
--- /dev/null
+++ b/xcb-proto/src/extensions/xtest.xml
@@ -0,0 +1,104 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+Copyright (C) 2006 Ian Osgood
+All Rights Reserved.
+
+Permission is hereby granted, free of charge, to any person ob/Sintaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+Except as contained in this notice, the names of the authors or their
+institutions shall not be used in advertising or otherwise to promote the
+sale, use or other dealings in this Software without prior written
+authorization from the authors.
+-->
+
+<xcb header="xtest" extension-xname="XTEST" extension-name="Test">
+
+ <!-- Conforms to XTEST 2.1 -->
+
+ <!-- Requests -->
+ <request name="GetVersion" opcode="0">
+ <field type="CARD8" name="major_version" />
+ <pad bytes="1" />
+ <field type="CARD16" name="minor_version" />
+ <reply>
+ <field type="CARD8" name="major_version" />
+ <field type="CARD16" name="minor_version" />
+ </reply>
+ </request>
+
+ <enum name="Cursor">
+ <item name="None"> <value>0</value></item>
+ <item name="Current"><value>1</value></item>
+ </enum>
+
+ <request name="CompareCursor" opcode="1">
+ <field type="WINDOW" name="window" />
+ <field type="CURSOR" name="cursor" />
+ <reply>
+ <field type="BOOL" name="same" />
+ </reply>
+ </request>
+
+ <!-- There are several ways to use the FakeInput request:
+ 1. Simulate a keypress:
+ type = XCBKeyPress or XCBKeyRelease
+ detail = keycode
+ 2. Simulate a button:
+ type = XCBButtonPress or XCBButtonRelease
+ detail = enum XCBButton (1..5)
+ 3. Simulate mouse motion:
+ type = XCBMotionNotify
+ detail = 0 or 1
+ window = XCBNone or a root window id
+ rootX,
+ rootY = position (relative if detail==1)
+
+ Version 2.2 adds support for the XInput extension:
+ 4. Simulate a device keypress
+ 5. Simulate a device button
+ 6. Simulate a proximity event
+ 7. Simulate a device motion event
+ [These are not yet supported, since we would also need to
+ send the variable-length state of the axes.]
+
+ In each case, time is set to a delay in milliseconds.
+ -->
+
+ <request name="FakeInput" opcode="2">
+ <field type="BYTE" name="type" />
+ <field type="BYTE" name="detail" />
+ <pad bytes="2" />
+ <field type="CARD32" name="time" />
+ <field type="WINDOW" name="window" />
+ <pad bytes="8" />
+ <field type="CARD16" name="rootX" />
+ <field type="CARD16" name="rootY" />
+ <pad bytes="7" />
+ <!-- Version 2.2: XInput device -->
+ <field type="CARD8" name="deviceid" />
+ <!-- Version 2.2: optional axes state here -->
+ </request>
+
+ <request name="GrabControl" opcode="3">
+ <field type="BOOL" name="impervious" />
+ <pad bytes="3" />
+ </request>
+
+ <!-- No events or errors -->
+
+</xcb>
\ No newline at end of file
More information about the xcb-commit
mailing list