kopia lustrzana https://github.com/FreeSpacenav/spacenavd
				
				
				
			- Fixed a bug where the daemon would quit if the X server is stopped.
- Alleviated the need for XSync in xsend_event. Now XFlush suffices. - Added separate sensitivity options for rotation and translation. - Added option to swap Y and Z translation axes. git-svn-id: svn+ssh://svn.code.sf.net/p/spacenav/code/trunk/spacenavd@96 ef983eb1-d774-4af8-acfd-baaf7b16a646pull/1/head
							rodzic
							
								
									f6a10f2786
								
							
						
					
					
						commit
						cd5312cd39
					
				|  | @ -16,7 +16,6 @@ You should have received a copy of the GNU General Public License | ||||||
| along with this program.  If not, see <http://www.gnu.org/licenses/>.
 | along with this program.  If not, see <http://www.gnu.org/licenses/>.
 | ||||||
| */ | */ | ||||||
| 
 | 
 | ||||||
| #include "config.h" |  | ||||||
| #include <stdio.h> | #include <stdio.h> | ||||||
| #include <stdlib.h> | #include <stdlib.h> | ||||||
| #include <string.h> | #include <string.h> | ||||||
|  | @ -27,19 +26,20 @@ along with this program.  If not, see <http://www.gnu.org/licenses/>. | ||||||
| 
 | 
 | ||||||
| enum {TX, TY, TZ, RX, RY, RZ}; | enum {TX, TY, TZ, RX, RY, RZ}; | ||||||
| 
 | 
 | ||||||
|  | static const int def_axmap[] = {0, 2, 1, 3, 5, 4}; | ||||||
|  | static const int def_axinv[] = {0, 1, 1, 0, 1, 1}; | ||||||
|  | 
 | ||||||
