/* * Ivypointer * * Copyright (C) 2007 * DGAC / DSNA / DTI / R&D * * Main and only file * * Authors: Benjamin Tissoires * * Please refer to file version.h for the * copyright notice regarding this software */ //#define _MPX_ #ifdef HAVE_CONFIG_H #include #endif #include #include #include #if X_DISPLAY_MISSING # error X11 is required to build xtest #else # include # include # include //# include //# include # define XK_MISCELLANY # define XK_XKB_KEYS # include # ifndef IsXExtensionKeyboard # define IsXExtensionKeyboard 3 # endif # ifndef IsXExtensionPointer # define IsXExtensionPointer 4 # endif # if HAVE_X11_EXTENSIONS_XTEST_H # include # else # error The XTest extension is required to build xtest # endif # if HAVE_X11_EXTENSIONS_XINERAMA_H // Xinerama.h may lack extern "C" for inclusion by C++ extern "C" { # include } # endif # if HAVE_XKB_EXTENSION # include # endif #endif #include #include #include #include "getopt.h" #define REGEXP_CHANGE_GEOMETRY_INPUT "^geometry_event device_id=(.*) x0=(.*) y0=(.*) x1=(.*) y1=(.*)" #define REGEXP_CHANGE_GEOMETRY_SCREEN "^screen_geometry_event device_id=(.*) x0=(.*) y0=(.*) x1=(.*) y1=(.*)" #define REGEXP_MOVE "^TelepointerMotion Id=(.*) X=(.*) Y=(.*)" #define REGEXP_DRAG "^TelepointerDrag Id=(.*) X=(.*) Y=(.*)" #define REGEXP_REL_MOVE "^TelepointerRelativeMotion Id=(.*) X=(.*) Y=(.*)" #define REGEXP_BUTTON "^TelepointerButton Id=(.*) Button=(.*) status=(.*)" #define REGEXP_POINTER "^pointer_event device_id=(.*) x=(.*) y=(.*) presure=(.*) tilt_x=(.*) tilt_y=(.*) wheel=(.*) predicted_x=(.*) predicted_y=(.*) type=(.*) serial_number=(.*) time=(.*) hires_x=(.*) hires_y=(.*) proximity=(.*)" #define REGEXP_PAD "^pad_event device_id=(.*) button=(.*) status=(.*) time=(.*)" #define REGEXP_SLIDER "^slider_event device_id=(.*) value=(.*) side=(.*) time=(.*)" #define REGEXP_BUTTON_WACOM "^button_event device_id=(.*) button=(.*) status=(.*) x=(.*) y=(.*) presure=(.*) tilt_x=(.*) tilt_y=(.*) wheel=(.*) predicted_x=(.*) predicted_y=(.*) type=(.*) serial_number=(.*) time=(.*) hires_x=(.*) hires_y=(.*) proximity=(.*)" #define WIDTH_WACOM 1600.0 #define HEIGHT_WACOM 1200.0 //#define WIDTH_WACOM 1.0 //#define HEIGHT_WACOM 1.0 #define TIME_CLICK 200 #define TIME_BETWEEN_CLICK 200 Display* display = NULL; #ifdef _MPX_ XDevice* dev = NULL; //#else //# error plop #endif float width,height; float coords_input[4] = {0.0,0.0,100.0,100.0}; float width_input,height_input, offsetx, offsety; int dragged = 0; int relative = 0; //int champX = 1; //int champY = 2; int champX = 12; int champY = 13; Display* openDisplay(const char* displayName) { // get the DISPLAY if (displayName == NULL) { displayName = getenv("DISPLAY"); if (displayName == NULL) { displayName = ":0.0"; } } // open the display printf("XOpenDisplay(\"%s\")\n", displayName); display = XOpenDisplay(displayName); if (display == NULL) { printf("EE : can't open display \"%s\"\n", displayName); return NULL; // throw XScreenUnavailable(60.0); } // verify the availability of the XTest extension int majorOpcode, firstEvent, firstError; if (!XQueryExtension(display, XTestExtensionName, &majorOpcode, &firstEvent, &firstError)) { printf("XTEST extension not available"); XCloseDisplay(display); return NULL; } XTestGrabControl(display, True); #if HAVE_XKB_EXTENSION { m_xkb = false; int major = XkbMajorVersion, minor = XkbMinorVersion; if (XkbLibraryVersion(&major, &minor)) { int opcode, firstError; if (XkbQueryExtension(display, &opcode, &m_xkbEventBase, &firstError, &major, &minor)) { m_xkb = true; XkbSelectEvents(display, XkbUseCoreKbd, XkbMapNotifyMask, XkbMapNotifyMask); XkbSelectEventDetails(display, XkbUseCoreKbd, XkbStateNotifyMask, XkbGroupStateMask, XkbGroupStateMask); } } } #endif return display; } XDevice *openDevice(Display * dpy, int id){ return XOpenDevice(dpy, id); } // -------------------------------------------------------------------------- // tools // -------------------------------------------------------------------------- void print_coords_input(void){ printf("coords of input : %.2f,%.2f %.2f,%.2f\n", coords_input[0], coords_input[1], coords_input[2], coords_input[3]); } int valid(float x, float y) { if (xcoords_input[2]) { // printf("x > x1\n"); return 0; } if (ycoords_input[3]){ // printf("y < y1\n"); return 0; } return 1; } // -------------------------------------------------------------------------- // X11 functions // -------------------------------------------------------------------------- void fakeMouseButton(const unsigned int xButton, Bool press, int x, int y) { if (xButton != 0) { #ifndef _MPX_ XTestFakeButtonEvent(display, xButton, press ? True : False, CurrentTime); #else int axes[2] = {x,y}; XTestFakeDeviceButtonEvent(display, dev, xButton, press ? True : False, axes, 2, CurrentTime); #endif XFlush(display); } } void fakeMouseMove(int x, int y) { // printf("x = %d,y = %d;\n ",x,y); #ifndef _MPX_ XTestFakeMotionEvent(display, DefaultScreen(display), x, y, CurrentTime); #else int axes[2] = {x,y}; XTestFakeDeviceMotionEvent(display, dev, False, 0, axes, 2, CurrentTime); #endif //XWarpPointer(display, None, RootWindow(display, 0), 0, 0, 0, 0, x, y); XFlush(display); } void fakeMouseRelativeMove(int dx, int dy) { #ifndef _MPX_ XTestFakeRelativeMotionEvent(display, dx, dy, CurrentTime); #else int axes[2] = {dx,dy}; XTestFakeDeviceMotionEvent(display, dev, True, 0, axes, 2, CurrentTime); #endif //XWarpPointer(display, None, None, 0, 0, 0, 0, dx, dy); XFlush(display); } // -------------------------------------------------------------------------- // Geometry callback // -------------------------------------------------------------------------- void CallbackGeometry(IvyClientPtr app, void *user_data, int argc, char *argv[]) { // char *id = argv[0]; float x0 = atof(argv[1]); float y0 = atof(argv[2]); float x1 = atof(argv[3]); float y1 = atof(argv[4]); if (x1 > x0 && y1 > y0 ){ coords_input[0] = x0; coords_input[1] = y0; coords_input[2] = x1; coords_input[3] = y1; width_input = coords_input[2]-coords_input[0]; height_input = coords_input[3]-coords_input[1]; print_coords_input(); } else { printf("bad coords received : %.0f,%.0f %.0f,%.0f\n",x0,y0,x1,y1); } } void CallbackScreen(IvyClientPtr app, void *user_data, int argc, char *argv[]) { // char *id = argv[0]; float x0 = atof(argv[1]); float y0 = atof(argv[2]); float x1 = atof(argv[3]); float y1 = atof(argv[4]); if (x1 > x0 && y1 > y0 ){ offsetx = x0; offsety = y0; width = x1-x0; height = y1-y0; printf("screen : %f+%f x %f+%f\n",offsetx,width,offsety,height); } else { printf("bad coords received : %.2f,%.2f %.2f,%.2f\n",x0,y0,x1,y1); } } // -------------------------------------------------------------------------- // Telepointer callbacks // -------------------------------------------------------------------------- void CallbackMove (IvyClientPtr app, void *user_data, int argc, char *argv[]) { // printf ("%s sent (size : %d)",IvyGetApplicationName(app),argc); // for (i = 0; i < argc; i++) // printf(" '%s'",argv[i]); float x = atof(argv[1]); float y = atof(argv[2]); x = x*width/100.0; y = y*height/100.0; // char *id = argv[0]; // printf("x = %f,y = %f; ",x,y); // printf("x = %f,y = %f\n",x,y); if (valid(x,y)){ fakeMouseMove((int)x,(int)y); if (dragged){ fakeMouseButton(1,0,x,y); dragged = 0; } } } void CallbackDrag (IvyClientPtr app, void *user_data, int argc, char *argv[]) { // char *id = argv[0]; float x = atof(argv[1]); float y = atof(argv[2]); x *= width/100.0; y *= height/100.0; // printf("x = %f,y = %f\n",x,y); if (valid(x,y)){ fakeMouseMove((int)x,(int)y); if (!dragged){ fakeMouseButton(1,1,x,y); dragged = 1; } } } void CallbackRelMove (IvyClientPtr app, void *user_data, int argc, char *argv[]) { // char *id = argv[0]; float x = atof(argv[1]); float y = atof(argv[2]); x *= width/100.0; y *= height/100.0; fakeMouseRelativeMove((int)x,(int)y); } void CallbackButton (IvyClientPtr app, void *user_data, int argc, char *argv[]) { // char *id = argv[0]; int b = atoi(argv[1]); int press = atoi(argv[2]); // if (!b) // return fakeMouseButton(b,press,0,0); } // -------------------------------------------------------------------------- // Wacom callbacks // -------------------------------------------------------------------------- void CallbackPointer (IvyClientPtr app, void *user_data, int argc, char *argv[]) { // char *id = argv[0]; float x = atof(argv[champX]); // predicted position float y = atof(argv[champY]); // predicted position int time = atoi(argv[11]); int presure = atoi(argv[3]); static float old_x = 0; static float old_y = 0; static int old_time = 0; static int should_click = 0; static int clicked = 0; if (!valid(x,y)){ // ignore outside events return; } // printf("x = %f,y = %f;\n ",x,y); x = offsetx + (x-coords_input[0])*width/width_input; y = offsety + (y-coords_input[1])*height/height_input; if (!relative) { //absolute mode fakeMouseMove((int)x,(int)y); if (!dragged && presure>0){ fakeMouseButton(1,1,x,y); dragged = 1; } } else { //relative mode int dx = (int)(x-old_x); int dy = (int)(y-old_y); int dt = time-old_time; // if (old_time) // printf("time=%d, old_time=%d, dt=%d\n",time, old_time, dt); if (presure > 0) { if (!should_click){ old_time = time; dt = 0; should_click = 1; // printf("armement du timeout\n"); } else { if (should_click ==1 && dt > TIME_CLICK){ should_click = 2; // printf("timeout\n"); } } fakeMouseRelativeMove(dx,dy); } else { if (should_click == 1) { // printf("dt = %d\n",dt); if (clicked) { //double click // printf("ck\n"); fakeMouseButton(1,0,x,y); } // printf("cli\n"); clicked = 1; old_time = time; fakeMouseButton(1,1,x,y); } should_click = 0; if (clicked) { if (dt > TIME_BETWEEN_CLICK){ // printf("ck\n"); fakeMouseButton(1,0,x,y); clicked = 0; } } else { old_time = 0; } } } // release (common of both modes) if (dragged && presure==0){ fakeMouseButton(1,0,x,y); dragged = 0; } old_x = x; old_y = y; } void CallbackPad (IvyClientPtr app, void *user_data, int argc, char *argv[]) { // char *id = argv[0]; int b = atoi(argv[1]); int press = 0; // if (!b) // return if (strcmp(argv[2],"up")){ press = 1; } // printf("Pad button=%d pressed%d event received\n",b, press); if (b==11 || b==15 || (press && (b==12 || b==16))){ //inversion du mode relative = !relative; } else { fakeMouseButton(b,press,0,0); } } void CallbackSlider (IvyClientPtr app, void *user_data, int argc, char *argv[]) { //TODO // char *id = argv[0]; // int b = atoi(argv[1]); // int press = atoi(argv[2]); // if (!b) // return // fakeMouseButton(b,press); } void CallbackButtonWacom (IvyClientPtr app, void *user_data, int argc, char *argv[]) { // char *id = argv[0]; int b = atoi(argv[1]); if (b == 1) // gestion propre du bouton 1 return; int press = strcmp(argv[2],"up"); fakeMouseButton(b,press,0,0); } void printHelpMsg(const char *name){ const char* helpmsg = "[options] [regexps]\n\t-b bus\t\tdefines the Ivy bus to which to connect to, defaults to 127:2010\n" "\t-t\t\tuse data from ModeManager instead of xinput_wacom\n" "\t-c x0,y0,x1,y1\tspecify the coords of the input used (only used with wacom)\n" "\t-C x0,y0,x1,y1\tspecify the coords of the screen used\n" "\t-r\tuse relative mode by default\n" "\t-p\tuse predictive mode\n" "\t-v\t\tprints the ivy relase number\n\n" ; printf("usage: %s %s",name,helpmsg); } int extractValues(char optarg[], float* output, const char name[]){ int i = 0; int j = 0; int last = 0; float coupures[4] = {0,0,0,0}; while(optarg[i]){ if (optarg[i] == ','){ coupures[j] = i; j++; if (j > 3) { printHelpMsg(name); exit(1); } } i++; } coupures[j] = i; j = 0; last = 0; for (i=0; i< 4; i++){ int length = coupures[i]-last; char buf [1024] = ""; int k; for (k = 0; k < length; k++) { buf[k] = optarg[last+k]; } output[i] = atof(buf); last = coupures[i]+1; } return 1; } // -------------------------------------------------------------------------- // Main // -------------------------------------------------------------------------- int main(int argc, char *argv[]) { const char* bus = 0; char busbuf [1024] = ""; int wacom = 1; int predictive_mode = 0; float user_coordsI = 0; float user_coordsO = 0; float coordsI[4] = {0,0,0,0}; float coordsO[4] = {0,0,0,0}; int c; int id = -1; while ((c = getopt(argc, argv, "vb:twc:C:rpd:")) != EOF) switch (c) { case 'b': strcpy (busbuf, optarg); bus = busbuf; break; case 'v': printf("ivy c library version %d.%d\n",IVYMAJOR_VERSION,IVYMINOR_VERSION); break; case 'r': relative = 1; break; case 'w': break; case 't': wacom = 0; break; case 'p': champX = 7; champY = 8; predictive_mode = 1; break; case 'c': user_coordsI = extractValues(optarg, coordsI, argv[0]); break; case 'C': user_coordsO = extractValues(optarg, coordsO, argv[0]); break; case 'd': id = atoi(optarg); break; default: printf("bad option : %s\n",(char*)&c); printHelpMsg(argv[0]); exit(1); } Display* d = openDisplay(NULL); if (!d){ return 1; } #ifdef _MPX_ if (id >=0){ printf("opening device id=%d\n",id); dev = openDevice(d,id); if (!dev) { printf("unable to open device id=%d\n",id); } } #endif if (wacom) { if (user_coordsI){ int i; for (i=0;i<4;i++) { coords_input[i] = coordsI[i]; } } else { if (predictive_mode){ coords_input[2] = WIDTH_WACOM; coords_input[3] = HEIGHT_WACOM; } else { coords_input[2] = 1.0; coords_input[3] = 1.0; } } print_coords_input(); width_input = coords_input[2]-coords_input[0]; height_input = coords_input[3]-coords_input[1]; } if (user_coordsO){ offsetx = coordsO[0]; offsety = coordsO[1]; width = coordsO[2]-coordsO[0]; height = coordsO[3]-coordsO[1]; } else { offsetx = 0; offsety = 0; width = DisplayWidth(d, DefaultScreen(d)); height = DisplayHeight(d, DefaultScreen(d)); } printf("screen : %.2f+%.2f x %.2f+%.2f\n",offsetx,width,offsety,height); // verifications if (width < 2 || height < 2 ){//|| (wacom && (width_input < || height_input < 2))){ print_coords_input(); printf("%.2f %.2f %.2f %.2f\n",width,height,width_input,height_input); printHelpMsg(argv[0]); exit(1); } MsgRcvPtr ptrMove,ptrRelMove,ptrButton; IvyInit("IvyPointer","IvyPointer Ready",NULL,NULL,NULL,NULL); if (!wacom) { // telepointer callbacks ptrMove=IvyBindMsg(CallbackMove,&ptrMove,REGEXP_MOVE); printf("bound to %s\n",REGEXP_MOVE); ptrMove=IvyBindMsg(CallbackDrag,&ptrMove,REGEXP_DRAG); printf("bound to %s\n",REGEXP_DRAG); ptrMove=IvyBindMsg(CallbackRelMove,&ptrRelMove,REGEXP_REL_MOVE); printf("bound to %s\n",REGEXP_REL_MOVE); ptrMove=IvyBindMsg(CallbackButton,&ptrButton,REGEXP_BUTTON); printf("bound to %s\n",REGEXP_BUTTON); } else { //wacom callbacks ptrMove=IvyBindMsg(CallbackGeometry,&ptrMove,REGEXP_CHANGE_GEOMETRY_INPUT); printf("bound to %s\n",REGEXP_CHANGE_GEOMETRY_INPUT); ptrMove=IvyBindMsg(CallbackPointer,&ptrMove,REGEXP_POINTER); printf("bound to %s\n",REGEXP_POINTER); // ptrMove=IvyBindMsg(CallbackSlider,&ptrMove,REGEXP_SLIDER); // printf("bound to %s\n",REGEXP_SLIDER); ptrMove=IvyBindMsg(CallbackPad,&ptrButton,REGEXP_PAD); printf("bound to %s\n",REGEXP_PAD); ptrMove=IvyBindMsg(CallbackButtonWacom,&ptrButton,REGEXP_BUTTON_WACOM); printf("bound to %s\n",REGEXP_BUTTON_WACOM); } ptrMove=IvyBindMsg(CallbackScreen,&ptrMove,REGEXP_CHANGE_GEOMETRY_SCREEN); printf("bound to %s\n",REGEXP_CHANGE_GEOMETRY_SCREEN); IvyStart(bus); #if (IVYMAJOR_VERSION == 3) && (IVYMINOR_VERSION < 9) IvyMainLoop(NULL, NULL); #else IvyMainLoop(); #endif return 0; }