19 |
19 |
20 #include <stdio.h> |
20 #include <stdio.h> |
21 #include <stdint.h> |
21 #include <stdint.h> |
22 #include <dlfcn.h> |
22 #include <dlfcn.h> |
23 #include <stdlib.h> |
23 #include <stdlib.h> |
24 #include <pthread.h> |
24 #include <unistd.h> |
25 |
25 |
26 #include <X11/Xlib.h> |
26 #include <X11/Xlib.h> |
27 #include <spnav.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 |
28 |
34 // from proto_x11.c (spacenavd) |
29 // from proto_x11.c (spacenavd) |
35 static Atom xa_event_motion, xa_event_bpress, xa_event_brelease, xa_event_cmd; |
30 static Atom xa_event_motion, xa_event_bpress, xa_event_brelease, xa_event_cmd; |
36 static float x11_sens = 1.0; |
31 static float x11_sens = 1.0; |
|
32 |
|
33 /* X11 error handler */ |
|
34 static int xerr(Display *dpy, XErrorEvent *err) { |
|
35 char buf[512]; |
|
36 |
|
37 fprintf(stderr, "xerr(%p, %p)\n", (void*) dpy, (void*) err); |
|
38 if (err->error_code == BadWindow) { |
|
39 fprintf(stderr, "BadWindow\n"); |
|
40 } else { |
|
41 XGetErrorText(dpy, err->error_code, buf, sizeof buf); |
|
42 fprintf(stderr, "Caught unexpected X error: %s\n", buf); |
|
43 } |
|
44 return 0; |
|
45 } |
|
46 |
|
47 /* X11 I/O error handler |
|
48 * This function must not return or xlib will abort. |
|
49 */ |
|
50 static int xioerr(Display *display) { |
|
51 fprintf(stderr, "Lost the X server!\n"); |
|
52 return 0; |
|
53 } |
37 |
54 |
38 /** |
55 /** |
39 * This function is based on proto_x11.c (spacenavd) written by: |
56 * This function is based on proto_x11.c (spacenavd) written by: |
40 * Copyright (C) 2007-2019 John Tsiombikas <nuclear@member.fsf.org> |
57 * Copyright (C) 2007-2019 John Tsiombikas <nuclear@member.fsf.org> |
41 * and published under GNU GPLv3+ |
58 * and published under GNU GPLv3+ |
78 |
95 |
79 default: |
96 default: |
80 break; |
97 break; |
81 } |
98 } |
82 |
99 |
83 XSendEvent(dpy, win, False, 0, &xevent); |
100 Window xxx; |
84 XFlush(dpy); |
101 int zzz; |
85 } |
102 int yyy = XGetInputFocus(dpy, &xxx, &zzz); |
86 |
103 fprintf(stderr, "spnav-lib-hack: XGetInputFocus(%p, %lx, %d) = %d\n", dpy, xxx, zzz, yyy); |
87 static void* spacenav_hack_translate_events(void* arg) { |
104 Status result = XSendEvent(dpy, win, False, 0, &xevent); |
88 pthread_setname_np(pthread_self(), "spacenav-hack"); // can be found with: ps H -o 'pid tid cmd comm' |
105 int xflushResult = XFlush(dpy); |
|
106 fprintf(stderr, "spnav-lib-hack: send_xevent(); XSendEvent() = %d; XFlush() = %d\n", result, xflushResult); |
|
107 } |
|
108 |
|
109 static void spacenav_hack_translate_events(Window win) { |
89 spnav_event event; |
110 spnav_event event; |
|
111 Display* dpy = XOpenDisplay(0); |
|
112 XSetErrorHandler(xerr); |
|
113 XSetIOErrorHandler(xioerr); |
|
114 fprintf(stderr, "Error handlers were set\n"); |
|
115 |
|
116 /* |
|
117 xa_event_motion = XInternAtom(dpy, "MotionEvent", False); |
|
118 xa_event_bpress = XInternAtom(dpy, "ButtonPressEvent", False); |
|
119 xa_event_brelease = XInternAtom(dpy, "ButtonReleaseEvent", False); |
|
120 xa_event_cmd = XInternAtom(dpy, "CommandEvent", False); |
|
121 */ |
|
122 |
|
123 fprintf(stderr, "spnav-lib-hack: xa_event_motion = %ld\n", xa_event_motion); |
|
124 fprintf(stderr, "spnav-lib-hack: xa_event_bpress = %ld\n", xa_event_bpress); |
|
125 fprintf(stderr, "spnav-lib-hack: xa_event_brelease = %ld\n", xa_event_brelease); |
|
126 fprintf(stderr, "spnav-lib-hack: xa_event_cmd = %ld\n", xa_event_cmd); |
|
127 |
90 while (1) { |
128 while (1) { |
91 if (spnav_wait_event(&event)) { |
129 if (spnav_wait_event(&event)) { |
92 //fprintf(stderr, "spnav-lib-hack: got event\n"); |
130 fprintf(stderr, "spnav-lib-hack: got event: PID=%d dpy=%p win=%lx\n", getpid(), dpy, win); |
93 XLockDisplay(spacenav_hack_dpy); |
131 //XLockDisplay(dpy); |
94 send_xevent(&event, spacenav_hack_dpy, spacenav_hack_win); |
132 send_xevent(&event, dpy, win); |
95 XUnlockDisplay(spacenav_hack_dpy); |
133 //XUnlockDisplay(dpy); |
96 } |
134 } |
97 } |
135 } |
98 } |
136 } |
99 |
137 |
100 int spnav_x11_open(Display* dpy, Window win) { |
138 int spnav_x11_open(Display* dpy, Window win) { |
101 spacenav_hack_dpy = dpy; |
|
102 spacenav_hack_win = win; |
|
103 |
|
104 int result = spnav_open(); |
139 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); |
140 fprintf(stderr, "spnav-lib-hack: instead of spnav_x11_open(%p, 0x%lx) calling spnav_open() = %d\n", dpy, win, result); |
106 |
141 |
|
142 xa_event_motion = XInternAtom(dpy, "MotionEvent", False); |
|
143 xa_event_bpress = XInternAtom(dpy, "ButtonPressEvent", False); |
|
144 xa_event_brelease = XInternAtom(dpy, "ButtonReleaseEvent", False); |
|
145 xa_event_cmd = XInternAtom(dpy, "CommandEvent", False); |
|
146 |
107 if (result == 0) { |
147 if (result == 0) { |
108 xa_event_motion = XInternAtom(dpy, "MotionEvent", False); |
148 pid_t pid = fork(); |
109 xa_event_bpress = XInternAtom(dpy, "ButtonPressEvent", False); |
149 fprintf(stderr, "spnav-lib-hack: fork() = %d; PID=%d\n", pid, getpid()); |
110 xa_event_brelease = XInternAtom(dpy, "ButtonReleaseEvent", False); |
150 if (pid == -1) return 1; |
111 xa_event_cmd = XInternAtom(dpy, "CommandEvent", False); |
151 if (pid == 0) spacenav_hack_translate_events(win); |
112 |
152 } |
113 XInitThreads(); |
153 |
114 pthread_create(&spacenav_hack_thread, NULL, spacenav_hack_translate_events, NULL); |
154 return result; |
115 } |
155 } |
116 |
156 |
117 return result; |
157 /** |
118 } |
158 * This function is based on proto_x11.c (spacenavd) written by: |
119 |
159 * Copyright (C) 2007-2019 John Tsiombikas <nuclear@member.fsf.org> |
120 |
160 * and published under GNU GPLv3+ |
121 |
161 * |
122 /* |
162 * @param dpy |
|
163 * @param win |
|
164 * @return |
|
165 */ |
123 int spnav_x11_event(const XEvent* xev, spnav_event* event) { |
166 int spnav_x11_event(const XEvent* xev, spnav_event* event) { |
124 xev. |
167 /* |
|
168 * Because real spnav_x11_open() was not called, the library has not initialized xa_event_* |
|
169 * variables and thus will return 0 (= not a spacenav event). |
|
170 */ |
|
171 |
|
172 int i; |
|
173 int xmsg_type; |
|
174 |
|
175 if (xev->type != ClientMessage) { |
|
176 return 0; |
|
177 } |
|
178 |
|
179 xmsg_type = xev->xclient.message_type; |
|
180 |
|
181 if (xmsg_type != xa_event_motion && xmsg_type != xa_event_bpress && |
|
182 xmsg_type != xa_event_brelease) { |
|
183 return 0; |
|
184 } |
|
185 |
|
186 if (xmsg_type == xa_event_motion) { |
|
187 event->type = SPNAV_EVENT_MOTION; |
|
188 event->motion.data = &event->motion.x; |
|
189 |
|
190 for (i = 0; i < 6; i++) { |
|
191 event->motion.data[i] = xev->xclient.data.s[i + 2]; |
|
192 } |
|
193 event->motion.period = xev->xclient.data.s[8]; |
|
194 } else { |
|
195 event->type = SPNAV_EVENT_BUTTON; |
|
196 event->button.press = xmsg_type == xa_event_bpress ? 1 : 0; |
|
197 event->button.bnum = xev->xclient.data.s[2]; |
|
198 } |
|
199 return event->type; |
|
200 |
|
201 /* |
125 static int (*real_spnav_x11_event)(const XEvent*, spnav_event*) = NULL; |
202 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"); |
203 if (!real_spnav_x11_event) real_spnav_x11_event = dlsym(RTLD_NEXT, "spnav_x11_event"); |
127 int result = real_spnav_x11_event(xev, event); |
204 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); |
205 if (result == SPNAV_EVENT_MOTION || result == SPNAV_EVENT_BUTTON) fprintf(stderr, "spnav-lib-hack: spnav_x11_event() = %d\n", result); |
129 return result; |
206 return result; |
130 } |
207 */ |
131 */ |
208 } |
132 |
209 |
133 |
210 |
134 /* |
211 /* |
135 int spnav_x11_open(Display* dpy, Window win) { |
212 int spnav_x11_open(Display* dpy, Window win) { |
136 static int (*real_spnav_x11_open)(Display*, Window) = NULL; |
213 static int (*real_spnav_x11_open)(Display*, Window) = NULL; |