| void default_cfg(struct cfg *cfg) | void default_cfg(struct cfg *cfg) | ||||||
| { | { | ||||||
| 	int i; | 	int i; | ||||||
| 	static const int axmap[] = {0, 2, 1, 3, 5, 4}; |  | ||||||
| 	static const int axinv[] = {0, 1, 1, 0, 1, 1}; |  | ||||||
| 
 | 
 | ||||||
| 	cfg->sensitivity = 1.0; | 	cfg->sensitivity = cfg->sens_trans = cfg->sens_rot = 1.0; | ||||||
| 	cfg->dead_threshold = 2; | 	cfg->dead_threshold = 2; | ||||||
| 	cfg->led = 1; | 	cfg->led = 1; | ||||||
| 
 | 
 | ||||||
| 	for(i=0; i<6; i++) { | 	for(i=0; i<6; i++) { | ||||||
| 		cfg->invert[i] = axinv[i]; | 		cfg->invert[i] = def_axinv[i]; | ||||||
| 		cfg->map_axis[i] = axmap[i]; | 		cfg->map_axis[i] = def_axmap[i]; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	for(i=0; i<MAX_BUTTONS; i++) { | 	for(i=0; i<MAX_BUTTONS; i++) { | ||||||
|  | @ -100,6 +100,20 @@ int read_cfg(const char *fname, struct cfg *cfg) | ||||||
| 			} | 			} | ||||||
| 			cfg->sensitivity = atof(val_str); | 			cfg->sensitivity = atof(val_str); | ||||||
| 
 | 
 | ||||||
|  | 		} else if(strcmp(key_str, "sensitivity-translation") == 0) { | ||||||
|  | 			if(!isnum) { | ||||||
|  | 				fprintf(stderr, "invalid configuration value for %s, expected a number.\n", key_str); | ||||||
|  | 				continue; | ||||||
|  | 			} | ||||||
|  | 			cfg->sens_trans = atof(val_str); | ||||||
|  | 
 | ||||||
|  | 		} else if(strcmp(key_str, "sensitivity-rotation") == 0) { | ||||||
|  | 			if(!isnum) { | ||||||
|  | 				fprintf(stderr, "invalid configuration value for %s, expected a number.\n", key_str); | ||||||
|  | 				continue; | ||||||
|  | 			} | ||||||
|  | 			cfg->sens_rot = atof(val_str); | ||||||
|  | 
 | ||||||
| 		} else if(strcmp(key_str, "invert-rot") == 0) { | 		} else if(strcmp(key_str, "invert-rot") == 0) { | ||||||
| 			if(strchr(val_str, 'x')) { | 			if(strchr(val_str, 'x')) { | ||||||
| 				cfg->invert[RX] = !cfg->invert[RX]; | 				cfg->invert[RX] = !cfg->invert[RX]; | ||||||
|  | @ -122,6 +136,30 @@ int read_cfg(const char *fname, struct cfg *cfg) | ||||||
| 				cfg->invert[TZ] = !cfg->invert[TZ]; | 				cfg->invert[TZ] = !cfg->invert[TZ]; | ||||||
| 			} | 			} | ||||||
| 
 | 
 | ||||||
|  | 		} else if(strcmp(key_str, "swap-yz") == 0) { | ||||||
|  | 			int i, swap_yz = 0; | ||||||
|  | 
 | ||||||
|  | 			if(isnum) { | ||||||
|  | 				swap_yz = atoi(val_str); | ||||||
|  | 			} else { | ||||||
|  | 				if(strcmp(val_str, "true") == 0 || strcmp(val_str, "on") == 0 || strcmp(val_str, "yes") == 0) { | ||||||
|  | 					swap_yz = 1; | ||||||
|  | 				} else if(strcmp(val_str, "false") == 0 || strcmp(val_str, "off") == 0 || strcmp(val_str, "no") == 0) { | ||||||
|  | 					swap_yz = 0; | ||||||
|  | 				} else { | ||||||
|  | 					fprintf(stderr, "invalid configuration value for %s, expected a boolean value.\n", key_str); | ||||||
|  | 					continue; | ||||||
|  | 				} | ||||||
|  | 			} | ||||||
|  | 
 | ||||||
|  | 			for(i=0; i<6; i++) { | ||||||
|  | 				if(swap_yz) { | ||||||
|  | 					cfg->map_axis[i] = i; | ||||||
|  | 				} else { | ||||||
|  | 					cfg->map_axis[i] = def_axmap[i]; | ||||||
|  | 				} | ||||||
|  | 			} | ||||||
|  | 
 | ||||||
| 		} else if(strcmp(key_str, "led") == 0) { | 		} else if(strcmp(key_str, "led") == 0) { | ||||||
| 			if(isnum) { | 			if(isnum) { | ||||||
| 				cfg->led = atoi(val_str); | 				cfg->led = atoi(val_str); | ||||||
|  | @ -170,27 +208,34 @@ int write_cfg(const char *fname, struct cfg *cfg) | ||||||
| 	fprintf(fp, "# sensitivity is multiplied with every motion (1.0 normal).\n"); | 	fprintf(fp, "# sensitivity is multiplied with every motion (1.0 normal).\n"); | ||||||
| 	fprintf(fp, "sensitivity = %.3f\n\n", cfg->sensitivity); | 	fprintf(fp, "sensitivity = %.3f\n\n", cfg->sensitivity); | ||||||
| 
 | 
 | ||||||
|  | 	fprintf(fp, "# separate sensitivity for rotation and translation.\n"); | ||||||
|  | 	fprintf(fp, "sensitivity-translation = %.3f\n", cfg->sens_trans); | ||||||
|  | 	fprintf(fp, "sensitivity-rotation = %.3f\n\n", cfg->sens_rot); | ||||||
|  | 
 | ||||||
| 	fprintf(fp, "# dead zone; any motion less than this number, is discarded as noise.\n"); | 	fprintf(fp, "# dead zone; any motion less than this number, is discarded as noise.\n"); | ||||||
| 	fprintf(fp, "dead-zone = %d\n\n", cfg->dead_threshold); | 	fprintf(fp, "dead-zone = %d\n\n", cfg->dead_threshold); | ||||||
| 
 | 
 | ||||||
| 	if(cfg->invert[0] || cfg->invert[1] || cfg->invert[2]) { | 	if(cfg->invert[0] || cfg->invert[1] || cfg->invert[2]) { | ||||||
| 		fprintf(fp, "# invert translations on some axes.\n"); | 		fprintf(fp, "# invert translations on some axes.\n"); | ||||||
| 		fprintf(fp, "invert-trans = "); | 		fprintf(fp, "invert-trans = "); | ||||||
| 		if(cfg->invert[0]) fputc('x', fp); | 		if(cfg->invert[0] != def_axinv[0]) fputc('x', fp); | ||||||
| 		if(cfg->invert[1]) fputc('y', fp); | 		if(cfg->invert[1] != def_axinv[1]) fputc('y', fp); | ||||||
| 		if(cfg->invert[2]) fputc('z', fp); | 		if(cfg->invert[2] != def_axinv[2]) fputc('z', fp); | ||||||
| 		fputs("\n\n", fp); | 		fputs("\n\n", fp); | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	if(cfg->invert[3] || cfg->invert[4] || cfg->invert[5]) { | 	if(cfg->invert[3] || cfg->invert[4] || cfg->invert[5]) { | ||||||
| 		fprintf(fp, "# invert rotations around some axes.\n"); | 		fprintf(fp, "# invert rotations around some axes.\n"); | ||||||
| 		fprintf(fp, "invert-rot = "); | 		fprintf(fp, "invert-rot = "); | ||||||
| 		if(cfg->invert[3]) fputc('x', fp); | 		if(cfg->invert[3] != def_axinv[3]) fputc('x', fp); | ||||||
| 		if(cfg->invert[4]) fputc('y', fp); | 		if(cfg->invert[4] != def_axinv[4]) fputc('y', fp); | ||||||
| 		if(cfg->invert[5]) fputc('z', fp); | 		if(cfg->invert[5] != def_axinv[5]) fputc('z', fp); | ||||||
| 		fputs("\n\n", fp); | 		fputs("\n\n", fp); | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  | 	fprintf(fp, "# swap translation along Y and Z axes\n"); | ||||||
|  | 	fprintf(fp, "swap-yz = %s\n\n", cfg->map_axis[1] == def_axmap[1] ? "false" : "true"); | ||||||
|  | 
 | ||||||
| 	if(!cfg->led) { | 	if(!cfg->led) { | ||||||
| 		fprintf(fp, "# disable led\n"); | 		fprintf(fp, "# disable led\n"); | ||||||
| 		fprintf(fp, "led = 0\n\n"); | 		fprintf(fp, "led = 0\n\n"); | ||||||
|  |  | ||||||
|  | @ -19,12 +19,10 @@ along with this program.  If not, see <http://www.gnu.org/licenses/>. | ||||||
| #ifndef CFGFILE_H_ | #ifndef CFGFILE_H_ | ||||||
| #define CFGFILE_H_ | #define CFGFILE_H_ | ||||||
| 
 | 
 | ||||||
| #include "config.h" |  | ||||||
| 
 |  | ||||||
| #define MAX_BUTTONS		64 | #define MAX_BUTTONS		64 | ||||||
| 
 | 
 | ||||||
| struct cfg { | struct cfg { | ||||||
| 	float sensitivity; | 	float sensitivity, sens_trans, sens_rot; | ||||||
| 	int dead_threshold; | 	int dead_threshold; | ||||||
| 	int invert[6]; | 	int invert[6]; | ||||||
| 	int map_axis[6]; | 	int map_axis[6]; | ||||||
|  |  | ||||||
|  | @ -55,9 +55,7 @@ void process_input(struct dev_input *inp) | ||||||
| 		inp->idx = cfg.map_axis[inp->idx]; | 		inp->idx = cfg.map_axis[inp->idx]; | ||||||
| 		sign = cfg.invert[inp->idx] ? -1 : 1; | 		sign = cfg.invert[inp->idx] ? -1 : 1; | ||||||
| 
 | 
 | ||||||
| 		if(cfg.sensitivity != 1.0) { | 		inp->val = (int)((float)inp->val * cfg.sensitivity * (inp->idx < 3 ? cfg.sens_trans : cfg.sens_rot)); | ||||||
| 			inp->val = (int)((float)inp->val * cfg.sensitivity); |  | ||||||
| 		} |  | ||||||
| 
 | 
 | ||||||
| 		ev.type = EVENT_MOTION; | 		ev.type = EVENT_MOTION; | ||||||
| 		ev.motion.data = (int*)&ev.motion.x; | 		ev.motion.data = (int*)&ev.motion.x; | ||||||
|  | @ -71,7 +69,7 @@ void process_input(struct dev_input *inp) | ||||||
| 			ev_pending = 0; | 			ev_pending = 0; | ||||||
| 		} | 		} | ||||||
| 		inp->idx = cfg.map_button[inp->idx]; | 		inp->idx = cfg.map_button[inp->idx]; | ||||||
| 		 | 
 | ||||||
| 		ev.type = EVENT_BUTTON; | 		ev.type = EVENT_BUTTON; | ||||||
| 		ev.button.press = inp->val; | 		ev.button.press = inp->val; | ||||||
| 		ev.button.bnum = inp->idx; | 		ev.button.bnum = inp->idx; | ||||||
|  |  | ||||||
|  | @ -21,6 +21,7 @@ along with this program.  If not, see <http://www.gnu.org/licenses/>. | ||||||
| #ifdef USE_X11 | #ifdef USE_X11 | ||||||
| #include <stdio.h> | #include <stdio.h> | ||||||
| #include <stdlib.h> | #include <stdlib.h> | ||||||
|  | #include <setjmp.h> | ||||||
| #include "proto_x11.h" | #include "proto_x11.h" | ||||||
| #include "client.h" | #include "client.h" | ||||||
| #include "spnavd.h" | #include "spnavd.h" | ||||||
|  | @ -34,7 +35,8 @@ enum cmd_msg { | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| static int catch_badwin(Display *dpy, XErrorEvent *err); | static int xerr(Display *dpy, XErrorEvent *err); | ||||||
|  | static int xioerr(Display *dpy); | ||||||
| 
 | 
 | ||||||
| static Display *dpy; | static Display *dpy; | ||||||
| static Window win; | static Window win; | ||||||
|  | @ -47,6 +49,8 @@ static Atom xa_event_motion, xa_event_bpress, xa_event_brelease, xa_event_cmd; | ||||||
|  */ |  */ | ||||||
| static float x11_sens = 1.0; | static float x11_sens = 1.0; | ||||||
| 
 | 
 | ||||||
|  | static jmp_buf jbuf; | ||||||
|  | 
 | ||||||
| 
 | 
 | ||||||
| int init_x11(void) | int init_x11(void) | ||||||
| { | { | ||||||
|  | @ -77,6 +81,14 @@ int init_x11(void) | ||||||
| 		xdet_start(); | 		xdet_start(); | ||||||
| 		return -1; | 		return -1; | ||||||
| 	} | 	} | ||||||
|  | 
 | ||||||
|  | 	XSetErrorHandler(xerr); | ||||||
|  | 	XSetIOErrorHandler(xioerr); | ||||||
|  | 
 | ||||||
|  | 	if(setjmp(jbuf)) { | ||||||
|  | 		return -1; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
| 	scr_count = ScreenCount(dpy); | 	scr_count = ScreenCount(dpy); | ||||||
| 	screen = DefaultScreen(dpy); | 	screen = DefaultScreen(dpy); | ||||||
| 	root = RootWindow(dpy, screen); | 	root = RootWindow(dpy, screen); | ||||||
|  | @ -127,23 +139,23 @@ void close_x11(void) | ||||||
| 	int i, scr_count; | 	int i, scr_count; | ||||||
| 	struct client *cnode; | 	struct client *cnode; | ||||||
| 
 | 
 | ||||||
| 	if(!dpy) return; | 	if(dpy && setjmp(jbuf) == 0) { | ||||||
|  | 		if(verbose) { | ||||||
|  | 			printf("closing X11 connection to display \"%s\"\n", getenv("DISPLAY")); | ||||||
|  | 		} | ||||||
| 
 | 
 | ||||||
| 	if(verbose) { | 		/* first delete all the CommandEvent properties from all root windows */ | ||||||
| 		printf("closing X11 connection to display \"%s\"\n", getenv("DISPLAY")); | 		scr_count = ScreenCount(dpy); | ||||||
|  | 		for(i=0; i<scr_count; i++) { | ||||||
|  | 			Window root = RootWindow(dpy, i); | ||||||
|  | 			XDeleteProperty(dpy, root, xa_event_cmd); | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		XDestroyWindow(dpy, win); | ||||||
|  | 		XCloseDisplay(dpy); | ||||||
|  | 		dpy = 0; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	/* first delete all the CommandEvent properties from all root windows */ |  | ||||||
| 	scr_count = ScreenCount(dpy); |  | ||||||
| 	for(i=0; i<scr_count; i++) { |  | ||||||
| 		Window root = RootWindow(dpy, i); |  | ||||||
| 		XDeleteProperty(dpy, root, xa_event_cmd); |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	XDestroyWindow(dpy, win); |  | ||||||
| 	XCloseDisplay(dpy); |  | ||||||
| 	dpy = 0; |  | ||||||
| 
 |  | ||||||
| 	/* also remove all x11 clients from the client list */ | 	/* also remove all x11 clients from the client list */ | ||||||
| 	cnode = first_client(); | 	cnode = first_client(); | ||||||
| 	while(cnode) { | 	while(cnode) { | ||||||
|  | @ -164,18 +176,13 @@ int get_x11_socket(void) | ||||||
| void send_xevent(spnav_event *ev, struct client *c) | void send_xevent(spnav_event *ev, struct client *c) | ||||||
| { | { | ||||||
| 	int i; | 	int i; | ||||||
| 	int (*prev_xerr_handler)(Display*, XErrorEvent*); |  | ||||||
| 	XEvent xevent; | 	XEvent xevent; | ||||||
| 
 | 
 | ||||||
| 	if(!dpy) return; | 	if(!dpy) return; | ||||||
| 
 | 
 | ||||||
| 	/* If any of the registered clients exit without notice, we can get a
 | 	if(setjmp(jbuf)) { | ||||||
| 	 * BadWindow exception. Thus we must install a custom handler to avoid | 		return; | ||||||
| 	 * crashing the daemon when that happens. Also catch_badwin (see below) | 	} | ||||||
| 	 * removes that client from the list, to avoid perpetually trying to send |  | ||||||
| 	 * events to an invalid window. |  | ||||||
| 	 */ |  | ||||||
| 	prev_xerr_handler = XSetErrorHandler(catch_badwin); |  | ||||||
| 
 | 
 | ||||||
| 	xevent.type = ClientMessage; | 	xevent.type = ClientMessage; | ||||||
| 	xevent.xclient.send_event = False; | 	xevent.xclient.send_event = False; | ||||||
|  | @ -206,12 +213,7 @@ void send_xevent(spnav_event *ev, struct client *c) | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	XSendEvent(dpy, get_client_window(c), False, 0, &xevent); | 	XSendEvent(dpy, get_client_window(c), False, 0, &xevent); | ||||||
| 
 | 	XFlush(dpy); | ||||||
| 	/* we *must* sync at this point, otherwise, a potential error may arrive
 |  | ||||||
| 	 * after we remove the error handler and crash the daemon. |  | ||||||
| 	 */ |  | ||||||
| 	XSync(dpy, False); |  | ||||||
| 	XSetErrorHandler(prev_xerr_handler); |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| int handle_xevents(fd_set *rset) | int handle_xevents(fd_set *rset) | ||||||
|  | @ -225,6 +227,10 @@ int handle_xevents(fd_set *rset) | ||||||
| 
 | 
 | ||||||
| 	/* process any pending X events */ | 	/* process any pending X events */ | ||||||
| 	if(FD_ISSET(ConnectionNumber(dpy), rset)) { | 	if(FD_ISSET(ConnectionNumber(dpy), rset)) { | ||||||
|  | 		if(setjmp(jbuf)) { | ||||||
|  | 			return 0; | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
| 		while(XPending(dpy)) { | 		while(XPending(dpy)) { | ||||||
| 			XEvent xev; | 			XEvent xev; | ||||||
| 			XNextEvent(dpy, &xev); | 			XNextEvent(dpy, &xev); | ||||||
|  | @ -301,12 +307,19 @@ void remove_client_window(Window win) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| /* X11 error handler for bad-windows */ | /* X11 error handler */ | ||||||
| static int catch_badwin(Display *dpy, XErrorEvent *err) | static int xerr(Display *dpy, XErrorEvent *err) | ||||||
| { | { | ||||||
| 	char buf[256]; | 	char buf[512]; | ||||||
|  | 
 | ||||||
|  | 	if(verbose) { | ||||||
|  | 		fprintf(stderr, "xerr(%p, %p)\n", (void*)dpy, (void*)err); | ||||||
|  | 	} | ||||||
| 
 | 
 | ||||||
| 	if(err->error_code == BadWindow) { | 	if(err->error_code == BadWindow) { | ||||||
|  | 		/* we may get a BadWindow error when trying to send events to
 | ||||||
|  | 		 * clients that have disconnected in the meanwhile. | ||||||
|  | 		 */ | ||||||
| 		remove_client_window((Window)err->resourceid); | 		remove_client_window((Window)err->resourceid); | ||||||
| 	} else { | 	} else { | ||||||
| 		XGetErrorText(dpy, err->error_code, buf, sizeof buf); | 		XGetErrorText(dpy, err->error_code, buf, sizeof buf); | ||||||
|  | @ -315,6 +328,21 @@ static int catch_badwin(Display *dpy, XErrorEvent *err) | ||||||
| 	return 0; | 	return 0; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | /* X11 I/O error handler
 | ||||||
|  |  * This function must not return or xlib will abort. | ||||||
|  |  */ | ||||||
|  | static int xioerr(Display *display) | ||||||
|  | { | ||||||
|  | 	fprintf(stderr, "Lost the X server!\n"); | ||||||
|  | 	dpy = 0; | ||||||
|  | 	close_x11(); | ||||||
|  | 	xdet_start(); | ||||||
|  | 
 | ||||||
|  | 	longjmp(jbuf, 1); | ||||||
|  | 
 | ||||||
|  | 	return 0; | ||||||
|  | } | ||||||
|  | 
 | ||||||
| #else | #else | ||||||
| int spacenavd_proto_x11_shut_up_empty_source_warning; | int spacenavd_proto_x11_shut_up_empty_source_warning; | ||||||
| #endif	/* USE_X11 */ | #endif	/* USE_X11 */ | ||||||
|  |  | ||||||
		Ładowanie…
	
		Reference in New Issue
	
	 John Tsiombikas
						John Tsiombikas