src/spacenav-lib-hack.c
branchv_0
changeset 1 ac5f3768ebb1
parent 0 37aa134ae57b
child 2 3ba27504be0e
equal deleted inserted replaced
0:37aa134ae57b 1:ac5f3768ebb1
       
     1 /**
       
     2  * Spacenav lib hack
       
     3  * Copyright © 2019 František Kučera (Frantovo.cz, GlobalCode.info)
       
     4  *
       
     5  * This program is free software: you can redistribute it and/or modify
       
     6  * it under the terms of the GNU General Public License as published by
       
     7  * the Free Software Foundation, either version 3 of the License, or
       
     8  * (at your option) any later version.
       
     9  *
       
    10  * This program is distributed in the hope that it will be useful,
       
    11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
       
    12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
       
    13  * GNU General Public License for more details.
       
    14  *
       
    15  * You should have received a copy of the GNU General Public License
       
    16  * along with this program. If not, see <http://www.gnu.org/licenses/>.
       
    17  */
       
    18 #define _GNU_SOURCE
       
    19 
       
    20 #include <stdio.h>
       
    21 #include <stdint.h>
       
    22 #include <dlfcn.h>
       
    23 #include <stdlib.h>
       
    24 #include <pthread.h>
       
    25 
       
    26 #include <X11/Xlib.h>
       
    27 #include <spnav.h>
       
    28 
       
    29 static Display* spacenav_hack_dpy;
       
    30 static Window spacenav_hack_win;
       
    31 
       
    32 static pthread_t spacenav_hack_thread;
       
    33 
       
    34 // from proto_x11.c (spacenavd)
       
    35 static Atom xa_event_motion, xa_event_bpress, xa_event_brelease, xa_event_cmd;
       
    36 static float x11_sens = 1.0;
       
    37 
       
    38 /**
       
    39  * This function is based on proto_x11.c (spacenavd) written by:
       
    40  * Copyright (C) 2007-2019 John Tsiombikas <nuclear@member.fsf.org>
       
    41  * and published under GNU GPLv3+
       
    42  * 
       
    43  * @param ev
       
    44  * @param dpy
       
    45  * @param win
       
    46  */
       
    47 static void send_xevent(spnav_event *ev, Display* dpy, Window win) {
       
    48 	int i;
       
    49 	XEvent xevent;
       
    50 
       
    51 	if (!dpy) return;
       
    52 
       
    53 	// if(setjmp(jbuf)) return;
       
    54 
       
    55 	xevent.type = ClientMessage;
       
    56 	xevent.xclient.send_event = False;
       
    57 	xevent.xclient.display = dpy;
       
    58 	xevent.xclient.window = win;
       
    59 
       
    60 	switch (ev->type) {
       
    61 		case SPNAV_EVENT_MOTION:
       
    62 			xevent.xclient.message_type = xa_event_motion;
       
    63 			xevent.xclient.format = 16;
       
    64 
       
    65 			for (i = 0; i < 6; i++) {
       
    66 				float val = (float) ev->motion.data[i] * x11_sens;
       
    67 				xevent.xclient.data.s[i + 2] = (short) val;
       
    68 			}
       
    69 			xevent.xclient.data.s[0] = xevent.xclient.data.s[1] = 0;
       
    70 			xevent.xclient.data.s[8] = ev->motion.period;
       
    71 			break;
       
    72 
       
    73 		case SPNAV_EVENT_BUTTON:
       
    74 			xevent.xclient.message_type = ev->button.press ? xa_event_bpress : xa_event_brelease;
       
    75 			xevent.xclient.format = 16;
       
    76 			xevent.xclient.data.s[2] = ev->button.bnum;
       
    77 			break;
       
    78 
       
    79 		default:
       
    80 			break;
       
    81 	}
       
    82 
       
    83 	XSendEvent(dpy, win, False, 0, &xevent);
       
    84 	XFlush(dpy);
       
    85 }
       
    86 
       
    87 static void* spacenav_hack_translate_events(void* arg) {
       
    88 	pthread_setname_np(pthread_self(), "spacenav-hack"); // can be found with: ps H -o 'pid tid cmd comm'
       
    89 	spnav_event event;
       
    90 	while (1) {
       
    91 		if (spnav_wait_event(&event)) {
       
    92 			//fprintf(stderr, "spnav-lib-hack: got event\n");
       
    93 			XLockDisplay(spacenav_hack_dpy);
       
    94 			send_xevent(&event, spacenav_hack_dpy, spacenav_hack_win);
       
    95 			XUnlockDisplay(spacenav_hack_dpy);
       
    96 		}
       
    97 	}
       
    98 }
       
    99 
       
   100 int spnav_x11_open(Display* dpy, Window win) {
       
   101 	spacenav_hack_dpy = dpy;
       
   102 	spacenav_hack_win = win;
       
   103 
       
   104 	int result = spnav_open();
       
   105 	fprintf(stderr, "spnav-lib-hack: instead of spnav_x11_open(%p, 0x%lx) calling spnav_open() = %d\n", dpy, win, result);
       
   106 
       
   107 	if (result == 0) {
       
   108 		xa_event_motion = XInternAtom(dpy, "MotionEvent", False);
       
   109 		xa_event_bpress = XInternAtom(dpy, "ButtonPressEvent", False);
       
   110 		xa_event_brelease = XInternAtom(dpy, "ButtonReleaseEvent", False);
       
   111 		xa_event_cmd = XInternAtom(dpy, "CommandEvent", False);
       
   112 		
       
   113 		XInitThreads();
       
   114 		pthread_create(&spacenav_hack_thread, NULL, spacenav_hack_translate_events, NULL);
       
   115 	}
       
   116 
       
   117 	return result;
       
   118 }
       
   119 
       
   120 
       
   121 
       
   122 /*
       
   123 int spnav_x11_event(const XEvent* xev, spnav_event* event) {
       
   124 	xev.
       
   125 	static int (*real_spnav_x11_event)(const XEvent*, spnav_event*) = NULL;
       
   126 	if (!real_spnav_x11_event) real_spnav_x11_event = dlsym(RTLD_NEXT, "spnav_x11_event");
       
   127 	int result = real_spnav_x11_event(xev, event);
       
   128 	if (result == SPNAV_EVENT_MOTION || result == SPNAV_EVENT_BUTTON) fprintf(stderr, "spnav-lib-hack: spnav_x11_event() = %d\n", result);
       
   129 	return result;
       
   130 }
       
   131  */
       
   132 
       
   133 
       
   134 /*
       
   135 int spnav_x11_open(Display* dpy, Window win) {
       
   136 	static int (*real_spnav_x11_open)(Display*, Window) = NULL;
       
   137 	if (!real_spnav_x11_open) real_spnav_x11_open = dlsym(RTLD_NEXT, "spnav_x11_open");
       
   138 	int result = real_spnav_x11_open(dpy, win);
       
   139 	fprintf(stderr, "spnav-lib-hack: spnav_x11_open() = %d\n", result);
       
   140 	return result;
       
   141 }
       
   142  */
       
   143 
       
   144 
       
   145 /*
       
   146 int spnav_open() {
       
   147 	return -1;
       
   148 }
       
   149  */
       
   150 
       
   151 /*
       
   152 int spnav_open() {
       
   153 	static int (*real_spnav_open)() = NULL;
       
   154 	if (!real_spnav_open) real_spnav_open = dlsym(RTLD_NEXT, "spnav_open");
       
   155 	int result = real_spnav_open();
       
   156 	// fprintf(stderr, "spnav-lib-hack: spnav_open() = %d\n", result);
       
   157 	return result;
       
   158 }
       
   159  */