fcolin@cenaath.cena.dgac.fr (Francois-Regis COLIN) (03/14/91)
here is a simple program to make access to an adjacent screen with the mouse. The purpose of this program is to make a reconfigurable working position: we need to have 3 screens manipulated by a various number of operator form 1 to 3 . so we need 3 displays NOT 3 screens because of the mouse. The program is not yiet finished but it begins to work with a mouse on any window allowing sendevent as normal event. problems : - major difficulties is to build the event correctly ( depending on the grag of the other screens ). we need to redo the job of the adjacent server . - response time may be slow ! - we need to establish a priority for accepting other mouse inputs questions : - should I continue to work on this program using X11R4 ? - should I wait for better support of Xinput ? - in fact should I wait for X11R5 ? - will R5 offer me better solution for my problem ? --------------- cut here (:->) -------------------- /* * Sharing mouse pointer to adjacent screen. * Purpose : controlling adjacent display not screen with a same mouse. * we need different display because there are two different operators * in front of two displays * Author : fcolin@cenaath.cena.dgac.fr * */ #include <X11/Xlib.h> #include <X11/Xutil.h> #include <X11/Xos.h> #include <stdio.h> static Display *display = NULL; /* display on wich is the mouse */ static Display *otherDisplay = NULL; /* display on wich is the pointeur */ static Display *leftDisplay = NULL; /* display on left of display */ static Display *rightDisplay = NULL; /* display on right of display */ static Window otherRootWindow = 0; static Window leftRootWindow = 0; static Window rightRootWindow = 0; static int savedAccel_numerator, savedAccel_denominator, savedThreshold; #define NB_MAPPING 4 static int savedNbMapping; static unsigned char savedMapping[NB_MAPPING]; static unsigned char zeroMapping[NB_MAPPING] = { 0,0,0,0}; static Pixmap NoCursorPixmap; static char NoCursor_bits[] = { 0x00}; static XColor color = { 0,0,0,0,0,0}; static unsigned int display_width, display_height; static int screen; /* external for otion parsing */ extern char *optarg; extern int optind, opterr; extern int getopt(int argc, char **argv, char *optstring); /* * Activate the mouse by settings accelerator and mapping to saved one */ static activate_mouse( Display *other ) { XChangePointerControl( otherDisplay, True, True, savedAccel_numerator, savedAccel_denominator, savedThreshold); XSetPointerMapping( otherDisplay, savedMapping, savedNbMapping ); } /* * Deactivate the mouse by settings accelerator and mapping to zero */ static deactivate_mouse( Display *other ) { XChangePointerControl( other, True, True, 0, 2, 0); XSetPointerMapping( other, zeroMapping, savedNbMapping ); } /* * Send Event to the specified window recalculating the new event */ static SimulateMouseEvent( Window destWindow, XEvent *event ) { /* recalculate the new coordinates relatives to the new display */ if ( !XTranslateCoordinates( otherDisplay, otherRootWindow, event->xbutton.window, event->xbutton.x_root, event->xbutton.y_root, &event->xbutton.x, &event->xbutton.y, &event->xbutton.subwindow )) printf("error Translate Coordinates\n"); /* update the event with new data */ event->xbutton.display = otherDisplay; event->xbutton.root = otherRootWindow; event->xbutton.serial = LastKnownRequestProcessed( otherDisplay ); if ( !XSendEvent( otherDisplay, destWindow, True, NULL, event )) printf("error sendind event\n"); } void main( int argc, char **argv ) { Window winLeft,winRight,simulatedgrabWindow; char *window_name = "CursorSharing"; XEvent report; int root_x, root_y,new_x; Window grabbingWindow; XSetWindowAttributes attributs; Cursor NoCursor; Bool pointerGrabbed = False; int c,i,grab; unsigned int dummy; if ( argc < 2 ) { (void)fprintf(stderr, "usage: %s -l leftDisplay -r rightDisplay\n",argv[0]); exit (-2); } /* connect to X server */ if ( (display=XOpenDisplay(NULL)) == NULL ) { (void) fprintf( stderr, "cannot connect to local X server\n"); exit( -1 ); } while ((c = getopt(argc, argv, "l:r:--")) != -1) switch (c) { case 'l': if ( (leftDisplay=XOpenDisplay(optarg)) == NULL ) { (void) fprintf( stderr, "cannot connect to X server %s\n", XDisplayName(optarg)); exit( -1 ); } leftRootWindow = RootWindow(leftDisplay,DefaultScreen(leftDisplay)); break; case 'r': if ( (rightDisplay=XOpenDisplay(optarg)) == NULL ) { (void) fprintf( stderr, "cannot connect to X server %s\n", XDisplayName(optarg)); exit( -1 ); } rightRootWindow = RootWindow(rightDisplay,DefaultScreen(rightDisplay)); break; case '?': (void)fprintf(stderr, "usage: %s -l leftDisplay -r rightDisplay\n",argv[0]); exit (-2); } /* get screen size from display structure macro all screens a supposed to be identical */ screen = DefaultScreen(display); display_width = DisplayWidth(display, screen); display_height = DisplayHeight(display, screen); /* create the invisible cursor to use when the pointer is on an other screen */ NoCursorPixmap = XCreateBitmapFromData( display,RootWindow(display,screen), NoCursor_bits, 1,1); NoCursor = XCreatePixmapCursor( display, NoCursorPixmap, NoCursorPixmap, &color,&color, 0,0); /* create small 1 pixel input only window width on the left edge of the screen */ attributs.override_redirect = True; winLeft = XCreateWindow(display, RootWindow(display,screen), 0, 0, 1, display_height,0,0, InputOnly,CopyFromParent, CWOverrideRedirect, &attributs); /* create small 1 pixel input only window width on the right edge of the screen */ attributs.override_redirect = True; winRight = XCreateWindow(display, RootWindow(display,screen), display_width - 1, 0, 1, display_height,0,0, InputOnly,CopyFromParent, CWOverrideRedirect, &attributs); /* Select event types wanted */ XSelectInput(display, winRight, EnterWindowMask ); XSelectInput(display, winLeft, EnterWindowMask ); /* Display window */ XMapWindow(display, winLeft); XMapWindow(display, winRight); pointerGrabbed = False; simulatedgrabWindow = -1; /* save the mouse control and mapping supposed identical on each display */ XGetPointerControl( display, &savedAccel_numerator, &savedAccel_denominator, &savedThreshold); savedNbMapping = XGetPointerMapping( display, savedMapping,NB_MAPPING); while (1) { if ( otherDisplay != NULL ) XFlush( otherDisplay ); XNextEvent(display, &report); switch (report.type) { /* when pointer is grabbed we simulate the mouse mouvement on the other display */ case MotionNotify: if ( pointerGrabbed ) { XWarpPointer(otherDisplay, None, otherRootWindow, 0,0, display_width,display_height, report.xmotion.x_root, report.xmotion.y_root ); /* send motion report if simulated grab is active */ if ( simulatedgrabWindow != -1) { report.xmotion.window = simulatedgrabWindow; SimulateMouseEvent ( simulatedgrabWindow, &report ); } } break; /* check crossing edge of the screen */ case EnterNotify: if (report.xcrossing.window == grabbingWindow ) { /* discard EnterNotify generated by WrapPointer */ grabbingWindow = 0; break; } if ( !pointerGrabbed ) { /* we are leaving our screen determine which display to use */ if (report.xcrossing.window == winLeft) { if ( leftDisplay == NULL ) break; otherDisplay = leftDisplay; otherRootWindow = leftRootWindow; grabbingWindow = winRight; /* grabbing opposite window to detect croosing back to out screen */ } else { if ( rightDisplay == NULL ) break; otherDisplay = rightDisplay; otherRootWindow = rightRootWindow; grabbingWindow = winLeft; /* grabbing opposite window to detect croosing back to out screen */ } /* grabbing our pointer to get all the futher events */ grab = XGrabPointer( display, grabbingWindow, False, PointerMotionMask | ButtonPressMask | ButtonReleaseMask | EnterWindowMask, GrabModeAsync, GrabModeAsync, None, NoCursor, CurrentTime ); if ( grab != GrabSuccess ) printf("grab result %d \n",grab); else { pointerGrabbed = True; /* freeze the other mouse * we can't grab this mouse because * we want normal event to take place */ deactivate_mouse( otherDisplay ); } } else { /* we are getting back to our display */ XUngrabPointer( display, CurrentTime ); pointerGrabbed = False; /* unfreeze the other mouse */ activate_mouse( otherDisplay ); } /* Warp the pointer to the opposite edge of our screen * so we got good motion event not limited to the edge */ new_x = abs((display_width - report.xcrossing.x_root) -2); XWarpPointer( display, None, RootWindow(display,DefaultScreen(display)), 0,0, display_width,display_height, new_x, report.xcrossing.y_root ); break; case ButtonPress: if ( pointerGrabbed ) { report.xbutton.subwindow = otherRootWindow; /* lookup for the window under the cursor */ do { report.xbutton.window = report.xbutton.subwindow; printf("search grab %lx\n",report.xbutton.window); if ( !XTranslateCoordinates( otherDisplay, otherRootWindow, report.xbutton.window, report.xbutton.x_root, report.xbutton.y_root, &report.xbutton.x, &report.xbutton.y, &report.xbutton.subwindow )) printf("error Translate Coordinates\n"); } while ( report.xbutton.subwindow != None ); if ( report.xbutton.window == otherRootWindow ) simulatedgrabWindow = PointerWindow; else simulatedgrabWindow = report.xbutton.window; printf("simul grab %lx\n",simulatedgrabWindow); SimulateMouseEvent( simulatedgrabWindow, &report ); } break; case ButtonRelease : if ( pointerGrabbed ) { report.xbutton.window = simulatedgrabWindow; SimulateMouseEvent( simulatedgrabWindow, &report ); simulatedgrabWindow = -1; } break; } /* end switch */ } /* end while */ } --------------- cut here (:-<) --------------------