- 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-baaf7b16a646
pull/1/head
John Tsiombikas 2010-02-27 23:49:56 +00:00
rodzic f6a10f2786
commit cd5312cd39
4 zmienionych plików z 120 dodań i 51 usunięć

Wyświetl plik

@ -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/>.
*/
#include "config.h"
#include <stdio.h>
#include <stdlib.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};
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)
{
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->led = 1;
for(i=0; i<6; i++) {
cfg->invert[i] = axinv[i];
cfg->map_axis[i] = axmap[i];
cfg->invert[i] = def_axinv[i];
cfg->map_axis[i] = def_axmap[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);
} 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) {
if(strchr(val_str, 'x')) {
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];
}
} 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) {
if(isnum) {
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 = %.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 = %d\n\n", cfg->dead_threshold);
if(cfg->invert[0] || cfg->invert[1] || cfg->invert[2]) {
fprintf(fp, "# invert translations on some axes.\n");
fprintf(fp, "invert-trans = ");
if(cfg->invert[0]) fputc('x', fp);
if(cfg->invert[1]) fputc('y', fp);
if(cfg->invert[2]) fputc('z', fp);
if(cfg->invert[0] != def_axinv[0]) fputc('x', fp);
if(cfg->invert[1] != def_axinv[1]) fputc('y', fp);
if(cfg->invert[2] != def_axinv[2]) fputc('z', fp);
fputs("\n\n", fp);
}
if(cfg->invert[3] || cfg->invert[4] || cfg->invert[5]) {
fprintf(fp, "# invert rotations around some axes.\n");
fprintf(fp, "invert-rot = ");
if(cfg->invert[3]) fputc('x', fp);
if(cfg->invert[4]) fputc('y', fp);
if(cfg->invert[5]) fputc('z', fp);
if(cfg->invert[3] != def_axinv[3]) fputc('x', fp);
if(cfg->invert[4] != def_axinv[4]) fputc('y', fp);
if(cfg->invert[5] != def_axinv[5]) fputc('z', 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) {
fprintf(fp, "# disable led\n");
fprintf(fp, "led = 0\n\n");

Wyświetl plik

@ -19,12 +19,10 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#ifndef CFGFILE_H_
#define CFGFILE_H_
#include "config.h"
#define MAX_BUTTONS 64
struct cfg {
float sensitivity;
float sensitivity, sens_trans, sens_rot;
int dead_threshold;
int invert[6];
int map_axis[6];

Wyświetl plik

@ -55,9 +55,7 @@ void process_input(struct dev_input *inp)
inp->idx = cfg.map_axis[inp->idx];
sign = cfg.invert[inp->idx] ? -1 : 1;
if(cfg.sensitivity != 1.0) {
inp->val = (int)((float)inp->val * cfg.sensitivity);
}
inp->val = (int)((float)inp->val * cfg.sensitivity * (inp->idx < 3 ? cfg.sens_trans : cfg.sens_rot));
ev.type = EVENT_MOTION;
ev.motion.data = (int*)&ev.motion.x;
@ -71,7 +69,7 @@ void process_input(struct dev_input *inp)
ev_pending = 0;
}
inp->idx = cfg.map_button[inp->idx];
ev.type = EVENT_BUTTON;
ev.button.press = inp->val;
ev.button.bnum = inp->idx;

Wyświetl plik

@ -21,6 +21,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#ifdef USE_X11
#include <stdio.h>
#include <stdlib.h>
#include <setjmp.h>
#include "proto_x11.h"
#include "client.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 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 jmp_buf jbuf;
int init_x11(void)
{
@ -77,6 +81,14 @@ int init_x11(void)
xdet_start();
return -1;
}
XSetErrorHandler(xerr);
XSetIOErrorHandler(xioerr);
if(setjmp(jbuf)) {
return -1;
}
scr_count = ScreenCount(dpy);
screen = DefaultScreen(dpy);
root = RootWindow(dpy, screen);
@ -127,23 +139,23 @@ void close_x11(void)
int i, scr_count;
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) {
printf("closing X11 connection to display \"%s\"\n", getenv("DISPLAY"));
/* 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;
}
/* 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 */
cnode = first_client();
while(cnode) {
@ -164,18 +176,13 @@ int get_x11_socket(void)
void send_xevent(spnav_event *ev, struct client *c)
{
int i;
int (*prev_xerr_handler)(Display*, XErrorEvent*);
XEvent xevent;
if(!dpy) return;
/* If any of the registered clients exit without notice, we can get a
* BadWindow exception. Thus we must install a custom handler to avoid
* 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);
if(setjmp(jbuf)) {
return;
}
xevent.type = ClientMessage;
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);
/* 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);
XFlush(dpy);
}
int handle_xevents(fd_set *rset)
@ -225,6 +227,10 @@ int handle_xevents(fd_set *rset)
/* process any pending X events */
if(FD_ISSET(ConnectionNumber(dpy), rset)) {
if(setjmp(jbuf)) {
return 0;
}
while(XPending(dpy)) {
XEvent xev;
XNextEvent(dpy, &xev);
@ -301,12 +307,19 @@ void remove_client_window(Window win)
}
/* X11 error handler for bad-windows */
static int catch_badwin(Display *dpy, XErrorEvent *err)
/* X11 error handler */
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) {
/* 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);
} else {
XGetErrorText(dpy, err->error_code, buf, sizeof buf);
@ -315,6 +328,21 @@ static int catch_badwin(Display *dpy, XErrorEvent *err)
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
int spacenavd_proto_x11_shut_up_empty_source_warning;
#endif /* USE_X11 */