1 /*
2  *  Display_x.i - C64 graphics display, emulator window handling,
3  *                X specific stuff
4  *
5  *  Frodo (C) 1994-1997,2002 Christian Bauer
6  *  X11 stuff by Bernd Schmidt/Lutz Vieweg
7  */
8 
9 #include "SAM.h"
10 #include "C64.h"
11 
12 #include <X11/Xlib.h>
13 #include <X11/Xutil.h>
14 #include <X11/keysym.h>
15 #include <X11/cursorfont.h>
16 
17 #if defined(X_USE_SHM)
18 #include <sys/ipc.h>
19 #include <sys/shm.h>
20 #include <X11/extensions/XShm.h>
21 static XShmSegmentInfo shminfo;
22 #endif
23 
24 static Display *display;
25 static int screen;
26 static Window rootwin, mywin;
27 
28 static GC black_gc, led_gc;
29 static XColor black, fill_gray, shine_gray, shadow_gray, red, green;
30 static Colormap cmap;
31 static Font led_font;
32 
33 static XImage *img;
34 static Visual *vis;
35 static XVisualInfo visualInfo;
36 static int bitdepth;
37 static char *bufmem;
38 static int hsize;
39 
40 // For LED error blinking
41 static C64Display *c64_disp;
42 static struct sigaction pulse_sa;
43 static itimerval pulse_tv;
44 
45 // Keyboard and joystick
46 static int keystate[256];
47 static int joystate = 0xFF;
48 static bool num_locked = false;
49 
50 static const long int eventmask = (KeyPressMask|KeyReleaseMask|FocusChangeMask|ExposureMask);
51 
52 
53 /*
54   C64 keyboard matrix:
55 
56     Bit 7   6   5   4   3   2   1   0
57   0    CUD  F5  F3  F1  F7 CLR RET DEL
58   1    SHL  E   S   Z   4   A   W   3
59   2     X   T   F   C   6   D   R   5
60   3     V   U   H   B   8   G   Y   7
61   4     N   O   K   M   0   J   I   9
62   5     ,   @   :   .   -   L   P   +
63   6     /   ^   =  SHR HOM  ;   *   �
64   7    R/S  Q   C= SPC  2  CTL  <-  1
65 */
66 
67 #define MATRIX(a,b) (((a) << 3) | (b))
68 
69 #define KEY_F9 512
70 #define KEY_F10 513
71 #define KEY_F11 514
72 #define KEY_F12 515
73 
74 #ifdef SUN
75 #define KEY_FIRE 58
76 #define KEY_JU 135
77 #define KEY_JD 7
78 #define KEY_JL 130
79 #define KEY_JR 2
80 #else
81 #define KEY_FIRE 516
82 #define KEY_JU 517
83 #define KEY_JD 518
84 #define KEY_JL 519
85 #define KEY_JR 520
86 #endif
87 
88 #define KEY_JUL 521
89 #define KEY_JUR 522
90 #define KEY_JDL 523
91 #define KEY_JDR 524
92 
93 #define KEY_KP_PLUS 525
94 #define KEY_KP_MINUS 526
95 #define KEY_KP_MULT 527
96 #define KEY_NUM_LOCK 528
97 
98 
99 /*
100  *  Decode KeySyms. This function knows about all keys that
101  *  are common between different keyboard languages.
102  */
103 
kc_decode(KeySym ks)104 static int kc_decode(KeySym ks)
105 {
106 	switch (ks) {
107 		case XK_A: case XK_a: return MATRIX(1,2);
108 		case XK_B: case XK_b: return MATRIX(3,4);
109 		case XK_C: case XK_c: return MATRIX(2,4);
110 		case XK_D: case XK_d: return MATRIX(2,2);
111 		case XK_E: case XK_e: return MATRIX(1,6);
112 		case XK_F: case XK_f: return MATRIX(2,5);
113 		case XK_G: case XK_g: return MATRIX(3,2);
114 		case XK_H: case XK_h: return MATRIX(3,5);
115 		case XK_I: case XK_i: return MATRIX(4,1);
116 		case XK_J: case XK_j: return MATRIX(4,2);
117 		case XK_K: case XK_k: return MATRIX(4,5);
118 		case XK_L: case XK_l: return MATRIX(5,2);
119 		case XK_M: case XK_m: return MATRIX(4,4);
120 		case XK_N: case XK_n: return MATRIX(4,7);
121 		case XK_O: case XK_o: return MATRIX(4,6);
122 		case XK_P: case XK_p: return MATRIX(5,1);
123 		case XK_Q: case XK_q: return MATRIX(7,6);
124 		case XK_R: case XK_r: return MATRIX(2,1);
125 		case XK_S: case XK_s: return MATRIX(1,5);
126 		case XK_T: case XK_t: return MATRIX(2,6);
127 		case XK_U: case XK_u: return MATRIX(3,6);
128 		case XK_V: case XK_v: return MATRIX(3,7);
129 		case XK_W: case XK_w: return MATRIX(1,1);
130 		case XK_X: case XK_x: return MATRIX(2,7);
131 		case XK_Y: case XK_y: return MATRIX(3,1);
132 		case XK_Z: case XK_z: return MATRIX(1,4);
133 
134 		case XK_0: return MATRIX(4,3);
135 		case XK_1: return MATRIX(7,0);
136 		case XK_2: return MATRIX(7,3);
137 		case XK_3: return MATRIX(1,0);
138 		case XK_4: return MATRIX(1,3);
139 		case XK_5: return MATRIX(2,0);
140 		case XK_6: return MATRIX(2,3);
141 		case XK_7: return MATRIX(3,0);
142 		case XK_8: return MATRIX(3,3);
143 		case XK_9: return MATRIX(4,0);
144 
145 		case XK_space: return MATRIX(7,4);
146 		case XK_grave: return MATRIX(7,1);
147 		case XK_backslash: return MATRIX(6,6);
148 		case XK_comma: return MATRIX(5,7);
149 		case XK_period: return MATRIX(5,4);
150 
151 		case XK_Escape: return MATRIX(7,7);
152 		case XK_Return: return MATRIX(0,1);
153 		case XK_BackSpace: case XK_Delete: return MATRIX(0,0);
154 		case XK_Insert: return MATRIX(6,3);
155 		case XK_Home: case XK_Help: return MATRIX(6,3);
156 		case XK_End: return MATRIX(6,0);
157 #ifdef __hpux
158 		case XK_Prior: return MATRIX(6,0);
159 		case XK_Next: return MATRIX(6,5);
160 #else
161 		case XK_Page_Up: return MATRIX(6,0);
162 		case XK_Page_Down: return MATRIX(6,5);
163 #endif
164 		case XK_Control_L: return MATRIX(7,2);
165 		case XK_Control_R: return MATRIX(7,5);
166 		case XK_Shift_L: return MATRIX(1,7);
167 		case XK_Shift_R: return MATRIX(6,4);
168 		case XK_Alt_L: return MATRIX(7,5);
169 		case XK_Alt_R: return MATRIX(7,5);
170 
171 		case XK_Up: return MATRIX(0,7)| 0x80;
172 		case XK_Down: return MATRIX(0,7);
173 		case XK_Left: return MATRIX(0,2) | 0x80;
174 		case XK_Right: return MATRIX(0,2);
175 
176 		case XK_F1: return MATRIX(0,4);
177 		case XK_F2: return MATRIX(0,4) | 0x80;
178 		case XK_F3: return MATRIX(0,5);
179 		case XK_F4: return MATRIX(0,5) | 0x80;
180 		case XK_F5: return MATRIX(0,6);
181 		case XK_F6: return MATRIX(0,6) | 0x80;
182 		case XK_F7: return MATRIX(0,3);
183 		case XK_F8: return MATRIX(0,3) | 0x80;
184 
185 		case XK_F9: return KEY_F9;
186 		case XK_F10: return KEY_F10;
187 		case XK_F11: return KEY_F11;
188 		case XK_F12: return KEY_F12;
189 
190 		/* You never know which Keysyms might be missing on some workstation
191 		 * This #ifdef should be enough. */
192 #if defined(XK_KP_Prior) && defined(XK_KP_Left) && defined(XK_KP_Insert) && defined (XK_KP_End)
193 		case XK_KP_0: case XK_KP_Insert: return KEY_FIRE;
194 		case XK_KP_1: case XK_KP_End: return KEY_JDL;
195 		case XK_KP_2: case XK_KP_Down: return KEY_JD;
196 		case XK_KP_3: case XK_KP_Next: return KEY_JDR;
197 		case XK_KP_4: case XK_KP_Left: return KEY_JL;
198 		case XK_KP_5: case XK_KP_Begin: return KEY_FIRE;
199 		case XK_KP_6: case XK_KP_Right: return KEY_JR;
200 		case XK_KP_7: case XK_KP_Home: return KEY_JUL;
201 		case XK_KP_8: case XK_KP_Up: return KEY_JU;
202 		case XK_KP_9: case XK_KP_Prior: return KEY_JUR;
203 #else
204 		case XK_KP_0: return KEY_FIRE;
205 		case XK_KP_1: return KEY_JDL;
206 		case XK_KP_2: return KEY_JD;
207 		case XK_KP_3: return KEY_JDR;
208 		case XK_KP_4: return KEY_JL;
209 		case XK_KP_5: return KEY_FIRE;
210 		case XK_KP_6: return KEY_JR;
211 		case XK_KP_7: return KEY_JUL;
212 		case XK_KP_8: return KEY_JU;
213 		case XK_KP_9: return KEY_JUR;
214 #endif
215 
216 		case XK_KP_Add: return KEY_KP_PLUS;
217 		case XK_KP_Subtract: return KEY_KP_MINUS;
218 		case XK_KP_Multiply: return KEY_KP_MULT;
219 		case XK_KP_Divide: return MATRIX(6,7);
220 		case XK_KP_Enter: return MATRIX(0,1);
221 
222 #ifdef SUN
223 		case XK_Num_Lock: return KEY_NUM_LOCK;
224 #endif
225 	}
226 	return -1;
227 }
228 
decode_us(KeySym ks)229 static int decode_us(KeySym ks)
230 {
231 	switch(ks) {	/* US specific */
232 		case XK_minus: return MATRIX(5,0);
233 		case XK_equal: return MATRIX(5,3);
234 		case XK_bracketleft: return MATRIX(5,6);
235 		case XK_bracketright: return MATRIX(6,1);
236 		case XK_semicolon: return MATRIX(5,5);
237 		case XK_apostrophe: return MATRIX(6,2);
238 		case XK_slash: return MATRIX(6,7);
239 	}
240 
241 	return -1;
242 }
243 
decode_de(KeySym ks)244 static int decode_de(KeySym ks)
245 {
246 	switch(ks) {	/* DE specific */
247 		case XK_ssharp: return MATRIX(5,0);
248 		case XK_apostrophe: return MATRIX(5,3);
249 		case XK_Udiaeresis: case XK_udiaeresis: return MATRIX(5,6);
250 		case XK_plus: return MATRIX(6,1);
251 		case XK_Odiaeresis: case XK_odiaeresis: return MATRIX(5,5);
252 		case XK_Adiaeresis: case XK_adiaeresis: return MATRIX(6,2);
253 		case XK_numbersign: return MATRIX(6,5);
254 		case XK_less: case XK_greater: return MATRIX(6,0);
255 		case XK_minus: return MATRIX(6,7);
256 	}
257 
258 	return -1;
259 }
260 
keycode2c64(XKeyEvent * event)261 static int keycode2c64(XKeyEvent *event)
262 {
263 	KeySym ks;
264 	int as;
265 	int index = 0;
266 
267 	do {
268 		ks = XLookupKeysym(event, index);
269 		as = kc_decode(ks);
270 
271 		if (as == -1)
272 			as = KBD_LANG == 0 ? decode_us(ks) : decode_de(ks);
273 		if (as != -1)
274 			return as;
275 		index++;
276 	} while (ks != NoSymbol);
277 
278 	return -1;
279 }
280 
281 
282 /*
283  *  Display constructor: Draw Speedometer/LEDs in window
284  */
285 
C64Display(C64 * the_c64)286 C64Display::C64Display(C64 *the_c64) : TheC64(the_c64)
287 {
288 	int i;
289 	char str[16];
290 
291 	quit_requested = false;
292 
293 	// LEDs off
294 	for (i=0; i<4; i++)
295 		led_state[i] = old_led_state[i] = LED_OFF;
296 
297 	// Draw speedometer/LEDs
298 	led_gc = XCreateGC(display, mywin, 0, 0);
299 	XSetFont(display, led_gc, led_font);
300 
301 	XSetForeground(display, led_gc, fill_gray.pixel);
302 	XFillRectangle(display, mywin, led_gc, 0, DISPLAY_Y, DISPLAY_X-1, 16);
303 
304 	XSetForeground(display, led_gc, shine_gray.pixel);
305 	XDrawLine(display, mywin, led_gc, 0, DISPLAY_Y, DISPLAY_X-1, DISPLAY_Y);
306 	for (i=0; i<5; i++)
307 		XDrawLine(display, mywin, led_gc, DISPLAY_X*i/5, DISPLAY_Y, DISPLAY_X*i/5, DISPLAY_Y+14);
308 	for (i=2; i<6; i++) {
309 		XDrawLine(display, mywin, led_gc, DISPLAY_X*i/5-23, DISPLAY_Y+11, DISPLAY_X*i/5-9, DISPLAY_Y+11);
310 		XDrawLine(display, mywin, led_gc, DISPLAY_X*i/5-9, DISPLAY_Y+11, DISPLAY_X*i/5-9, DISPLAY_Y+5);
311 	}
312 
313 	XSetForeground(display, led_gc, shadow_gray.pixel);
314 	XDrawLine(display, mywin, led_gc, 0, DISPLAY_Y+15, DISPLAY_X-1, DISPLAY_Y+15);
315 	for (i=1; i<6; i++)
316 		XDrawLine(display, mywin, led_gc, DISPLAY_X*i/5-1, DISPLAY_Y+1, DISPLAY_X*i/5-1, DISPLAY_Y+15);
317 	for (i=2; i<6; i++) {
318 		XDrawLine(display, mywin, led_gc, DISPLAY_X*i/5-24, DISPLAY_Y+11, DISPLAY_X*i/5-24, DISPLAY_Y+4);
319 		XDrawLine(display, mywin, led_gc, DISPLAY_X*i/5-24, DISPLAY_Y+4, DISPLAY_X*i/5-9, DISPLAY_Y+4);
320 	}
321 
322 	for (i=0; i<4; i++) {
323 		sprintf(str, "Drive %d", i+8);
324 		XSetForeground(display, led_gc, black.pixel);
325 		XDrawString(display, mywin, led_gc, DISPLAY_X*(i+1)/5+8, DISPLAY_Y+12, str, strlen(str));
326 		draw_led(i, LED_OFF);
327 	}
328 
329 	// Start timer for LED error blinking
330 	c64_disp = this;
331 	pulse_sa.sa_handler = (void (*)(int))pulse_handler;
332 	pulse_sa.sa_flags = 0;
333 	sigemptyset(&pulse_sa.sa_mask);
334 	sigaction(SIGALRM, &pulse_sa, NULL);
335 	pulse_tv.it_interval.tv_sec = 0;
336 	pulse_tv.it_interval.tv_usec = 400000;
337 	pulse_tv.it_value.tv_sec = 0;
338 	pulse_tv.it_value.tv_usec = 400000;
339 	setitimer(ITIMER_REAL, &pulse_tv, NULL);
340 }
341 
342 
343 /*
344  *  Display destructor
345  */
346 
~C64Display()347 C64Display::~C64Display()
348 {
349 	XAutoRepeatOn(display);
350 	XSync(display, 0);
351 }
352 
353 
354 /*
355  *  Prefs may have changed
356  */
357 
NewPrefs(Prefs * prefs)358 void C64Display::NewPrefs(Prefs *prefs)
359 {
360 }
361 
362 
363 /*
364  *  Connect to X server and open window
365  */
366 
init_graphics(void)367 int init_graphics(void)
368 {
369 	int i;
370 	char *display_name = 0;
371 	XSetWindowAttributes wattr;
372 	XSizeHints *hints;
373 	XColor exact_color;
374 	int pixbytes;
375 
376 	display = XOpenDisplay(display_name);
377 	if (display == 0)  {
378 		fprintf(stderr, "Can't connect to X server %s\n", XDisplayName(display_name));
379 		return 0;
380 	}
381 
382 	screen = XDefaultScreen(display);
383 	rootwin = XRootWindow(display, screen);
384 	if (XMatchVisualInfo(display, screen, 8, PseudoColor, &visualInfo)) {
385 		/* for our HP boxes */
386 	} else if (XMatchVisualInfo(display, screen, 8, GrayScale, &visualInfo)) {
387 	} else {
388 		fprintf(stderr, "Can't obtain appropriate X visual\n");
389 		return 0;
390 	}
391 
392 	vis = visualInfo.visual;
393 	bitdepth = visualInfo.depth;
394 	pixbytes = (bitdepth == 24 || bitdepth == 32 ? 4 : bitdepth == 12 || bitdepth == 16 ? 2 : 1);
395 	fprintf(stderr, "Using %d bit visual\n", bitdepth);
396 
397 	hsize = (DISPLAY_X + 3) & ~3;
398 
399 #if defined(X_USE_SHM)
400         img = XShmCreateImage(display, vis, bitdepth, ZPixmap, 0, &shminfo,
401 			      hsize, DISPLAY_Y);
402 
403         shminfo.shmid = shmget(IPC_PRIVATE, DISPLAY_Y * img->bytes_per_line,
404                                IPC_CREAT | 0777);
405         shminfo.shmaddr = img->data = bufmem = (char *)shmat(shminfo.shmid, 0, 0);
406         shminfo.readOnly = False;
407         XShmAttach(display, &shminfo);
408         XSync(display,0);
409         /* now deleting means making it temporary */
410         shmctl(shminfo.shmid, IPC_RMID, 0);
411 #else
412 	bufmem = (char *)malloc(pixbytes * hsize * DISPLAY_Y);
413 	img = XCreateImage(display, vis, bitdepth, ZPixmap, 0, bufmem, hsize, DISPLAY_Y, 32, 0);
414 #endif
415 
416 	cmap = XCreateColormap(display, rootwin, vis, AllocNone);
417 
418 	XParseColor(display, cmap, "#000000", &black);
419 	if (!XAllocColor(display, cmap, &black))
420 		fprintf(stderr, "Whoops??\n");
421 
422 	wattr.event_mask = eventmask;
423 	wattr.background_pixel = black.pixel;
424 	wattr.backing_store = Always;
425 	wattr.backing_planes = bitdepth;
426 	wattr.border_pixmap = None;
427 	wattr.border_pixel = black.pixel;
428 	wattr.colormap = cmap;
429 
430 	mywin = XCreateWindow(display, rootwin, 0, 0, DISPLAY_X, DISPLAY_Y + 16, 0,
431 						  bitdepth, InputOutput, vis,
432 						  CWEventMask|CWBackPixel|CWBorderPixel|CWBackingStore
433 						  |CWBackingPlanes|CWColormap,
434 						  &wattr);
435 	XMapWindow(display, mywin);
436 	XStoreName(display, mywin, "Frodo");
437 
438 	if ((hints = XAllocSizeHints()) != NULL) {
439 		hints->min_width = DISPLAY_X;
440 		hints->max_width = DISPLAY_X;
441 		hints->min_height = DISPLAY_Y + 16;
442 		hints->max_height = DISPLAY_Y + 16;
443 		hints->flags = PMinSize | PMaxSize;
444 		XSetWMNormalHints(display, mywin, hints);
445 		XFree((char *)hints);
446 	}
447 
448 	black_gc = XCreateGC(display,mywin, 0, 0);
449     	XSetForeground(display, black_gc, black.pixel);
450 
451 	// Allocate colors for speedometer/LEDs
452 	if (!XAllocNamedColor(display, cmap, "rgb:d0/d0/d0", &fill_gray, &exact_color))
453 		return 0;
454 	if (!XAllocNamedColor(display, cmap, "rgb:e8/e8/e8", &shine_gray, &exact_color))
455 		return 0;
456 	if (!XAllocNamedColor(display, cmap, "rgb:98/98/98", &shadow_gray, &exact_color))
457 		return 0;
458 	if (!XAllocNamedColor(display, cmap, "rgb:f0/00/00", &red, &exact_color))
459 		return 0;
460 	if (!XAllocNamedColor(display, cmap, "rgb:00/f0/00", &green, &exact_color))
461 		return 0;
462 
463 	// Load font for speedometer/LED labels
464 	led_font = XLoadFont(display, "-*-helvetica-medium-r-*-*-10-*");
465 
466 	for(i=0; i<256; i++)
467 		keystate[i] = 0;
468 
469 	return 1;
470 }
471 
472 
473 /*
474  *  Redraw bitmap
475  */
476 
Update(void)477 void C64Display::Update(void)
478 {
479 	// Update C64 display
480 	XSync(display, 0);
481 #if defined(X_USE_SHM)
482 	XShmPutImage(display, mywin, black_gc, img, 0, 0, 0, 0, DISPLAY_X, DISPLAY_Y, 0);
483 #else
484  	XPutImage(display, mywin, black_gc, img, 0, 0, 0, 0, DISPLAY_X, DISPLAY_Y);
485 #endif
486 
487 	// Update drive LEDs
488 	for (int i=0; i<4; i++)
489 		if (led_state[i] != old_led_state[i]) {
490 			draw_led(i, led_state[i]);
491 			old_led_state[i] = led_state[i];
492 		}
493 }
494 
495 
496 /*
497  *  Draw one drive LED
498  */
499 
draw_led(int num,int state)500 void C64Display::draw_led(int num, int state)
501 {
502 	switch (state) {
503 		case LED_OFF:
504 		case LED_ERROR_OFF:
505 			XSetForeground(display, led_gc, black.pixel);
506 			break;
507 		case LED_ON:
508 			XSetForeground(display, led_gc, green.pixel);
509 			break;
510 		case LED_ERROR_ON:
511 			XSetForeground(display, led_gc, red.pixel);
512 			break;
513 	}
514 	XFillRectangle(display, mywin, led_gc, DISPLAY_X*(num+2)/5-23, DISPLAY_Y+5, 14, 6);
515 }
516 
517 
518 /*
519  *  LED error blink
520  */
521 
pulse_handler(int sig)522 void C64Display::pulse_handler(int sig)
523 {
524 	for (int i=0; i<4; i++)
525 		switch (c64_disp->led_state[i]) {
526 			case LED_ERROR_ON:
527 				c64_disp->led_state[i] = LED_ERROR_OFF;
528 				break;
529 			case LED_ERROR_OFF:
530 				c64_disp->led_state[i] = LED_ERROR_ON;
531 				break;
532 		}
533 }
534 
535 
536 /*
537  *  Draw speedometer
538  */
539 
Speedometer(int speed)540 void C64Display::Speedometer(int speed)
541 {
542 	static int delay = 0;
543 
544 	if (delay >= 20) {
545 		char str[16];
546 		sprintf(str, "%d%%", speed);
547 		XSetForeground(display, led_gc, fill_gray.pixel);
548 		XFillRectangle(display,mywin, led_gc, 1, DISPLAY_Y+1, DISPLAY_X/5-2, 14);
549 		XSetForeground(display, led_gc, black.pixel);
550 		XDrawString(display, mywin, led_gc, 24, DISPLAY_Y+12, str, strlen(str));
551 		delay = 0;
552 	} else
553 		delay++;
554 }
555 
556 
557 /*
558  *  Return pointer to bitmap data
559  */
560 
BitmapBase(void)561 uint8 *C64Display::BitmapBase(void)
562 {
563 	return (uint8 *)bufmem;
564 }
565 
566 
567 /*
568  *  Return number of bytes per row
569  */
570 
BitmapXMod(void)571 int C64Display::BitmapXMod(void)
572 {
573 	return hsize;
574 }
575 
576 
577 /*
578  *  Poll the keyboard
579  */
580 
PollKeyboard(uint8 * key_matrix,uint8 * rev_matrix,uint8 * joystick)581 void C64Display::PollKeyboard(uint8 *key_matrix, uint8 *rev_matrix, uint8 *joystick)
582 {
583 	static bool auto_rep = true;
584 	for(;;) {
585 		XEvent event;
586 		if (!XCheckMaskEvent(display, eventmask, &event))
587 			break;
588 
589 		switch(event.type) {
590 
591 			case KeyPress: {
592 				int kc = keycode2c64((XKeyEvent *)&event);
593 				if (kc == -1)
594 					break;
595 				switch (kc) {
596 
597 					case KEY_F9:	// F9: Invoke SAM
598 						SAM(TheC64);
599 						break;
600 
601 					case KEY_F10:	// F10: Quit
602 						quit_requested = true;
603 						break;
604 
605 					case KEY_F11:	// F11: NMI (Restore)
606 						TheC64->NMI();
607 						break;
608 
609 					case KEY_F12:	// F12: Reset
610 						TheC64->Reset();
611 						break;
612 
613 					case KEY_NUM_LOCK:	// NumLock: Toggle joyport
614 						num_locked = true;
615 						break;
616 
617 					case KEY_FIRE:
618 						joystate &= ~0x10;
619 						break;
620 					case KEY_JD:
621 						joystate &= ~0x02;
622 						break;
623 					case KEY_JU:
624 						joystate &= ~0x01;
625 						break;
626 					case KEY_JL:
627 						joystate &= ~0x04;
628 						break;
629 					case KEY_JR:
630 						joystate &= ~0x08;
631 						break;
632 					case KEY_JUL:
633 						joystate &= ~0x05;
634 						break;
635 					case KEY_JUR:
636 						joystate &= ~0x09;
637 						break;
638 					case KEY_JDL:
639 						joystate &= ~0x06;
640 						break;
641 					case KEY_JDR:
642 						joystate &= ~0x0a;
643 						break;
644 
645 					case KEY_KP_PLUS:	// '+' on keypad: Increase SkipFrames
646 						ThePrefs.SkipFrames++;
647 						break;
648 
649 					case KEY_KP_MINUS:	// '-' on keypad: Decrease SkipFrames
650 						if (ThePrefs.SkipFrames > 1)
651 							ThePrefs.SkipFrames--;
652 						break;
653 
654 					case KEY_KP_MULT:	// '*' on keypad: Toggle speed limiter
655 						ThePrefs.LimitSpeed = !ThePrefs.LimitSpeed;
656 						break;
657 
658 					default:
659 						if (keystate[kc])
660 							break;
661 						keystate[kc] = 1;
662 						int c64_byte, c64_bit, shifted;
663 						c64_byte = kc >> 3;
664 						c64_bit = kc & 7;
665 						shifted = kc & 128;
666 						c64_byte &= 7;
667 						if (shifted) {
668 							key_matrix[6] &= 0xef;
669 							rev_matrix[4] &= 0xbf;
670 						}
671 						key_matrix[c64_byte] &= ~(1 << c64_bit);
672 						rev_matrix[c64_bit] &= ~(1 << c64_byte);
673 						break;
674 				}
675 				break;
676 			}
677 
678 			case KeyRelease: {
679 				int kc = keycode2c64((XKeyEvent *)&event);
680 				if (kc == -1)
681 					break;
682 				switch (kc) {
683 
684 					case KEY_NUM_LOCK:
685 						num_locked = false;
686 						break;
687 
688 					case KEY_FIRE:
689 						joystate |= 0x10;
690 						break;
691 					case KEY_JD:
692 						joystate |= 0x02;
693 						break;
694 					case KEY_JU:
695 						joystate |= 0x01;
696 						break;
697 					case KEY_JL:
698 						joystate |= 0x04;
699 						break;
700 					case KEY_JR:
701 						joystate |= 0x08;
702 						break;
703 					case KEY_JUL:
704 						joystate |= 0x05;
705 						break;
706 					case KEY_JUR:
707 						joystate |= 0x09;
708 						break;
709 					case KEY_JDL:
710 						joystate |= 0x06;
711 						break;
712 					case KEY_JDR:
713 						joystate |= 0x0a;
714 						break;
715 
716 					default:
717 						if (!keystate[kc])
718 							break;
719 						keystate[kc] = 0;
720 						int c64_byte, c64_bit, shifted;
721 						c64_byte = kc >> 3;
722 						c64_bit = kc & 7;
723 						shifted = kc & 128;
724 						c64_byte &= 7;
725 						if (shifted) {
726 							key_matrix[6] |= 0x10;
727 							rev_matrix[4] |= 0x40;
728 						}
729 						key_matrix[c64_byte] |= (1 << c64_bit);
730 						rev_matrix[c64_bit] |= (1 << c64_byte);
731 						break;
732 				}
733 			}
734 
735 			case FocusIn:
736 				if (auto_rep) {
737 					XAutoRepeatOff(display);
738 					auto_rep = false;
739 				}
740 				break;
741 
742 			case FocusOut:
743 				if (!auto_rep) {
744 					XAutoRepeatOn(display);
745 					auto_rep = true;
746 				}
747 				break;
748 		}
749 	}
750 	*joystick = joystate;
751 }
752 
753 
754 /*
755  *  Check if NumLock is down (for switching the joystick keyboard emulation)
756  */
757 
NumLock(void)758 bool C64Display::NumLock(void)
759 {
760 	return num_locked;
761 }
762 
763 
764 /*
765  *  Allocate C64 colors
766  */
767 
InitColors(uint8 * colors)768 void C64Display::InitColors(uint8 *colors)
769 {
770 	int i;
771 	XColor col;
772 	char str[20];
773 
774 	for (i=0; i< 256; i++) {
775 		sprintf(str, "rgb:%x/%x/%x", palette_red[i & 0x0f], palette_green[i & 0x0f], palette_blue[i & 0x0f]);
776 		XParseColor(display, cmap, str, &col);
777 		if (XAllocColor(display, cmap, &col))
778 			colors[i] = col.pixel;
779 		else
780 			fprintf(stderr, "Couldn't get all colors\n");
781 	}
782 }
783 
784 
785 /*
786  *  Show a requester (error message)
787  */
788 
ShowRequester(char * a,char * b,char *)789 long int ShowRequester(char *a,char *b,char *)
790 {
791 	printf("%s: %s\n", a, b);
792 	return 1;
793 }
794