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 (:-<) --------------------