rev |
line source |
nuclear@0
|
1 #include <stdio.h>
|
nuclear@0
|
2 #include <stdlib.h>
|
nuclear@4
|
3 #include <float.h>
|
nuclear@0
|
4 #include <assert.h>
|
nuclear@0
|
5 #include <errno.h>
|
nuclear@0
|
6 #include <unistd.h>
|
nuclear@0
|
7 #include <sys/select.h>
|
nuclear@0
|
8 #include <GL/glew.h>
|
nuclear@0
|
9 #include <X11/Xlib.h>
|
nuclear@0
|
10 #include <GL/glx.h>
|
nuclear@1
|
11 #include "dev.h"
|
nuclear@4
|
12 #include "scene.h"
|
nuclear@0
|
13
|
nuclear@0
|
14 static bool init();
|
nuclear@0
|
15 static void cleanup();
|
nuclear@0
|
16 static void display();
|
nuclear@0
|
17 static void keyb(int key, bool pressed);
|
nuclear@0
|
18 static void mouse(int bn, bool pressed, int x, int y);
|
nuclear@0
|
19 static void motion(int x, int y);
|
nuclear@4
|
20 static Ray calc_pick_ray(int x, int y);
|
nuclear@0
|
21
|
nuclear@0
|
22 static Window create_window(const char *title, int xsz, int ysz);
|
nuclear@0
|
23 static void process_events();
|
nuclear@0
|
24 static int translate_keysym(KeySym sym);
|
nuclear@0
|
25
|
nuclear@2
|
26 static int proc_args(int argc, char **argv);
|
nuclear@2
|
27
|
nuclear@0
|
28 static Display *dpy;
|
nuclear@0
|
29 static Window win;
|
nuclear@0
|
30 static GLXContext ctx;
|
nuclear@0
|
31 static Atom xa_wm_prot, xa_wm_del_win;
|
nuclear@0
|
32
|
nuclear@0
|
33 static int win_width, win_height;
|
nuclear@0
|
34
|
nuclear@4
|
35 static bool draw_pending;
|
nuclear@0
|
36 static bool win_mapped;
|
nuclear@0
|
37
|
nuclear@2
|
38 static int fakefd = -1;
|
nuclear@2
|
39 static char *fake_devpath;
|
nuclear@2
|
40
|
nuclear@4
|
41 static float cam_theta, cam_phi, cam_dist = 140;
|
nuclear@4
|
42 static Scene *scn;
|
nuclear@4
|
43
|
nuclear@4
|
44 enum { BN_TICKET, BN_NEXT, NUM_BUTTONS };
|
nuclear@6
|
45 static const char *button_names[] = { "button1", "button2" };
|
nuclear@4
|
46 static Object *button_obj[NUM_BUTTONS];
|
nuclear@6
|
47 static Object *disp_obj[2];
|
nuclear@6
|
48 static Object *led_obj[2];
|
nuclear@6
|
49 static Vector3 led_on_emissive;
|
nuclear@4
|
50
|
nuclear@2
|
51 int main(int argc, char **argv)
|
nuclear@0
|
52 {
|
nuclear@2
|
53 if(proc_args(argc, argv) == -1) {
|
nuclear@2
|
54 return 1;
|
nuclear@2
|
55 }
|
nuclear@0
|
56 if(!init()) {
|
nuclear@0
|
57 return 1;
|
nuclear@0
|
58 }
|
nuclear@0
|
59 atexit(cleanup);
|
nuclear@0
|
60
|
nuclear@0
|
61 int xfd = ConnectionNumber(dpy);
|
nuclear@0
|
62
|
nuclear@4
|
63 // run once through pending events before going into the select loop
|
nuclear@4
|
64 process_events();
|
nuclear@4
|
65
|
nuclear@0
|
66 for(;;) {
|
nuclear@0
|
67 fd_set rd;
|
nuclear@0
|
68 FD_ZERO(&rd);
|
nuclear@0
|
69
|
nuclear@0
|
70 FD_SET(xfd, &rd);
|
nuclear@2
|
71 FD_SET(fakefd, &rd);
|
nuclear@0
|
72
|
nuclear@4
|
73 struct timeval noblock = {0, 0};
|
nuclear@2
|
74 int maxfd = xfd > fakefd ? xfd : fakefd;
|
nuclear@4
|
75 while(select(maxfd + 1, &rd, 0, 0, draw_pending ? &noblock : 0) == -1 && errno == EINTR);
|
nuclear@0
|
76
|
nuclear@0
|
77 if(FD_ISSET(xfd, &rd)) {
|
nuclear@0
|
78 process_events();
|
nuclear@0
|
79 }
|
nuclear@2
|
80 if(FD_ISSET(fakefd, &rd)) {
|
nuclear@2
|
81 proc_dev_input();
|
nuclear@2
|
82 }
|
nuclear@0
|
83
|
nuclear@4
|
84 if(draw_pending) {
|
nuclear@0
|
85 display();
|
nuclear@4
|
86 draw_pending = false;
|
nuclear@0
|
87 }
|
nuclear@0
|
88 }
|
nuclear@0
|
89 return 0;
|
nuclear@0
|
90 }
|
nuclear@0
|
91
|
nuclear@0
|
92 static bool init()
|
nuclear@0
|
93 {
|
nuclear@2
|
94 if(fake_devpath) {
|
nuclear@2
|
95 if((fakefd = start_dev(fake_devpath)) == -1) {
|
nuclear@2
|
96 return false;
|
nuclear@2
|
97 }
|
nuclear@2
|
98 }
|
nuclear@1
|
99
|
nuclear@0
|
100 if(!(dpy = XOpenDisplay(0))) {
|
nuclear@0
|
101 fprintf(stderr, "failed to connect to the X server!\n");
|
nuclear@0
|
102 return false;
|
nuclear@0
|
103 }
|
nuclear@0
|
104
|
nuclear@4
|
105 if(!(win = create_window("equeue device emulator", 800, 600))) {
|
nuclear@0
|
106 return false;
|
nuclear@0
|
107 }
|
nuclear@0
|
108
|
nuclear@4
|
109 glewInit();
|
nuclear@4
|
110
|
nuclear@4
|
111 scn = new Scene;
|
nuclear@4
|
112 if(!scn->load("data/device.obj")) {
|
nuclear@4
|
113 fprintf(stderr, "failed to load device 3D model\n");
|
nuclear@4
|
114 return false;
|
nuclear@4
|
115 }
|
nuclear@4
|
116
|
nuclear@4
|
117 for(int i=0; i<NUM_BUTTONS; i++) {
|
nuclear@4
|
118 button_obj[i] = scn->get_object(button_names[i]);
|
nuclear@4
|
119 if(!button_obj[i]) {
|
nuclear@4
|
120 fprintf(stderr, "invalid 3D model\n");
|
nuclear@4
|
121 return false;
|
nuclear@4
|
122 }
|
nuclear@4
|
123 BSphere &bs = button_obj[i]->get_mesh()->get_bounds();
|
nuclear@4
|
124 bs.set_radius(bs.get_radius() * 1.5);
|
nuclear@4
|
125 }
|
nuclear@4
|
126
|
nuclear@6
|
127 disp_obj[0] = scn->get_object("7seg0");
|
nuclear@6
|
128 disp_obj[1] = scn->get_object("7seg1");
|
nuclear@6
|
129 if(!disp_obj[0] || !disp_obj[1]) {
|
nuclear@6
|
130 fprintf(stderr, "invalid 3D model\n");
|
nuclear@6
|
131 return false;
|
nuclear@6
|
132 }
|
nuclear@6
|
133 scn->remove_object(disp_obj[0]);
|
nuclear@6
|
134 scn->remove_object(disp_obj[1]);
|
nuclear@6
|
135
|
nuclear@6
|
136 led_obj[0] = scn->get_object("led1");
|
nuclear@6
|
137 led_obj[1] = scn->get_object("led2");
|
nuclear@6
|
138 if(!led_obj[0] || !led_obj[1]) {
|
nuclear@6
|
139 fprintf(stderr, "invalid 3D model\n");
|
nuclear@6
|
140 return false;
|
nuclear@6
|
141 }
|
nuclear@6
|
142 scn->remove_object(led_obj[0]);
|
nuclear@6
|
143 scn->remove_object(led_obj[1]);
|
nuclear@6
|
144 led_on_emissive = led_obj[0]->mtl.emissive;
|
nuclear@6
|
145
|
nuclear@4
|
146 glEnable(GL_DEPTH_TEST);
|
nuclear@4
|
147 glEnable(GL_CULL_FACE);
|
nuclear@4
|
148 glEnable(GL_LIGHTING);
|
nuclear@4
|
149 glEnable(GL_LIGHT0);
|
nuclear@4
|
150
|
nuclear@4
|
151 glClearColor(0.1, 0.1, 0.1, 1);
|
nuclear@4
|
152
|
nuclear@0
|
153 return true;
|
nuclear@0
|
154 }
|
nuclear@0
|
155
|
nuclear@0
|
156 static void cleanup()
|
nuclear@0
|
157 {
|
nuclear@4
|
158 delete scn;
|
nuclear@4
|
159
|
nuclear@1
|
160 stop_dev();
|
nuclear@1
|
161
|
nuclear@0
|
162 if(!dpy) return;
|
nuclear@0
|
163
|
nuclear@0
|
164 if(win) {
|
nuclear@0
|
165 XDestroyWindow(dpy, win);
|
nuclear@0
|
166 }
|
nuclear@0
|
167 XCloseDisplay(dpy);
|
nuclear@0
|
168 }
|
nuclear@0
|
169
|
nuclear@6
|
170 #define DIGIT_USZ (1.0 / 11.0)
|
nuclear@6
|
171
|
nuclear@0
|
172 static void display()
|
nuclear@0
|
173 {
|
nuclear@0
|
174 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
nuclear@0
|
175
|
nuclear@0
|
176 glMatrixMode(GL_MODELVIEW);
|
nuclear@0
|
177 glLoadIdentity();
|
nuclear@4
|
178 glTranslatef(0, 0, -cam_dist);
|
nuclear@4
|
179 glRotatef(cam_phi, 1, 0, 0);
|
nuclear@4
|
180 glRotatef(cam_theta, 0, 1, 0);
|
nuclear@4
|
181
|
nuclear@4
|
182 float lpos[] = {-7, 5, 10, 0};
|
nuclear@4
|
183 glLightfv(GL_LIGHT0, GL_POSITION, lpos);
|
nuclear@4
|
184
|
nuclear@4
|
185 scn->render();
|
nuclear@0
|
186
|
nuclear@6
|
187 // shift the textures and modify the materials to make the display match our state
|
nuclear@6
|
188 for(int i=0; i<2; i++) {
|
nuclear@6
|
189 int digit = get_display_number();
|
nuclear@6
|
190 for(int j=0; j<i; j++) {
|
nuclear@6
|
191 digit /= 10;
|
nuclear@6
|
192 }
|
nuclear@6
|
193 digit %= 10;
|
nuclear@6
|
194
|
nuclear@6
|
195 float uoffs = DIGIT_USZ + DIGIT_USZ * digit;
|
nuclear@6
|
196
|
nuclear@6
|
197 disp_obj[i]->mtl.tex_offset[TEX_DIFFUSE] = Vector2(uoffs, 0);
|
nuclear@6
|
198 disp_obj[i]->render();
|
nuclear@6
|
199
|
nuclear@6
|
200 // LEDs
|
nuclear@6
|
201 if(get_led_state(i)) {
|
nuclear@6
|
202 led_obj[i]->mtl.emissive = led_on_emissive;
|
nuclear@6
|
203 } else {
|
nuclear@6
|
204 led_obj[i]->mtl.emissive = Vector3(0, 0, 0);
|
nuclear@6
|
205 }
|
nuclear@6
|
206 led_obj[i]->render();
|
nuclear@6
|
207 }
|
nuclear@6
|
208
|
nuclear@0
|
209 glXSwapBuffers(dpy, win);
|
nuclear@0
|
210 assert(glGetError() == GL_NO_ERROR);
|
nuclear@0
|
211 }
|
nuclear@0
|
212
|
nuclear@0
|
213 static void reshape(int x, int y)
|
nuclear@0
|
214 {
|
nuclear@0
|
215 glViewport(0, 0, x, y);
|
nuclear@0
|
216
|
nuclear@0
|
217 glMatrixMode(GL_PROJECTION);
|
nuclear@0
|
218 glLoadIdentity();
|
nuclear@4
|
219 gluPerspective(50.0, (float)x / (float)y, 1.0, 1000.0);
|
nuclear@4
|
220
|
nuclear@4
|
221 win_width = x;
|
nuclear@4
|
222 win_height = y;
|
nuclear@0
|
223 }
|
nuclear@0
|
224
|
nuclear@0
|
225 static void keyb(int key, bool pressed)
|
nuclear@0
|
226 {
|
nuclear@0
|
227 if(pressed) {
|
nuclear@0
|
228 switch(key) {
|
nuclear@0
|
229 case 27:
|
nuclear@0
|
230 exit(0);
|
nuclear@0
|
231 }
|
nuclear@0
|
232 }
|
nuclear@0
|
233 }
|
nuclear@0
|
234
|
nuclear@4
|
235 static bool bnstate[32];
|
nuclear@4
|
236 static int prev_x, prev_y;
|
nuclear@4
|
237
|
nuclear@0
|
238 static void mouse(int bn, bool pressed, int x, int y)
|
nuclear@0
|
239 {
|
nuclear@4
|
240 bnstate[bn] = pressed;
|
nuclear@4
|
241 prev_x = x;
|
nuclear@4
|
242 prev_y = y;
|
nuclear@4
|
243
|
nuclear@4
|
244 if(bn == 0 && pressed) {
|
nuclear@4
|
245 // do picking
|
nuclear@4
|
246 Ray ray = calc_pick_ray(x, win_height - y);
|
nuclear@4
|
247
|
nuclear@4
|
248 HitPoint minhit;
|
nuclear@4
|
249 minhit.t = FLT_MAX;
|
nuclear@4
|
250 int hit_found = -1;
|
nuclear@4
|
251
|
nuclear@4
|
252 for(int i=0; i<NUM_BUTTONS; i++) {
|
nuclear@4
|
253 HitPoint hit;
|
nuclear@4
|
254 if(button_obj[i]->get_mesh()->get_bounds().intersect(ray, &hit) && hit.t < minhit.t) {
|
nuclear@4
|
255 minhit = hit;
|
nuclear@4
|
256 hit_found = i;
|
nuclear@4
|
257 }
|
nuclear@4
|
258 }
|
nuclear@4
|
259
|
nuclear@4
|
260 if(hit_found != -1) {
|
nuclear@4
|
261 switch(hit_found) {
|
nuclear@4
|
262 case BN_TICKET:
|
nuclear@4
|
263 issue_ticket();
|
nuclear@4
|
264 printf("issue ticket\n");
|
nuclear@4
|
265 break;
|
nuclear@4
|
266
|
nuclear@4
|
267 case BN_NEXT:
|
nuclear@4
|
268 next_customer();
|
nuclear@4
|
269 printf("next customer\n");
|
nuclear@4
|
270 break;
|
nuclear@4
|
271 }
|
nuclear@4
|
272 draw_pending = true;
|
nuclear@4
|
273 }
|
nuclear@4
|
274 }
|
nuclear@0
|
275 }
|
nuclear@0
|
276
|
nuclear@0
|
277 static void motion(int x, int y)
|
nuclear@0
|
278 {
|
nuclear@4
|
279 int dx = x - prev_x;
|
nuclear@4
|
280 int dy = y - prev_y;
|
nuclear@4
|
281 prev_x = x;
|
nuclear@4
|
282 prev_y = y;
|
nuclear@4
|
283
|
nuclear@4
|
284 if(bnstate[0]) {
|
nuclear@4
|
285 cam_theta += dx * 0.5;
|
nuclear@4
|
286 cam_phi += dy * 0.5;
|
nuclear@4
|
287 if(cam_phi < -90) cam_phi = -90;
|
nuclear@4
|
288 if(cam_phi > 90) cam_phi = 90;
|
nuclear@6
|
289
|
nuclear@6
|
290 } else if(bnstate[2]) {
|
nuclear@4
|
291 cam_dist += dy * 0.5;
|
nuclear@4
|
292 if(cam_dist < 0.0) cam_dist = 0.0;
|
nuclear@6
|
293
|
nuclear@6
|
294 } else {
|
nuclear@6
|
295 float xoffs = 2.0 * x / win_width - 1.0;
|
nuclear@6
|
296 float yoffs = 2.0 * y / win_height - 1.0;
|
nuclear@6
|
297 cam_theta = -xoffs * 15.0 * (win_width / win_height);
|
nuclear@6
|
298 cam_phi = -yoffs * 15.0;
|
nuclear@4
|
299 }
|
nuclear@6
|
300 draw_pending = true;
|
nuclear@4
|
301 }
|
nuclear@4
|
302
|
nuclear@4
|
303 static Ray calc_pick_ray(int x, int y)
|
nuclear@4
|
304 {
|
nuclear@4
|
305 double mv[16], proj[16];
|
nuclear@4
|
306 int vp[4];
|
nuclear@4
|
307 double resx, resy, resz;
|
nuclear@4
|
308 Ray ray;
|
nuclear@4
|
309
|
nuclear@4
|
310 glGetDoublev(GL_MODELVIEW_MATRIX, mv);
|
nuclear@4
|
311 glGetDoublev(GL_PROJECTION_MATRIX, proj);
|
nuclear@4
|
312 glGetIntegerv(GL_VIEWPORT, vp);
|
nuclear@4
|
313
|
nuclear@4
|
314 gluUnProject(x, y, 0, mv, proj, vp, &resx, &resy, &resz);
|
nuclear@4
|
315 ray.origin = Vector3(resx, resy, resz);
|
nuclear@4
|
316
|
nuclear@4
|
317 gluUnProject(x, y, 1, mv, proj, vp, &resx, &resy, &resz);
|
nuclear@4
|
318 ray.dir = normalize(Vector3(resx, resy, resz) - ray.origin);
|
nuclear@4
|
319
|
nuclear@4
|
320 return ray;
|
nuclear@0
|
321 }
|
nuclear@0
|
322
|
nuclear@0
|
323 static Window create_window(const char *title, int xsz, int ysz)
|
nuclear@0
|
324 {
|
nuclear@0
|
325 int scr = DefaultScreen(dpy);
|
nuclear@0
|
326 Window root = RootWindow(dpy, scr);
|
nuclear@0
|
327
|
nuclear@0
|
328 int glxattr[] = {
|
nuclear@0
|
329 GLX_RGBA,
|
nuclear@0
|
330 GLX_RED_SIZE, 8,
|
nuclear@0
|
331 GLX_GREEN_SIZE, 8,
|
nuclear@0
|
332 GLX_BLUE_SIZE, 8,
|
nuclear@0
|
333 GLX_DEPTH_SIZE, 24,
|
nuclear@0
|
334 GLX_DOUBLEBUFFER,
|
nuclear@0
|
335 #if defined(GLX_VERSION_1_4) || defined(GLX_ARB_multisample)
|
nuclear@0
|
336 GLX_SAMPLE_BUFFERS_ARB, 1,
|
nuclear@0
|
337 GLX_SAMPLES_ARB, 1,
|
nuclear@0
|
338 #endif
|
nuclear@0
|
339 None
|
nuclear@0
|
340 };
|
nuclear@0
|
341
|
nuclear@0
|
342 XVisualInfo *vis = glXChooseVisual(dpy, scr, glxattr);
|
nuclear@0
|
343 if(!vis) {
|
nuclear@0
|
344 fprintf(stderr, "failed to find a suitable visual\n");
|
nuclear@0
|
345 return 0;
|
nuclear@0
|
346 }
|
nuclear@0
|
347
|
nuclear@0
|
348 if(!(ctx = glXCreateContext(dpy, vis, 0, True))) {
|
nuclear@0
|
349 fprintf(stderr, "failed to create OpenGL context\n");
|
nuclear@0
|
350 XFree(vis);
|
nuclear@0
|
351 return -1;
|
nuclear@0
|
352 }
|
nuclear@0
|
353
|
nuclear@0
|
354 XSetWindowAttributes xattr;
|
nuclear@0
|
355 xattr.background_pixel = xattr.border_pixel = BlackPixel(dpy, scr);
|
nuclear@0
|
356 xattr.colormap = XCreateColormap(dpy, root, vis->visual, AllocNone);
|
nuclear@0
|
357 unsigned int xattr_mask = CWColormap | CWBackPixel | CWBorderPixel;
|
nuclear@0
|
358
|
nuclear@0
|
359 Window win = XCreateWindow(dpy, root, 0, 0, xsz, ysz, 0, vis->depth, InputOutput,
|
nuclear@0
|
360 vis->visual, xattr_mask, &xattr);
|
nuclear@0
|
361 if(!win) {
|
nuclear@0
|
362 fprintf(stderr, "failed to create window\n");
|
nuclear@0
|
363 glXDestroyContext(dpy, ctx);
|
nuclear@0
|
364 XFree(vis);
|
nuclear@0
|
365 return -1;
|
nuclear@0
|
366 }
|
nuclear@0
|
367 XFree(vis);
|
nuclear@0
|
368
|
nuclear@0
|
369 unsigned int evmask = StructureNotifyMask | VisibilityChangeMask | ExposureMask |
|
nuclear@0
|
370 KeyPressMask | KeyReleaseMask | ButtonPressMask | ButtonReleaseMask |
|
nuclear@6
|
371 PointerMotionMask;
|
nuclear@0
|
372 XSelectInput(dpy, win, evmask);
|
nuclear@0
|
373
|
nuclear@0
|
374 xa_wm_prot = XInternAtom(dpy, "WM_PROTOCOLS", False);
|
nuclear@0
|
375 xa_wm_del_win = XInternAtom(dpy, "WM_DELETE_WINDOW", False);
|
nuclear@0
|
376 XSetWMProtocols(dpy, win, &xa_wm_del_win, 1);
|
nuclear@0
|
377
|
nuclear@0
|
378 XClassHint hint;
|
nuclear@0
|
379 hint.res_name = hint.res_class = (char*)"equeue_win";
|
nuclear@0
|
380 XSetClassHint(dpy, win, &hint);
|
nuclear@0
|
381
|
nuclear@0
|
382 XTextProperty wm_name;
|
nuclear@0
|
383 XStringListToTextProperty((char**)&title, 1, &wm_name);
|
nuclear@0
|
384 XSetWMName(dpy, win, &wm_name);
|
nuclear@0
|
385 XSetWMIconName(dpy, win, &wm_name);
|
nuclear@0
|
386 XFree(wm_name.value);
|
nuclear@0
|
387
|
nuclear@0
|
388 XMapWindow(dpy, win);
|
nuclear@0
|
389 glXMakeCurrent(dpy, win, ctx);
|
nuclear@0
|
390
|
nuclear@0
|
391 return win;
|
nuclear@0
|
392 }
|
nuclear@0
|
393
|
nuclear@0
|
394 static void process_events()
|
nuclear@0
|
395 {
|
nuclear@0
|
396 XEvent ev;
|
nuclear@0
|
397
|
nuclear@0
|
398 while(XPending(dpy)) {
|
nuclear@0
|
399 XNextEvent(dpy, &ev);
|
nuclear@0
|
400 switch(ev.type) {
|
nuclear@0
|
401 case MapNotify:
|
nuclear@0
|
402 win_mapped = true;
|
nuclear@0
|
403 break;
|
nuclear@0
|
404
|
nuclear@0
|
405 case UnmapNotify:
|
nuclear@0
|
406 win_mapped = false;
|
nuclear@0
|
407 break;
|
nuclear@0
|
408
|
nuclear@0
|
409 case Expose:
|
nuclear@0
|
410 if(win_mapped && ev.xexpose.count == 0) {
|
nuclear@6
|
411 draw_pending = true;
|
nuclear@0
|
412 }
|
nuclear@0
|
413 break;
|
nuclear@0
|
414
|
nuclear@0
|
415 case MotionNotify:
|
nuclear@0
|
416 motion(ev.xmotion.x, ev.xmotion.y);
|
nuclear@0
|
417 break;
|
nuclear@0
|
418
|
nuclear@0
|
419 case ButtonPress:
|
nuclear@0
|
420 mouse(ev.xbutton.button - 1, true, ev.xbutton.x, ev.xbutton.y);
|
nuclear@0
|
421 break;
|
nuclear@0
|
422
|
nuclear@0
|
423 case ButtonRelease:
|
nuclear@0
|
424 mouse(ev.xbutton.button - 1, false, ev.xbutton.x, ev.xbutton.y);
|
nuclear@0
|
425 break;
|
nuclear@0
|
426
|
nuclear@0
|
427 case KeyPress:
|
nuclear@0
|
428 {
|
nuclear@0
|
429 KeySym sym = XLookupKeysym(&ev.xkey, 0);
|
nuclear@0
|
430 keyb(translate_keysym(sym), true);
|
nuclear@0
|
431 }
|
nuclear@0
|
432 break;
|
nuclear@0
|
433
|
nuclear@0
|
434 case KeyRelease:
|
nuclear@0
|
435 {
|
nuclear@0
|
436 KeySym sym = XLookupKeysym(&ev.xkey, 0);
|
nuclear@0
|
437 keyb(translate_keysym(sym), false);
|
nuclear@0
|
438 }
|
nuclear@0
|
439 break;
|
nuclear@0
|
440
|
nuclear@0
|
441 case ConfigureNotify:
|
nuclear@0
|
442 {
|
nuclear@0
|
443 int xsz = ev.xconfigure.width;
|
nuclear@0
|
444 int ysz = ev.xconfigure.height;
|
nuclear@0
|
445
|
nuclear@0
|
446 if(xsz != win_width || ysz != win_height) {
|
nuclear@0
|
447 win_width = xsz;
|
nuclear@0
|
448 win_height = ysz;
|
nuclear@0
|
449 reshape(xsz, ysz);
|
nuclear@0
|
450 }
|
nuclear@0
|
451 }
|
nuclear@0
|
452 break;
|
nuclear@0
|
453
|
nuclear@0
|
454 case ClientMessage:
|
nuclear@0
|
455 if(ev.xclient.message_type == xa_wm_prot) {
|
nuclear@0
|
456 if((Atom)ev.xclient.data.l[0] == xa_wm_del_win) {
|
nuclear@0
|
457 exit(0);
|
nuclear@0
|
458 }
|
nuclear@0
|
459 }
|
nuclear@0
|
460 break;
|
nuclear@0
|
461
|
nuclear@0
|
462 default:
|
nuclear@0
|
463 break;
|
nuclear@0
|
464 }
|
nuclear@0
|
465
|
nuclear@0
|
466 }
|
nuclear@0
|
467 }
|
nuclear@0
|
468
|
nuclear@0
|
469 static int translate_keysym(KeySym sym)
|
nuclear@0
|
470 {
|
nuclear@0
|
471 switch(sym) {
|
nuclear@0
|
472 case XK_BackSpace:
|
nuclear@0
|
473 return '\b';
|
nuclear@0
|
474 case XK_Tab:
|
nuclear@0
|
475 return '\t';
|
nuclear@0
|
476 case XK_Linefeed:
|
nuclear@0
|
477 return '\r';
|
nuclear@0
|
478 case XK_Return:
|
nuclear@0
|
479 return '\n';
|
nuclear@0
|
480 case XK_Escape:
|
nuclear@0
|
481 return 27;
|
nuclear@0
|
482 default:
|
nuclear@0
|
483 break;
|
nuclear@0
|
484 }
|
nuclear@0
|
485 return (int)sym;
|
nuclear@0
|
486 }
|
nuclear@2
|
487
|
nuclear@2
|
488 static int proc_args(int argc, char **argv)
|
nuclear@2
|
489 {
|
nuclear@2
|
490 for(int i=1; i<argc; i++) {
|
nuclear@2
|
491 if(argv[i][0] == '-') {
|
nuclear@2
|
492 fprintf(stderr, "unexpected option: %s\n", argv[i]);
|
nuclear@2
|
493 return -1;
|
nuclear@2
|
494
|
nuclear@2
|
495 } else {
|
nuclear@2
|
496 if(fake_devpath) {
|
nuclear@2
|
497 fprintf(stderr, "unexpected argument: %s\n", argv[i]);
|
nuclear@2
|
498 return -1;
|
nuclear@2
|
499 }
|
nuclear@2
|
500 fake_devpath = argv[i];
|
nuclear@2
|
501 }
|
nuclear@2
|
502 }
|
nuclear@2
|
503 if(!fake_devpath) {
|
nuclear@2
|
504 fprintf(stderr, "no device path specified, running standalone\n");
|
nuclear@2
|
505 }
|
nuclear@2
|
506 return 0;
|
nuclear@2
|
507 }
|