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;
|
||||||
|
|
|
||||||
|
|
@ -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