1 /** \file   keyboard.c
2  * \brief   Common keyboard emulation.
3  *
4  * \author  Andreas Boose <viceteam@t-online.de>
5  * \author  Ettore Perazzoli <ettore@comm2000.it>
6  * \author  Jouko Valta <jopi@stekt.oulu.fi>
7  * \author  Andre Fachat <fachat@physik.tu-chemnitz.de>
8  * \author  Bernhard Kuhn <kuhn@eikon.e-technik.tu-muenchen.de>
9  */
10 
11 /*
12  * This file is part of VICE, the Versatile Commodore Emulator.
13  * See README for copyright notice.
14  *
15  *  This program is free software; you can redistribute it and/or modify
16  *  it under the terms of the GNU General Public License as published by
17  *  the Free Software Foundation; either version 2 of the License, or
18  *  (at your option) any later version.
19  *
20  *  This program is distributed in the hope that it will be useful,
21  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
22  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
23  *  GNU General Public License for more details.
24  *
25  *  You should have received a copy of the GNU General Public License
26  *  along with this program; if not, write to the Free Software
27  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
28  *  02111-1307  USA.
29  *
30  */
31 
32 #include "vice.h"
33 
34 #include <stdio.h>
35 #include <stdlib.h>
36 #include <string.h>
37 #include <ctype.h>
38 
39 #ifndef RAND_MAX
40 #include <limits.h>
41 #define RAND_MAX INT_MAX
42 #endif
43 
44 #include "alarm.h"
45 #include "archdep.h"
46 #include "archdep_kbd_get_host_mapping.h"
47 #include "cmdline.h"
48 #include "joystick.h"
49 #include "joy.h"
50 #include "kbd.h"
51 #include "keyboard.h"
52 #include "lib.h"
53 #include "log.h"
54 #include "machine.h"
55 #include "maincpu.h"
56 #include "network.h"
57 #include "resources.h"
58 #include "snapshot.h"
59 #include "sysfile.h"
60 #include "types.h"
61 #include "util.h"
62 #include "vice-event.h"
63 
64 /* #define DBGKBD */
65 
66 #ifdef DBGKBD
67 #define DBG(x)  printf x
68 #else
69 #define DBG(x)
70 #endif
71 
72 #define KEYBOARD_RAND() lib_unsigned_rand(1, (unsigned int)machine_get_cycles_per_frame())
73 
74 /* Keyboard array.  */
75 int keyarr[KBD_ROWS];
76 int rev_keyarr[KBD_COLS];
77 
78 /* Shift lock state.  */
79 int keyboard_shiftlock = 0;
80 
81 /* Keyboard status to be latched into the keyboard array.  */
82 static int latch_keyarr[KBD_ROWS];
83 static int latch_rev_keyarr[KBD_COLS];
84 
85 static int network_keyarr[KBD_ROWS];
86 static int network_rev_keyarr[KBD_COLS];
87 
88 static alarm_t *keyboard_alarm = NULL;
89 
90 static log_t keyboard_log = LOG_DEFAULT;
91 
92 static keyboard_machine_func_t keyboard_machine_func = NULL;
93 
94 static CLOCK keyboard_delay = 0;
95 
96 static int keyboard_clear = 0;
97 
98 static alarm_t *restore_alarm = NULL; /* restore key alarm context */
99 
100 
101 /** \brief  Resource value for KdbStatusbar
102  *
103  * Determines whether to show the keyboard debugging widget on the statusbar.
104  */
105 static int kbd_statusbar_enabled = 0;
106 
107 
108 /** \brief  Resource handler for 'KbdStatusbar'
109  *
110  * Enables/disables the display of the keyboard debugging on the statusbar
111  *
112  * \param[in]   val     enable display of widget
113  * \param[in]   param   extra data (unused)
114  *
115  * \return 0
116  */
keyboard_set_keyboard_statusbar(int val,void * param)117 static int keyboard_set_keyboard_statusbar(int val, void *param)
118 {
119     kbd_statusbar_enabled = val ? 1 : 0;
120     return 0;   /* Okidoki */
121 }
122 
123 
keyboard_latch_matrix(CLOCK offset)124 static void keyboard_latch_matrix(CLOCK offset)
125 {
126     if (network_connected()) {
127         memcpy(keyarr, network_keyarr, sizeof(keyarr));
128         memcpy(rev_keyarr, network_rev_keyarr, sizeof(rev_keyarr));
129     } else {
130         memcpy(keyarr, latch_keyarr, sizeof(keyarr));
131         memcpy(rev_keyarr, latch_rev_keyarr, sizeof(rev_keyarr));
132     }
133     if (keyboard_machine_func != NULL) {
134         keyboard_machine_func(keyarr);
135     }
136 }
137 
keyboard_set_latch_keyarr(int row,int col,int value)138 static int keyboard_set_latch_keyarr(int row, int col, int value)
139 {
140     if (row < 0 || col < 0) {
141         return -1;
142     }
143     /* printf("keyboard_set_latch_keyarr %d: %d %d\n", value, row, col); */
144     if (value) {
145         latch_keyarr[row] |= 1 << col;
146         latch_rev_keyarr[col] |= 1 << row;
147     } else {
148         latch_keyarr[row] &= ~(1 << col);
149         latch_rev_keyarr[col] &= ~(1 << row);
150     }
151 #if 0
152     {
153         int r, c;
154         for (r = 0; r < 8; r++) {
155             for (c = 0; c < 8; c++) {
156                 printf("%c", latch_keyarr[r] & (1 << c) ? '*' : '.');
157             }
158             printf("\n");
159         }
160     }
161 #endif
162     return 0;
163 }
164 
165 /*-----------------------------------------------------------------------*/
166 
167 static void keyboard_key_clear_internal(void);
168 
keyboard_event_record(void)169 static void keyboard_event_record(void)
170 {
171     event_record(EVENT_KEYBOARD_MATRIX, (void *)keyarr, sizeof(keyarr));
172 }
173 
keyboard_event_playback(CLOCK offset,void * data)174 void keyboard_event_playback(CLOCK offset, void *data)
175 {
176     int row, col;
177 
178     memcpy(latch_keyarr, data, sizeof(keyarr));
179 
180     for (row = 0; row < KBD_ROWS; row++) {
181         for (col = 0; col < KBD_COLS; col++) {
182             keyboard_set_latch_keyarr(row, col, latch_keyarr[row] & (1 << col));
183         }
184     }
185 
186     keyboard_latch_matrix(offset);
187 }
188 
keyboard_restore_event_playback(CLOCK offset,void * data)189 void keyboard_restore_event_playback(CLOCK offset, void *data)
190 {
191     machine_set_restore_key((int)(*(uint32_t *)data));
192 }
193 
keyboard_latch_handler(CLOCK offset,void * data)194 static void keyboard_latch_handler(CLOCK offset, void *data)
195 {
196     alarm_unset(keyboard_alarm);
197     alarm_context_update_next_pending(keyboard_alarm->context);
198 
199     keyboard_latch_matrix(offset);
200 
201     keyboard_event_record();
202 }
203 
keyboard_event_delayed_playback(void * data)204 void keyboard_event_delayed_playback(void *data)
205 {
206     int row, col;
207 
208     memcpy(network_keyarr, data, sizeof(network_keyarr));
209 
210     for (row = 0; row < KBD_ROWS; row++) {
211         for (col = 0; col < KBD_COLS; col++) {
212             if (network_keyarr[row] & (1 << col)) {
213                 network_rev_keyarr[col] |= 1 << row;
214             } else {
215                 network_rev_keyarr[col] &= ~(1 << row);
216             }
217         }
218     }
219 
220     if (keyboard_clear == 1) {
221         keyboard_key_clear_internal();
222         keyboard_clear = 0;
223     }
224 
225     alarm_set(keyboard_alarm, maincpu_clk + keyboard_delay);
226 }
227 /*-----------------------------------------------------------------------*/
228 
keyboard_set_keyarr(int row,int col,int value)229 void keyboard_set_keyarr(int row, int col, int value)
230 {
231     if (keyboard_set_latch_keyarr(row, col, value) < 0) {
232         return;
233     }
234 
235     alarm_set(keyboard_alarm, maincpu_clk + KEYBOARD_RAND());
236 }
237 
keyboard_clear_keymatrix(void)238 void keyboard_clear_keymatrix(void)
239 {
240     memset(keyarr, 0, sizeof(keyarr));
241     memset(rev_keyarr, 0, sizeof(rev_keyarr));
242     memset(latch_keyarr, 0, sizeof(latch_keyarr));
243     memset(latch_rev_keyarr, 0, sizeof(latch_rev_keyarr));
244     keyboard_shiftlock = 0;
245 }
246 
keyboard_register_machine(keyboard_machine_func_t func)247 void keyboard_register_machine(keyboard_machine_func_t func)
248 {
249     keyboard_machine_func = func;
250 }
251 
keyboard_register_delay(unsigned int delay)252 void keyboard_register_delay(unsigned int delay)
253 {
254     keyboard_delay = delay;
255 }
256 
keyboard_register_clear(void)257 void keyboard_register_clear(void)
258 {
259     keyboard_clear = 1;
260 }
261 /*-----------------------------------------------------------------------*/
262 
263 /* 40/80 column key.  */
264 static signed long key_ctrl_column4080 = -1;
265 static key_ctrl_column4080_func_t key_ctrl_column4080_func = NULL;
266 
267 /* CAPS (ASCII/DIN) key.  */
268 static signed long key_ctrl_caps = -1;
269 static key_ctrl_caps_func_t key_ctrl_caps_func = NULL;
270 
271 /* joyport attached keypad. */
272 static signed long key_joy_keypad[KBD_JOY_KEYPAD_ROWS][KBD_JOY_KEYPAD_COLS];
273 static key_joy_keypad_func_t key_joy_keypad_func = NULL;
274 
keyboard_register_column4080_key(key_ctrl_column4080_func_t func)275 void keyboard_register_column4080_key(key_ctrl_column4080_func_t func)
276 {
277     key_ctrl_column4080_func = func;
278 }
279 
keyboard_register_caps_key(key_ctrl_caps_func_t func)280 void keyboard_register_caps_key(key_ctrl_caps_func_t func)
281 {
282     key_ctrl_caps_func = func;
283 }
284 
keyboard_register_joy_keypad(key_joy_keypad_func_t func)285 void keyboard_register_joy_keypad(key_joy_keypad_func_t func)
286 {
287     key_joy_keypad_func = func;
288 }
289 
290 /*-----------------------------------------------------------------------*/
291 
292 enum shift_type {
293     NO_SHIFT = 0,                 /* Key is not shifted. Keys will be deshifted,
294                                      no other flags will be checked */
295 
296     VIRTUAL_SHIFT     = (1 << 0), /* The key needs a shift on the emulated machine. */
297     LEFT_SHIFT        = (1 << 1), /* Key is left shift on the emulated machine. */
298     RIGHT_SHIFT       = (1 << 2), /* Key is right shift on the emulated machine. */
299     ALLOW_SHIFT       = (1 << 3), /* Allow key to be shifted. */
300     DESHIFT_SHIFT     = (1 << 4), /* Although SHIFT might be pressed, do not
301                                      press shift on the emulated machine. */
302     ALLOW_OTHER       = (1 << 5), /* Allow another key code to be assigned if
303                                      SHIFT is pressed. */
304     SHIFT_LOCK        = (1 << 6), /* Key is shift lock on the emulated machine */
305     MAP_MOD_SHIFT     = (1 << 7), /* Key requires SHIFT to be pressed on host */
306 
307     ALT_MAP           = (1 << 8), /* Key is used for an alternative keyboard mapping (x128) */
308 
309     MAP_MOD_RIGHT_ALT = (1 << 9), /* Key requires right ALT (Alt-gr) to be pressed on host */
310     MAP_MOD_CTRL     = (1 << 10), /* Key requires control to be pressed on host */
311 
312     VIRTUAL_CBM      = (1 << 11), /* The key is combined with CBM on the emulated machine */
313     VIRTUAL_CTRL     = (1 << 12), /* The key is combined with CTRL on the emulated machine */
314 
315     LEFT_CBM         = (1 << 13), /* Key is CBM on the emulated machine */
316     LEFT_CTRL        = (1 << 14)  /* Key is CTRL on the emulated machine */
317 };
318 
319 struct keyboard_conv_s {
320     signed long sym;
321     int row;
322     int column;
323     enum shift_type shift;
324     char *comment;
325 };
326 typedef struct keyboard_conv_s keyboard_conv_t;
327 
328 /* Is the resource code ready to load the keymap?  */
329 static int load_keymap_ok = 0;
330 
331 /* Memory size of array in sizeof(keyconv_t), 0 = static.  */
332 static int keyc_mem = 0;
333 
334 /* Number of convs used in sizeof(keyconv_t).  */
335 static int keyc_num = 0;
336 
337 /* Two possible restore keys.  */
338 static signed long key_ctrl_restore1 = -1;
339 static signed long key_ctrl_restore2 = -1;
340 
341 /* Is an alternative mapping active? */
342 static int key_alternative = 0;
343 
344 static keyboard_conv_t *keyconvmap = NULL;
345 
346 /* matrix locations for the modifier keys */
347 static int kbd_lshiftrow = -1;
348 static int kbd_lshiftcol = -1;
349 static int kbd_rshiftrow = -1;
350 static int kbd_rshiftcol = -1;
351 static int kbd_lcbmrow   = -1;
352 static int kbd_lcbmcol   = -1;
353 static int kbd_lctrlrow  = -1;
354 static int kbd_lctrlcol  = -1;
355 
356 #define KEY_NONE   0
357 #define KEY_RSHIFT 1
358 #define KEY_LSHIFT 2
359 #define KEY_LCBM   3
360 #define KEY_LCTRL  4
361 
362 static int vshift = KEY_NONE;   /* virtual shift */
363 static int vcbm   = KEY_NONE;   /* virtual cbm */
364 static int vctrl  = KEY_NONE;   /* virtual ctrl */
365 
366 static int shiftl = KEY_NONE;   /* shift-lock */
367 
368 /*-----------------------------------------------------------------------*/
369 
370 static int left_shift_down, right_shift_down,
371             left_cbm_down, left_ctrl_down,
372             virtual_shift_down, virtual_cbm_down, virtual_ctrl_down;
373 static int key_latch_row, key_latch_column;
374 
rshift_defined(void)375 static inline int rshift_defined(void) {
376     if ((kbd_rshiftrow != -1) && (kbd_rshiftcol != -1)) {
377         return 1;
378     }
379     return 0;
380 }
381 
lshift_defined(void)382 static inline int lshift_defined(void) {
383     if ((kbd_lshiftrow != -1) && (kbd_lshiftcol != -1)) {
384         return 1;
385     }
386     return 0;
387 }
388 
lcbm_defined(void)389 static inline int lcbm_defined(void) {
390     if ((kbd_lcbmrow != -1) && (kbd_lcbmcol != -1)) {
391         return 1;
392     }
393     return 0;
394 }
395 
lctrl_defined(void)396 static inline int lctrl_defined(void) {
397     if ((kbd_lctrlrow != -1) && (kbd_lctrlcol != -1)) {
398         return 1;
399     }
400     return 0;
401 }
402 
vshift_defined(void)403 static inline int vshift_defined(void) {
404     return !(vshift == KEY_NONE);
405 }
406 
vctrl_defined(void)407 static inline int vctrl_defined(void) {
408     return !(vctrl == KEY_NONE);
409 }
410 
vcbm_defined(void)411 static inline int vcbm_defined(void) {
412     return !(vcbm == KEY_NONE);
413 }
414 
shiftlock_defined(void)415 static inline int shiftlock_defined(void) {
416     return !(shiftl == KEY_NONE);
417 }
418 
keyboard_key_deshift(void)419 static void keyboard_key_deshift(void)
420 {
421     if (lshift_defined()) {
422         keyboard_set_latch_keyarr(kbd_lshiftrow, kbd_lshiftcol, 0);
423     }
424     if (rshift_defined()) {
425         keyboard_set_latch_keyarr(kbd_rshiftrow, kbd_rshiftcol, 0);
426     }
427     if (lcbm_defined()) {
428         keyboard_set_latch_keyarr(kbd_lcbmrow,   kbd_lcbmcol,   0);
429     }
430     if (lctrl_defined()) {
431         keyboard_set_latch_keyarr(kbd_lctrlrow,  kbd_lctrlcol,  0);
432     }
433 }
434 
keyboard_key_shift(void)435 static void keyboard_key_shift(void)
436 {
437     if (lshift_defined()) {
438         if (left_shift_down > 0
439             || (virtual_shift_down > 0 && vshift == KEY_LSHIFT)
440             || (keyboard_shiftlock > 0 && shiftl == KEY_LSHIFT)) {
441             keyboard_set_latch_keyarr(kbd_lshiftrow, kbd_lshiftcol, 1);
442         }
443     }
444     if (rshift_defined()) {
445         if (right_shift_down > 0
446             || (virtual_shift_down > 0 && vshift == KEY_RSHIFT)
447             || (keyboard_shiftlock > 0 && shiftl == KEY_RSHIFT)) {
448             keyboard_set_latch_keyarr(kbd_rshiftrow, kbd_rshiftcol, 1);
449         }
450     }
451     if (lcbm_defined()) {
452         if (left_cbm_down > 0
453             || (virtual_cbm_down > 0 && vcbm == KEY_LCBM)) {
454             keyboard_set_latch_keyarr(kbd_lcbmrow, kbd_lcbmcol, 1);
455         }
456     }
457     if (lctrl_defined()) {
458         if (left_ctrl_down > 0
459             || (virtual_ctrl_down > 0 && vctrl == KEY_LCTRL)) {
460             keyboard_set_latch_keyarr(kbd_lctrlrow, kbd_lctrlcol, 1);
461         }
462     }
463 }
464 
keyboard_key_pressed_matrix(int row,int column,int shift)465 static int keyboard_key_pressed_matrix(int row, int column, int shift)
466 {
467     if (row >= 0) {
468         key_latch_row = row;
469         key_latch_column = column;
470 
471         if (shift == NO_SHIFT) {
472             keyboard_key_deshift();
473         } else {
474             /* FIXME: somehow make sure virtual shift/cbm/ctrl is really only
475                       valid for one combined keypress. the shift/ctrl/cbm
476                       status should not get permanently altered by deshifting */
477             if (shift & DESHIFT_SHIFT) {
478                 /* FIXME: should this really remove ALL modifiers? */
479                 keyboard_key_deshift();
480             }
481             if (shift & VIRTUAL_SHIFT) {
482                 virtual_shift_down = 1;
483             }
484             if (shift & LEFT_SHIFT) {
485                 left_shift_down = 1;
486             }
487             if (shift & RIGHT_SHIFT) {
488                 right_shift_down = 1;
489             }
490             if (shift & SHIFT_LOCK) {
491                 keyboard_shiftlock ^= 1;
492             }
493             if (lcbm_defined()) {
494                 if (shift & VIRTUAL_CBM) {
495                     virtual_cbm_down = 1;
496                 }
497                 if (shift & LEFT_CBM) {
498                     left_cbm_down = 1;
499                 }
500             }
501             if (lctrl_defined()) {
502                 if (shift & VIRTUAL_CTRL) {
503                     virtual_ctrl_down = 1;
504                 }
505                 if (shift & LEFT_CTRL) {
506                     left_ctrl_down = 1;
507                 }
508             }
509 
510             if (shift & DESHIFT_SHIFT) {
511                 /* FIXME: should this really remove ALL modifiers? */
512                 left_shift_down = 0;
513                 right_shift_down = 0;
514                 left_ctrl_down = 0;
515                 left_cbm_down = 0;
516             }
517             keyboard_key_shift();
518 
519         }
520         return 1;
521     }
522 
523     return 0;
524 }
525 
526 /*
527     restore key handling. restore key presses are distributed randomly
528     across a frame.
529 
530     FIXME: when network play is active this is not the case yet
531 */
532 
533 static int restore_raw = 0;
534 static int restore_delayed = 0;
535 static int restore_quick_release = 0;
536 
restore_alarm_triggered(CLOCK offset,void * data)537 static void restore_alarm_triggered(CLOCK offset, void *data)
538 {
539     uint32_t event_data;
540     alarm_unset(restore_alarm);
541 
542     event_data = (uint32_t)restore_delayed;
543     machine_set_restore_key(restore_delayed);
544     event_record(EVENT_KEYBOARD_RESTORE, (void*)&event_data, sizeof(uint32_t));
545     restore_delayed = 0;
546 
547     if (restore_quick_release) {
548         restore_quick_release = 0;
549         alarm_set(restore_alarm, maincpu_clk + KEYBOARD_RAND());
550     }
551 }
552 
keyboard_restore_pressed(void)553 static void keyboard_restore_pressed(void)
554 {
555     uint32_t event_data;
556     event_data = (uint32_t)1;
557     if (network_connected()) {
558         network_event_record(EVENT_KEYBOARD_RESTORE, (void*)&event_data, sizeof(uint32_t));
559     } else {
560         if (restore_raw == 0) {
561             restore_delayed = 1;
562             restore_quick_release = 0;
563             alarm_set(restore_alarm, maincpu_clk + KEYBOARD_RAND());
564         }
565     }
566     restore_raw = 1;
567 }
568 
keyboard_restore_released(void)569 static void keyboard_restore_released(void)
570 {
571     uint32_t event_data;
572     event_data = (uint32_t)0;
573     if (network_connected()) {
574         network_event_record(EVENT_KEYBOARD_RESTORE, (void*)&event_data, sizeof(uint32_t));
575     } else {
576         if (restore_raw == 1) {
577             if (restore_delayed) {
578                 restore_quick_release = 1;
579             } else {
580                 alarm_set(restore_alarm, maincpu_clk + KEYBOARD_RAND());
581             }
582         }
583     }
584     restore_raw = 0;
585 }
586 
587 /* press a key, this is called by the UI */
keyboard_key_pressed(signed long key,int mod)588 void keyboard_key_pressed(signed long key, int mod)
589 {
590     int i, j, latch;
591 
592     /* log_debug("%s:  %3i %04x", __func__, key, mod); */
593 
594     if (event_playback_active()) {
595         return;
596     }
597 
598     /* Restore */
599     if (((key == key_ctrl_restore1) || (key == key_ctrl_restore2))
600         && machine_has_restore_key()) {
601         keyboard_restore_pressed();
602         return;
603     }
604 
605     /* c128 40/80 column key */
606     if (key == key_ctrl_column4080) {
607         if (key_ctrl_column4080_func != NULL) {
608             key_ctrl_column4080_func();
609         }
610         return;
611     }
612 
613     /* c128 caps lock key */
614     if (key == key_ctrl_caps) {
615         if (key_ctrl_caps_func != NULL) {
616             key_ctrl_caps_func();
617         }
618         return;
619     }
620 
621     if (key_joy_keypad_func != NULL) {
622         for (i = 0; i < KBD_JOY_KEYPAD_ROWS; ++i) {
623             for (j = 0; j < KBD_JOY_KEYPAD_COLS; ++j) {
624                 if (key == key_joy_keypad[i][j]) {
625                     key_joy_keypad_func(i, j, 1);
626                     return;
627                 }
628             }
629         }
630     }
631 
632 #ifdef COMMON_JOYKEYS
633     for (i = 0; i < JOYSTICK_NUM; ++i) {
634         if (joystick_port_map[i] == JOYDEV_NUMPAD
635             || joystick_port_map[i] == JOYDEV_KEYSET1
636             || joystick_port_map[i] == JOYDEV_KEYSET2) {
637             if (joystick_check_set(key, joystick_port_map[i] - JOYDEV_NUMPAD, 1 + i)) {
638                 return;
639             }
640         }
641     }
642 #endif
643 
644     if (keyconvmap == NULL) {
645         return;
646     }
647 
648     latch = 0;
649 
650     for (i = 0; i < keyc_num; ++i) {
651         if (key == keyconvmap[i].sym) {
652             /* skip keys from alternative keyset */
653             if ((keyconvmap[i].shift & ALT_MAP) && !key_alternative) {
654                 continue;
655             }
656 
657             /* find explicit matches on modifiers pressed on host */
658             if ((keyconvmap[i].shift & MAP_MOD_RIGHT_ALT) && (!(mod & KBD_MOD_RALT)) ) {
659                 continue;
660             }
661             if ((keyconvmap[i].shift & MAP_MOD_CTRL) && (!(mod & (KBD_MOD_LCTRL | KBD_MOD_RCTRL))) ) {
662                 continue;
663             }
664             if ((keyconvmap[i].shift & MAP_MOD_SHIFT) && (!(mod & (KBD_MOD_LSHIFT | KBD_MOD_RSHIFT))) ) {
665                 continue;
666             }
667 
668             if (keyboard_key_pressed_matrix(keyconvmap[i].row,
669                                             keyconvmap[i].column,
670                                             keyconvmap[i].shift)) {
671                 latch = 1;
672                 if (!(keyconvmap[i].shift & ALLOW_OTHER)
673                     /*|| (right_shift_down + left_shift_down) == 0*/) {
674                     break;
675                 }
676             }
677         }
678     }
679 
680     if (latch) {
681         keyboard_set_latch_keyarr(key_latch_row, key_latch_column, 1);
682         if (network_connected()) {
683             CLOCK delay = KEYBOARD_RAND();
684             network_event_record(EVENT_KEYBOARD_DELAY, (void *)&delay, sizeof(delay));
685             network_event_record(EVENT_KEYBOARD_MATRIX, (void *)latch_keyarr, sizeof(latch_keyarr));
686         } else {
687             alarm_set(keyboard_alarm, maincpu_clk + KEYBOARD_RAND());
688         }
689     }
690 }
691 
keyboard_key_released_matrix(int row,int column,int shift)692 static int keyboard_key_released_matrix(int row, int column, int shift)
693 {
694     int skip_release = 0;
695 
696     if (row >= 0) {
697         key_latch_row = row;
698         key_latch_column = column;
699 
700         if (shift & VIRTUAL_SHIFT) {
701             virtual_shift_down = 0;
702         }
703         if (shift & LEFT_SHIFT) {
704             left_shift_down = 0;
705             if (keyboard_shiftlock && (shiftl == KEY_LSHIFT)) {
706                 skip_release = 1;
707             }
708         }
709         if (shift & RIGHT_SHIFT) {
710             right_shift_down = 0;
711             if (keyboard_shiftlock && (shiftl == KEY_RSHIFT)) {
712                 skip_release = 1;
713             }
714         }
715 #if 0
716         if (shift & SHIFT_LOCK) {
717             keyboard_shiftlock = 0;
718             if (((shiftl == KEY_RSHIFT) && right_shift_down)
719                 || ((shiftl == KEY_LSHIFT) && left_shift_down)) {
720                 skip_release = 1;
721             }
722         }
723 #endif
724         /* when shift lock is released and shift lock is "locked", then exit
725            early and do nothing */
726         if (shift & SHIFT_LOCK) {
727             if (keyboard_shiftlock) {
728                 return 0;
729             }
730         }
731 
732         if (lcbm_defined()) {
733             if (shift & VIRTUAL_CBM) {
734                 virtual_cbm_down = 0;
735             }
736             if (shift & LEFT_CBM) {
737                 left_cbm_down = 0;
738             }
739         }
740 
741         if (lctrl_defined()) {
742             if (shift & VIRTUAL_CTRL) {
743                 virtual_ctrl_down = 0;
744             }
745             if (shift & LEFT_CTRL) {
746                 left_ctrl_down = 0;
747             }
748         }
749 
750         /* Map shift keys. */
751         if (right_shift_down > 0
752             || (virtual_shift_down > 0 && vshift == KEY_RSHIFT)
753             || (keyboard_shiftlock > 0 && shiftl == KEY_RSHIFT)) {
754             keyboard_set_latch_keyarr(kbd_rshiftrow, kbd_rshiftcol, 1);
755         } else {
756             keyboard_set_latch_keyarr(kbd_rshiftrow, kbd_rshiftcol, 0);
757         }
758 
759         if (left_shift_down > 0
760             || (virtual_shift_down > 0 && vshift == KEY_LSHIFT)
761             || (keyboard_shiftlock > 0 && shiftl == KEY_LSHIFT)) {
762             keyboard_set_latch_keyarr(kbd_lshiftrow, kbd_lshiftcol, 1);
763         } else {
764             keyboard_set_latch_keyarr(kbd_lshiftrow, kbd_lshiftcol, 0);
765         }
766 
767         if (lcbm_defined()) {
768             if (left_cbm_down > 0
769                 || (virtual_cbm_down > 0 && vcbm == KEY_LCBM)) {
770                 keyboard_set_latch_keyarr(kbd_lcbmrow, kbd_lcbmcol, 1);
771             } else {
772                 keyboard_set_latch_keyarr(kbd_lcbmrow, kbd_lcbmcol, 0);
773             }
774         }
775 
776         if (lctrl_defined()) {
777             if (left_ctrl_down > 0
778                 || (virtual_ctrl_down > 0 && vctrl == KEY_LCTRL)) {
779                 keyboard_set_latch_keyarr(kbd_lctrlrow, kbd_lctrlcol, 1);
780             } else {
781                 keyboard_set_latch_keyarr(kbd_lctrlrow, kbd_lctrlcol, 0);
782             }
783         }
784         return !skip_release;
785     }
786 
787     return 0;
788 }
789 
790 /* release a key, this is called by the UI */
keyboard_key_released(signed long key,int mod)791 void keyboard_key_released(signed long key, int mod)
792 {
793     int i, j, latch;
794 
795     /* log_debug("%s: %3i %04x", __func__, key, mod); */
796 
797     if (event_playback_active()) {
798         return;
799     }
800 
801     /* Restore */
802     if (((key == key_ctrl_restore1) || (key == key_ctrl_restore2))
803         && machine_has_restore_key()) {
804         keyboard_restore_released();
805         return;
806     }
807 
808     if (key_joy_keypad_func != NULL) {
809         for (i = 0; i < KBD_JOY_KEYPAD_ROWS; ++i) {
810             for (j = 0; j < KBD_JOY_KEYPAD_COLS; ++j) {
811                 if (key == key_joy_keypad[i][j]) {
812                     key_joy_keypad_func(i, j, 0);
813                     return;
814                 }
815             }
816         }
817     }
818 
819 #ifdef COMMON_JOYKEYS
820     for (i = 0; i < JOYSTICK_NUM; ++i) {
821         if (joystick_port_map[i] == JOYDEV_NUMPAD
822             || joystick_port_map[i] == JOYDEV_KEYSET1
823             || joystick_port_map[i] == JOYDEV_KEYSET2) {
824             if (joystick_check_clr(key, joystick_port_map[i] - JOYDEV_NUMPAD, 1 + i)) {
825                 return;
826             }
827         }
828     }
829 #endif
830 
831     if (keyconvmap == NULL) {
832         return;
833     }
834 
835     latch = 0;
836 
837     for (i = 0; i < keyc_num; i++) {
838         if (key == keyconvmap[i].sym) {
839             if ((keyconvmap[i].shift & ALT_MAP) && !key_alternative) {
840                 continue;
841             }
842 
843             if (keyboard_key_released_matrix(keyconvmap[i].row,
844                                              keyconvmap[i].column,
845                                              keyconvmap[i].shift)) {
846                 latch = 1;
847                 keyboard_set_latch_keyarr(keyconvmap[i].row,
848                                           keyconvmap[i].column, 0);
849                 if (!(keyconvmap[i].shift & ALLOW_OTHER)
850                     /*|| (right_shift_down + left_shift_down) == 0*/) {
851                     break;
852                 }
853             }
854         }
855     }
856 
857     if (latch) {
858         if (network_connected()) {
859             CLOCK delay = KEYBOARD_RAND();
860             network_event_record(EVENT_KEYBOARD_DELAY, (void *)&delay, sizeof(delay));
861             network_event_record(EVENT_KEYBOARD_MATRIX, (void *)latch_keyarr, sizeof(latch_keyarr));
862         } else {
863             alarm_set(keyboard_alarm, maincpu_clk + KEYBOARD_RAND());
864         }
865     }
866 }
867 
keyboard_key_clear_internal(void)868 static void keyboard_key_clear_internal(void)
869 {
870     keyboard_clear_keymatrix();
871     joystick_clear_all();
872     virtual_cbm_down = virtual_shift_down =
873         left_shift_down = right_shift_down = keyboard_shiftlock = 0;
874 #ifdef COMMON_JOYKEYS
875     joystick_joypad_clear();
876 #endif
877 }
878 
keyboard_key_clear(void)879 void keyboard_key_clear(void)
880 {
881     if (event_playback_active()) {
882         return;
883     }
884 
885     if (network_connected()) {
886         network_event_record(EVENT_KEYBOARD_CLEAR, NULL, 0);
887         return;
888     }
889 
890     keyboard_key_clear_internal();
891 }
892 
keyboard_set_keyarr_any(int row,int col,int value)893 void keyboard_set_keyarr_any(int row, int col, int value)
894 {
895     signed long sym;
896 
897     if (row < 0) {
898         if ((row == KBD_ROW_RESTORE_1) && (col == KBD_COL_RESTORE_1)) {
899             sym = key_ctrl_restore1;
900         } else if ((row == KBD_ROW_RESTORE_2) && (col == KBD_COL_RESTORE_2)) {
901             sym = key_ctrl_restore2;
902         } else if ((row == KBD_ROW_4080COLUMN) && (col == KBD_COL_4080COLUMN)) {
903             sym = key_ctrl_column4080;
904         } else if ((row == KBD_ROW_CAPSLOCK) && (col == KBD_COL_CAPSLOCK)) {
905             sym = key_ctrl_caps;
906         } else if ((row == KBD_ROW_JOY_KEYPAD) &&
907             (col >= 0) && (col < KBD_JOY_KEYPAD_NUMKEYS)) {
908             sym = key_joy_keypad[col / KBD_JOY_KEYPAD_COLS][col % KBD_JOY_KEYPAD_COLS];
909         } else {
910             return;
911         }
912 
913         if (value) {
914             keyboard_key_pressed(sym, 0);
915         } else {
916             keyboard_key_released(sym, 0);
917         }
918     } else {
919         keyboard_set_keyarr(row, col, value);
920     }
921 }
922 
923 /*-----------------------------------------------------------------------*/
924 
keyboard_alternative_set(int alternative)925 void keyboard_alternative_set(int alternative)
926 {
927     key_alternative = alternative;
928 }
929 
930 /*-----------------------------------------------------------------------*/
931 
keyboard_keyconvmap_alloc(void)932 static void keyboard_keyconvmap_alloc(void)
933 {
934 #define KEYCONVMAP_SIZE_MIN 150
935 
936     keyconvmap = lib_malloc(KEYCONVMAP_SIZE_MIN * sizeof(keyboard_conv_t));
937     keyc_num = 0;
938     keyc_mem = KEYCONVMAP_SIZE_MIN - 1;
939     keyconvmap[0].sym = ARCHDEP_KEYBOARD_SYM_NONE;
940 }
941 
keyboard_keyconvmap_free(void)942 static void keyboard_keyconvmap_free(void)
943 {
944     lib_free(keyconvmap);
945     keyconvmap = NULL;
946 }
947 
keyboard_keyconvmap_realloc(void)948 static void keyboard_keyconvmap_realloc(void)
949 {
950     keyc_mem += keyc_mem / 2;
951     keyconvmap = lib_realloc(keyconvmap, (keyc_mem + 1) * sizeof(keyboard_conv_t));
952 }
953 
954 /*-----------------------------------------------------------------------*/
955 
956 static int keyboard_parse_keymap(const char *filename, int child);
957 
keyboard_keyword_rowcol(int * row,int * col)958 static int keyboard_keyword_rowcol(int *row, int *col)
959 {
960     int r, c;
961     char *p;
962 
963     p = strtok(NULL, " \t,");
964     if (p != NULL) {
965         r = atoi(p);
966         p = strtok(NULL, " \t,");
967         if (p != NULL) {
968             c = atoi(p);
969             /* no error */
970             *row = r; *col = c;
971             return 0;
972         }
973     }
974     return -1;
975 }
976 
keyboard_keyword_lshift(void)977 static int keyboard_keyword_lshift(void)
978 {
979     return keyboard_keyword_rowcol(&kbd_lshiftrow, &kbd_lshiftcol);
980 }
981 
keyboard_keyword_rshift(void)982 static int keyboard_keyword_rshift(void)
983 {
984     return keyboard_keyword_rowcol(&kbd_rshiftrow, &kbd_rshiftcol);
985 }
986 
keyboard_keyword_vshiftl(void)987 static int keyboard_keyword_vshiftl(void)
988 {
989     char *p = strtok(NULL, " \t,\r");
990 
991     if (!strcmp(p, "RSHIFT")) {
992         return KEY_RSHIFT;
993     } else if (!strcmp(p, "LSHIFT")) {
994         return KEY_LSHIFT;
995     }
996 
997     return -1;
998 }
999 
keyboard_keyword_vshift(void)1000 static int keyboard_keyword_vshift(void)
1001 {
1002     int ret = keyboard_keyword_vshiftl();
1003     if (ret < 0) {
1004         return -1;
1005     }
1006     vshift = ret;
1007     return 0;
1008 }
1009 
keyboard_keyword_shiftl(void)1010 static int keyboard_keyword_shiftl(void)
1011 {
1012     int ret = keyboard_keyword_vshiftl();
1013     if (ret < 0) {
1014         return -1;
1015     }
1016     shiftl = ret;
1017     return 0;
1018 }
1019 
keyboard_keyword_lcbm(void)1020 static int keyboard_keyword_lcbm(void)
1021 {
1022     return keyboard_keyword_rowcol(&kbd_lcbmrow, &kbd_lcbmcol);
1023 }
1024 
keyboard_keyword_cbm(void)1025 static int keyboard_keyword_cbm(void)
1026 {
1027     char *p = strtok(NULL, " \t,\r");
1028 
1029     if (!strcmp(p, "LCBM")) {
1030         return KEY_LCBM;
1031     }
1032     return -1;
1033 }
1034 
keyboard_keyword_vcbm(void)1035 static int keyboard_keyword_vcbm(void)
1036 {
1037     int ret = keyboard_keyword_cbm();
1038     if (ret < 0) {
1039         return -1;
1040     }
1041     vcbm = ret;
1042     return 0;
1043 }
1044 
keyboard_keyword_lctrl(void)1045 static int keyboard_keyword_lctrl(void)
1046 {
1047     return keyboard_keyword_rowcol(&kbd_lctrlrow, &kbd_lctrlcol);
1048 }
1049 
keyboard_keyword_ctrl(void)1050 static int keyboard_keyword_ctrl(void)
1051 {
1052     char *p = strtok(NULL, " \t,\r");
1053 
1054     if (!strcmp(p, "LCTRL")) {
1055         return KEY_LCTRL;
1056     }
1057     return -1;
1058 }
1059 
keyboard_keyword_vctrl(void)1060 static int keyboard_keyword_vctrl(void)
1061 {
1062     int ret = keyboard_keyword_ctrl();
1063     if (ret < 0) {
1064         return -1;
1065     }
1066     vctrl = ret;
1067     return 0;
1068 }
1069 
keyboard_keyword_clear(void)1070 static void keyboard_keyword_clear(void)
1071 {
1072     int i, j;
1073 
1074     keyc_num = 0;
1075     keyconvmap[0].sym = ARCHDEP_KEYBOARD_SYM_NONE;
1076     key_ctrl_restore1 = -1;
1077     key_ctrl_restore2 = -1;
1078     key_ctrl_caps = -1;
1079     key_ctrl_column4080 = -1;
1080     vshift = KEY_NONE;
1081     shiftl = KEY_NONE;
1082     vcbm = KEY_NONE;
1083     vctrl = KEY_NONE;
1084     kbd_lshiftrow = -1;
1085     kbd_lshiftcol = -1;
1086     kbd_rshiftrow = -1;
1087     kbd_rshiftcol = -1;
1088     kbd_lcbmrow   = -1;
1089     kbd_lcbmcol   = -1;
1090     kbd_lctrlrow  = -1;
1091     kbd_lctrlcol  = -1;
1092 
1093     for (i = 0; i < KBD_JOY_KEYPAD_ROWS; ++i) {
1094         for (j = 0; j < KBD_JOY_KEYPAD_COLS; ++j) {
1095             key_joy_keypad[i][j] = -1;
1096         }
1097     }
1098 }
1099 
keyboard_keyword_include(void)1100 static void keyboard_keyword_include(void)
1101 {
1102     char *key;
1103 
1104     key = strtok(NULL, " \t");
1105     keyboard_parse_keymap(key, 1);
1106 }
1107 
keyboard_keysym_undef(signed long sym)1108 static void keyboard_keysym_undef(signed long sym)
1109 {
1110     int i;
1111 
1112     if (sym >= 0) {
1113         for (i = 0; i < keyc_num; i++) {
1114             if (keyconvmap[i].sym == sym) {
1115                 if (keyc_num) {
1116                     keyconvmap[i] = keyconvmap[--keyc_num];
1117                 }
1118                 keyconvmap[keyc_num].sym = ARCHDEP_KEYBOARD_SYM_NONE;
1119                 break;
1120             }
1121         }
1122     }
1123 }
1124 
keyboard_keyword_undef(void)1125 static void keyboard_keyword_undef(void)
1126 {
1127     char *key;
1128 
1129     /* TODO: this only unsets from the main table, not for joysticks
1130      *       inventing another keyword to reset joysticks only is perhaps a
1131      *       good idea.
1132      */
1133     key = strtok(NULL, " \t");
1134     keyboard_keysym_undef(kbd_arch_keyname_to_keynum(key));
1135 }
1136 
keyboard_parse_keyword(char * buffer,int line,const char * filename)1137 static void keyboard_parse_keyword(char *buffer, int line, const char *filename)
1138 {
1139     int ret = 0;
1140     char *key;
1141 
1142     key = strtok(buffer + 1, " \t:");
1143 
1144     if (!strcmp(key, "LSHIFT")) {
1145         ret = keyboard_keyword_lshift();
1146     } else if (!strcmp(key, "RSHIFT")) {
1147         ret = keyboard_keyword_rshift();
1148     } else if (!strcmp(key, "VSHIFT")) {
1149         ret = keyboard_keyword_vshift();
1150     } else if (!strcmp(key, "SHIFTL")) {
1151         ret = keyboard_keyword_shiftl();
1152     } else if (!strcmp(key, "LCBM")) {
1153         ret = keyboard_keyword_lcbm();
1154     } else if (!strcmp(key, "VCBM")) {
1155         ret = keyboard_keyword_vcbm();
1156     } else if (!strcmp(key, "LCTRL")) {
1157         ret = keyboard_keyword_lctrl();
1158     } else if (!strcmp(key, "VCTRL")) {
1159         ret = keyboard_keyword_vctrl();
1160     } else if (!strcmp(key, "CLEAR")) {
1161         keyboard_keyword_clear();
1162     } else if (!strcmp(key, "INCLUDE")) {
1163         keyboard_keyword_include();
1164     } else if (!strcmp(key, "UNDEF")) {
1165         keyboard_keyword_undef();
1166     } else {
1167         log_error(keyboard_log, "%s:%d: unknown keyword (%s).", filename, line, key);
1168     }
1169 
1170     if (ret) {
1171         log_error(keyboard_log, "%s:%d: Bad keyword (%s).", filename, line, key);
1172     }
1173 }
1174 
keyboard_parse_set_pos_row(signed long sym,int row,int col,int shift)1175 static void keyboard_parse_set_pos_row(signed long sym, int row, int col,
1176                                        int shift)
1177 {
1178     int i;
1179 
1180     for (i = 0; i < keyc_num; i++) {
1181         if (sym == keyconvmap[i].sym
1182             && !(keyconvmap[i].shift & ALLOW_OTHER)
1183             && !(keyconvmap[i].shift & ALT_MAP)) {
1184             keyconvmap[i].row = row;
1185             keyconvmap[i].column = col;
1186             keyconvmap[i].shift = shift;
1187             break;
1188         }
1189     }
1190 
1191     /* Not in table -> add.  */
1192     if (i >= keyc_num) {
1193         /* Table too small -> realloc.  */
1194         if (keyc_num >= keyc_mem) {
1195             keyboard_keyconvmap_realloc();
1196         }
1197 
1198         if (keyc_num < keyc_mem) {
1199             keyconvmap[keyc_num].sym = sym;
1200             keyconvmap[keyc_num].row = row;
1201             keyconvmap[keyc_num].column = col;
1202             keyconvmap[keyc_num].shift = shift;
1203             keyconvmap[++keyc_num].sym = ARCHDEP_KEYBOARD_SYM_NONE;
1204         }
1205     }
1206 }
1207 
keyboard_parse_set_neg_row(signed long sym,int row,int col)1208 static int keyboard_parse_set_neg_row(signed long sym, int row, int col)
1209 {
1210     if ((row == KBD_ROW_JOY_KEYMAP_A) &&
1211         (col >= 0) && (col < JOYSTICK_KEYSET_NUM_KEYS)) {
1212 #ifdef COMMON_JOYKEYS
1213         joykeys[JOYSTICK_KEYSET_IDX_A][col] = (int)sym;
1214 #endif
1215     } else if ((row == KBD_ROW_JOY_KEYMAP_B) &&
1216         (col >= 0) && (col < JOYSTICK_KEYSET_NUM_KEYS)) {
1217 #ifdef COMMON_JOYKEYS
1218         joykeys[JOYSTICK_KEYSET_IDX_B][col] = (int)sym;
1219 #endif
1220     } else if ((row == KBD_ROW_RESTORE_1) && (col == KBD_COL_RESTORE_1)) {
1221         key_ctrl_restore1 = sym;
1222     } else if ((row == KBD_ROW_RESTORE_2) && (col == KBD_COL_RESTORE_2)) {
1223         key_ctrl_restore2 = sym;
1224     } else if ((row == KBD_ROW_4080COLUMN) && (col == KBD_COL_4080COLUMN)) {
1225         key_ctrl_column4080 = sym;
1226     } else if ((row == KBD_ROW_CAPSLOCK) && (col == KBD_COL_CAPSLOCK)) {
1227         key_ctrl_caps = sym;
1228     } else if ((row == KBD_ROW_JOY_KEYPAD) &&
1229         (col >= 0) && (col < KBD_JOY_KEYPAD_NUMKEYS)) {
1230         key_joy_keypad[col / KBD_JOY_KEYPAD_COLS][col % KBD_JOY_KEYPAD_COLS] = sym;
1231     } else {
1232         return -1;
1233     }
1234     return 0;
1235 }
1236 
keyboard_parse_entry(char * buffer,int line,const char * filename)1237 static void keyboard_parse_entry(char *buffer, int line, const char *filename)
1238 {
1239     char *key, *p;
1240     signed long sym;
1241     long row;
1242     int col;
1243     int shift = 0;
1244 
1245     key = strtok(buffer, " \t:");
1246 
1247     sym = kbd_arch_keyname_to_keynum(key);
1248 
1249     /* log_debug("%s: %s %i", __func__, key, sym); */
1250 
1251     if (sym < 0) {
1252         log_error(keyboard_log, "Could not find key `%s'!", key);
1253         return;
1254     }
1255 
1256     p = strtok(NULL, " \t,");
1257     if (p != NULL) {
1258         row = strtol(p, NULL, 10);
1259         p = strtok(NULL, " \t,");
1260         if (p != NULL) {
1261             col = atoi(p);  /* YUCK! */
1262             p = strtok(NULL, " \t");
1263             if (p != NULL || row < 0) {
1264                 if (p != NULL) {
1265                     shift = atoi(p);
1266                 }
1267 
1268                 if (row >= 0) {
1269                     keyboard_parse_set_pos_row(sym, (int)row, col, shift);
1270                 } else {
1271                     if (keyboard_parse_set_neg_row(sym, (int)row, col) < 0) {
1272                         log_error(keyboard_log,
1273                                   "%s:%d: Bad row/column value (%ld/%d) for keysym `%s'.",
1274                                   filename, line, row, col, key);
1275                     }
1276                 }
1277 
1278                 /* printf("%s:%d: %s %d %d (%04x)\n", filename, line, key, row, col, shift); */
1279 
1280                 /* sanity checks */
1281 
1282                 if (((shift & LEFT_SHIFT) && ((shift & RIGHT_SHIFT) || (shift & SHIFT_LOCK))) ||
1283                     ((shift & RIGHT_SHIFT) && ((shift & LEFT_SHIFT) || (shift & SHIFT_LOCK))) ||
1284                     ((shift & SHIFT_LOCK) && ((shift & RIGHT_SHIFT) || (shift & LEFT_SHIFT)))) {
1285                     log_warning(keyboard_log, "%s:%d: only one of \"right shift\", \"left shift\" or \"shift lock\" flags should be used.", filename, line);
1286                 }
1287                 if (((shift & VIRTUAL_SHIFT) && ((shift & VIRTUAL_CBM) || (shift & VIRTUAL_CTRL))) ||
1288                     ((shift & VIRTUAL_CBM) && ((shift & VIRTUAL_SHIFT) || (shift & VIRTUAL_CTRL))) ||
1289                     ((shift & VIRTUAL_CTRL) && ((shift & VIRTUAL_CBM) || (shift & VIRTUAL_SHIFT)))) {
1290                     log_warning(keyboard_log, "%s:%d: only one of \"virtual shift\", \"virtual ctrl\" or \"virtual cbm\" flags should be used.", filename, line);
1291                 }
1292 
1293                 /* sanity checks for shift */
1294 
1295                 if (shift & VIRTUAL_SHIFT) {
1296                     if (!vshift_defined()) {
1297                         log_warning(keyboard_log, "%s:%d: virtual shift flag used but no !VSHIFT defined", filename, line);
1298                     }
1299                 }
1300 
1301                 if (shift & LEFT_SHIFT) {
1302                     if (!lshift_defined()) {
1303                         log_warning(keyboard_log, "%s:%d: SHIFT flag used but no !LSHIFT defined", filename, line);
1304                     } else {
1305                         if ((row != kbd_lshiftrow) || (col != kbd_lshiftcol)) {
1306                             log_warning(keyboard_log, "%s:%d: SHIFT flag used but row and/or col differs from !LSHIFT definition", filename, line);
1307                         }
1308                     }
1309                 }
1310                 if (shift & RIGHT_SHIFT) {
1311                     if (!rshift_defined()) {
1312                         log_warning(keyboard_log, "%s:%d: SHIFT flag used but no !RSHIFT defined", filename, line);
1313                     } else {
1314                         if ((row != kbd_rshiftrow) || (col != kbd_rshiftcol)) {
1315                             log_warning(keyboard_log, "%s:%d: SHIFT flag used but row and/or col differs from !RSHIFT definition", filename, line);
1316                         }
1317                     }
1318                 }
1319                 if (shift & SHIFT_LOCK) {
1320                     if (!shiftlock_defined()) {
1321                         log_warning(keyboard_log, "%s:%d: SHIFT-lock flag used but no !SHIFTL defined", filename, line);
1322                     } else {
1323                         if (shiftl == KEY_RSHIFT) {
1324                             if ((row != kbd_rshiftrow) || (col != kbd_rshiftcol)) {
1325                                 log_warning(keyboard_log, "%s:%d: SHIFT-lock flag used but row and/or col differs from !RSHIFT definition", filename, line);
1326                             }
1327                         } else if (shiftl == KEY_LSHIFT) {
1328                             if ((row != kbd_lshiftrow) || (col != kbd_lshiftcol)) {
1329                                 log_warning(keyboard_log, "%s:%d: SHIFT-lock flag used but row and/or col differs from !LSHIFT definition", filename, line);
1330                             }
1331                         }
1332                     }
1333                 }
1334 
1335                 if (lshift_defined()) {
1336                     if ((row == kbd_lshiftrow) && (col == kbd_lshiftcol)) {
1337                         if ((!(shift & LEFT_SHIFT)) && (!(shift & (RIGHT_SHIFT | SHIFT_LOCK)))) {
1338                             log_warning(keyboard_log, "%s:%d: !LSHIFT defined but key does not use SHIFT flag", filename, line);
1339                         }
1340                     }
1341                 }
1342                 if (rshift_defined()) {
1343                     if ((row == kbd_rshiftrow) && (col == kbd_rshiftcol)) {
1344                         if ((!(shift & RIGHT_SHIFT)) && (!(shift & (RIGHT_SHIFT | SHIFT_LOCK)))) {
1345                             log_warning(keyboard_log, "%s:%d: !RSHIFT defined but key does not use SHIFT flag", filename, line);
1346                         }
1347                     }
1348                 }
1349                 if (shiftlock_defined()) {
1350                         if (shiftl == KEY_RSHIFT) {
1351                             if ((row == kbd_rshiftrow) && (col == kbd_rshiftcol)) {
1352                                 if ((!(shift & SHIFT_LOCK)) && (!(shift & (RIGHT_SHIFT | LEFT_SHIFT)))) {
1353                                     log_warning(keyboard_log, "%s:%d: !SHIFTL defined but key does not use SHIFT-lock flag", filename, line);
1354                                 }
1355                             }
1356                         } else if (shiftl == KEY_LSHIFT) {
1357                             if ((row == kbd_lshiftrow) && (col == kbd_lshiftcol)) {
1358                                 if ((!(shift & SHIFT_LOCK)) && (!(shift & (RIGHT_SHIFT | LEFT_SHIFT)))) {
1359                                     log_warning(keyboard_log, "%s:%d: !SHIFTL defined but key does not use SHIFT-lock flag", filename, line);
1360                                 }
1361                             }
1362                         }
1363                 }
1364 
1365                 /* sanity checks for cbm */
1366                 if (shift & VIRTUAL_CBM) {
1367                     if (!vcbm_defined()) {
1368                         log_warning(keyboard_log, "%s:%d: virtual CBM flag used but no !VCBM defined", filename, line);
1369                     }
1370                 }
1371                 if (shift & LEFT_CBM) {
1372                     if (!lcbm_defined()) {
1373                         log_warning(keyboard_log, "%s:%d: CBM flag used but no !LCBM defined", filename, line);
1374                     } else {
1375                         if ((row != kbd_lcbmrow) || (col != kbd_lcbmcol)) {
1376                             log_warning(keyboard_log, "%s:%d: CBM flag used but row and/or col differs from !LCBM definition", filename, line);
1377                         }
1378                     }
1379                 }
1380                 if (lcbm_defined()) {
1381                     if ((row == kbd_lcbmrow) && (col == kbd_lcbmcol)) {
1382                         if (!(shift & LEFT_CBM)) {
1383                             log_warning(keyboard_log, "%s:%d: !LCBM defined but key does not use CBM flag", filename, line);
1384                         }
1385                     }
1386                 }
1387                 /* sanity checks for ctrl */
1388                 if (shift & VIRTUAL_CTRL) {
1389                     if (!vctrl_defined()) {
1390                         log_warning(keyboard_log, "%s:%d: virtual CTRL flag used but no !VCTRL defined", filename, line);
1391                     }
1392                 }
1393                 if (shift & LEFT_CTRL) {
1394                     if (!lctrl_defined()) {
1395                         log_warning(keyboard_log, "%s:%d: CTRL flag used but no !LCTRL defined", filename, line);
1396                     } else {
1397                         if ((row != kbd_lctrlrow) || (col != kbd_lctrlcol)) {
1398                             log_warning(keyboard_log, "%s:%d: CTRL flag used but row and/or col differs from !LCTRL definition", filename, line);
1399                         }
1400                     }
1401                 }
1402                 if (lctrl_defined()) {
1403                     if ((row == kbd_lctrlrow) && (col == kbd_lctrlcol)) {
1404                         if (!(shift & LEFT_CTRL)) {
1405                             log_warning(keyboard_log, "%s:%d: !LCTRL defined but key does not use CTRL flag", filename, line);
1406                         }
1407                     }
1408                 }
1409             }
1410         }
1411     }
1412 }
1413 
check_modifiers(const char * filename)1414 static int check_modifiers(const char *filename)
1415 {
1416     int n = 0;
1417     char *ms[8] = {
1418         "!LSHIFT ", "!RSHIFT ", "!VSHIFT! ", "!LCBM ", "!VCBM ", "!LCTRL ", "!VCTRL ", "!SHIFTL "
1419     };
1420 
1421     if (!lshift_defined()) {
1422         n |= (1 << 0);
1423     }
1424     if (!rshift_defined()) {
1425         n |= (1 << 1);
1426     }
1427     if (!vshift_defined()) {
1428         n |= (1 << 2);
1429     }
1430     if (!lcbm_defined()) {
1431         n |= (1 << 3);
1432     }
1433     if (!vcbm_defined()) {
1434         n |= (1 << 4);
1435     }
1436     if (!lctrl_defined()) {
1437         n |= (1 << 5);
1438     }
1439     if (!vctrl_defined()) {
1440         n |= (1 << 6);
1441     }
1442     if (!shiftlock_defined()) {
1443         n |= (1 << 7);
1444     }
1445     if (n) {
1446         log_warning(keyboard_log, "%s: %s%s%s%s%s%s%s%snot defined.",
1447             filename,
1448             n & (1 << 0) ? ms[0] : "",
1449             n & (1 << 1) ? ms[1] : "",
1450             n & (1 << 2) ? ms[2] : "",
1451             n & (1 << 3) ? ms[3] : "",
1452             n & (1 << 4) ? ms[4] : "",
1453             n & (1 << 5) ? ms[5] : "",
1454             n & (1 << 6) ? ms[6] : "",
1455             n & (1 << 7) ? ms[7] : ""
1456         );
1457         return -1;
1458     }
1459     return 0;
1460 }
1461 
keyboard_parse_keymap(const char * filename,int child)1462 static int keyboard_parse_keymap(const char *filename, int child)
1463 {
1464     FILE *fp;
1465     char *complete_path = NULL;
1466     char buffer[1024];
1467     int line = 0;
1468 
1469     DBG((">keyboard_parse_keymap(%s)\n", filename));
1470 
1471     /* open in binary mode so the newline system doesn't matter */
1472     fp = sysfile_open(filename, &complete_path, "rb");
1473 
1474     if (fp == NULL) {
1475         log_message(keyboard_log, "Error loading keymap `%s'->`%s'.", filename, complete_path ? complete_path : "<empty/null>");
1476         DBG(("<keyboard_parse_keymap(%s) ERROR\n", filename));
1477         return -1;
1478     }
1479 
1480     log_message(keyboard_log, "%s keymap `%s'.", child ? " including" : "Loading", complete_path);
1481 
1482     do {
1483         buffer[0] = 0;
1484         if (fgets(buffer, 999, fp)) {
1485             char *p;
1486             long blen = (long)strlen(buffer);
1487 
1488             line++;
1489 
1490             if (blen == 0) {
1491                 break;
1492             }
1493 
1494             /* remove trailing CR or/and LF */
1495             blen--;
1496             while (blen >= 0 && (buffer[blen] == '\n' || buffer[blen] == '\r')) {
1497                 buffer[blen--] = '\0';
1498             }
1499 
1500             /* remove comments */
1501             if ((p = strchr(buffer, '#'))) {
1502                 *p = 0;
1503             }
1504 
1505             switch (*buffer) {
1506                 case 0:
1507                     break;
1508                 case '!':
1509                     /* keyword handling */
1510                     keyboard_parse_keyword(buffer, line, filename);
1511                     break;
1512                 default:
1513                     /* table entry handling */
1514                     keyboard_parse_entry(buffer, line, filename);
1515                     break;
1516             }
1517         }
1518     } while (!feof(fp));
1519     fclose(fp);
1520 
1521     lib_free(complete_path);
1522 
1523     check_modifiers(filename);
1524 
1525     DBG(("<keyboard_parse_keymap OK\n"));
1526     return 0;
1527 }
1528 
keyboard_keymap_load(const char * filename)1529 static int keyboard_keymap_load(const char *filename)
1530 {
1531     DBG((">keyboard_keymap_load(%s)\n", filename));
1532     if (filename == NULL) {
1533         DBG(("<keyboard_keymap_load ERROR\n"));
1534         return -1;
1535     }
1536 
1537     if (keyconvmap != NULL) {
1538         keyboard_keyconvmap_free();
1539     }
1540 
1541     keyboard_keyconvmap_alloc();
1542 
1543     DBG(("<keyboard_keymap_load -> keyboard_parse_keymap\n"));
1544     return keyboard_parse_keymap(filename, 0);
1545 }
1546 
1547 /*-----------------------------------------------------------------------*/
1548 
keyboard_set_map_any(signed long sym,int row,int col,int shift)1549 void keyboard_set_map_any(signed long sym, int row, int col, int shift)
1550 {
1551     if (row >= 0) {
1552         keyboard_parse_set_pos_row(sym, row, col, shift);
1553     } else {
1554         keyboard_parse_set_neg_row(sym, row, col);
1555     }
1556 }
1557 
keyboard_set_unmap_any(signed long sym)1558 void keyboard_set_unmap_any(signed long sym)
1559 {
1560     keyboard_keysym_undef(sym);
1561 }
1562 
keyboard_keymap_dump(const char * filename)1563 int keyboard_keymap_dump(const char *filename)
1564 {
1565     FILE *fp;
1566     int i, j;
1567 
1568     if (filename == NULL) {
1569         return -1;
1570     }
1571 
1572     fp = fopen(filename, MODE_WRITE_TEXT);
1573 
1574     if (fp == NULL) {
1575         return -1;
1576     }
1577 
1578     fprintf(fp, "# VICE keyboard mapping file\n"
1579             "#\n"
1580             "# A Keyboard map is read in as patch to the current map.\n"
1581             "#\n"
1582             "# File format:\n"
1583             "# - comment lines start with '#'\n"
1584             "# - keyword lines start with '!keyword'\n"
1585             "# - normal line has 'keysym/scancode row column shiftflag'\n"
1586             "#\n"
1587             "# Keywords and their lines are:\n"
1588             "# '!CLEAR'               clear whole table\n"
1589             "# '!INCLUDE filename'    read file as mapping file\n"
1590             "# '!LSHIFT row col'      left shift keyboard row/column\n"
1591             "# '!RSHIFT row col'      right shift keyboard row/column\n"
1592             "# '!VSHIFT shiftkey'     virtual shift key (RSHIFT or LSHIFT)\n"
1593             "# '!SHIFTL shiftkey'     shift lock key (RSHIFT or LSHIFT)\n"
1594             "# '!LCTRL row col'       left control keyboard row/column\n"
1595             "# '!VCTRL ctrlkey'       virtual control key (LCTRL)\n"
1596             "# '!LCBM row col'        left CBM keyboard row/column\n"
1597             "# '!VCBM cbmkey'         virtual CBM key (LCBM)\n"
1598             "# '!UNDEF keysym'        remove keysym from table\n"
1599             "#\n"
1600             "# Shiftflag can have the values:\n"
1601             "# 0      key is not shifted for this keysym/scancode\n"
1602             "# 1      key is combined with shift for this keysym/scancode\n"
1603             "# 2      key is left shift on emulated machine\n"
1604             "# 4      key is right shift on emulated machine\n"
1605             "# 8      key can be shifted or not with this keysym/scancode\n"
1606             "# 16     deshift key for this keysym/scancode\n"
1607             "# 32     another definition for this keysym/scancode follows\n"
1608             "# 64     key is shift-lock on emulated machine\n"
1609             "# 128    shift modifier required on host\n"
1610             "# 256    key is used for an alternative keyboard mapping\n"
1611             "# 512    alt-r (alt-gr) modifier required on host\n"
1612             "# 1024   ctrl modifier required on host\n"
1613             "# 2048   key is combined with cbm for this keysym/scancode\n"
1614             "# 4096   key is combined with ctrl for this keysym/scancode\n"
1615             "# 8192   key is (left) cbm on emulated machine\n"
1616             "# 16384  key is (left) ctrl on emulated machine\n"
1617             "#\n"
1618             "# to migrate older keymaps and use the CBM and/or CTRL related features:\n"
1619             "#\n"
1620             "# - define !LCTRL, !VCTRL, !LCBM, !VCBM\n"
1621             "# - add 'key is (left) cbm/ctrl on emulated machine' flags to\n"
1622             "#   all keys that map to the cbm or ctrl key respectively.\n"
1623             "#\n"
1624             "# after that the virtual cbm/ctrl flags and requiring host modifiers\n"
1625             "# should work as expected. keep an eye on the error messages.\n"
1626             "#\n"
1627             "# Negative row values:\n"
1628             "# 'keysym -1 n' joystick keymap A, direction n\n"
1629             "# 'keysym -2 n' joystick keymap B, direction n\n"
1630             "# 'keysym -3 0' first RESTORE key\n"
1631             "# 'keysym -3 1' second RESTORE key\n"
1632             "# 'keysym -4 0' 40/80 column key\n"
1633             "# 'keysym -4 1' CAPS (ASCII/DIN) key\n"
1634             "# 'keysym -5 n' joyport keypad, key n\n"
1635             "#\n"
1636             "# Joystick direction values:\n"
1637             "# 0      Fire\n"
1638             "# 1      South/West\n"
1639             "# 2      South\n"
1640             "# 3      South/East\n"
1641             "# 4      West\n"
1642             "# 5      East\n"
1643             "# 6      North/West\n"
1644             "# 7      North\n"
1645             "# 8      North/East\n"
1646             "#\n"
1647             "# Joyport keypad key layout:\n"
1648             "# --------------------------\n"
1649             "# |  0 |  1 |  2 |  3 |  4 |\n"
1650             "# --------------------------\n"
1651             "# |  5 |  6 |  7 |  8 |  9 |\n"
1652             "# --------------------------\n"
1653             "# | 10 | 11 | 12 | 13 | 14 |\n"
1654             "# --------------------------\n"
1655             "# | 15 | 16 | 17 | 18 | 19 |\n"
1656             "# --------------------------\n"
1657             "#\n"
1658             "# When a bigger spaced key is used,\n"
1659             "# it uses the upper left most key value.\n"
1660            );
1661 
1662     /* FIXME: output the keyboard matrix for the respective target */
1663 
1664     fprintf(fp, "!CLEAR\n");
1665     if (lshift_defined()) {
1666         fprintf(fp, "!LSHIFT %d %d\n", kbd_lshiftrow, kbd_lshiftcol);
1667     }
1668     if (rshift_defined()) {
1669         fprintf(fp, "!RSHIFT %d %d\n", kbd_rshiftrow, kbd_rshiftcol);
1670     }
1671     if (vshift_defined()) {
1672         fprintf(fp, "!VSHIFT %s\n", (vshift == KEY_RSHIFT) ? "RSHIFT" : "LSHIFT");
1673     }
1674     if (shiftlock_defined()) {
1675         fprintf(fp, "!SHIFTL %s\n", (shiftl == KEY_RSHIFT) ? "RSHIFT" : "LSHIFT");
1676     }
1677     if (lctrl_defined()) {
1678         fprintf(fp, "!LCTRL %d %d\n", kbd_lctrlrow, kbd_lctrlcol);
1679     }
1680     if (vctrl_defined()) {
1681         fprintf(fp, "!VCTRL %s\n", (vctrl == KEY_LCTRL) ? "LCTRL" : "?");
1682     }
1683     if (lcbm_defined()) {
1684         fprintf(fp, "!LCBM %d %d\n", kbd_lcbmrow, kbd_lcbmcol);
1685     }
1686     if (vcbm_defined()) {
1687         fprintf(fp, "!VCBM %s\n", (vcbm == KEY_LCBM) ? "LCBM" : "?");
1688     }
1689     fprintf(fp, "\n");
1690 
1691     for (i = 0; keyconvmap[i].sym != ARCHDEP_KEYBOARD_SYM_NONE; i++) {
1692         fprintf(fp, "%s %d %d %u\n",
1693                 kbd_arch_keynum_to_keyname(keyconvmap[i].sym),
1694                 keyconvmap[i].row, keyconvmap[i].column,
1695                 keyconvmap[i].shift);
1696     }
1697     fprintf(fp, "\n");
1698 
1699     if ((key_ctrl_restore1 != -1) || (key_ctrl_restore2 != -1)) {
1700         fprintf(fp, "#\n"
1701                 "# Restore key mappings\n"
1702                 "#\n");
1703         if (key_ctrl_restore1 != -1) {
1704             fprintf(fp, "%s -3 0\n",
1705                     kbd_arch_keynum_to_keyname(key_ctrl_restore1));
1706         }
1707         if (key_ctrl_restore2 != -1) {
1708             fprintf(fp, "%s -3 1\n",
1709                     kbd_arch_keynum_to_keyname(key_ctrl_restore2));
1710         }
1711         fprintf(fp, "\n");
1712     }
1713 
1714     if (key_ctrl_column4080 != -1) {
1715         fprintf(fp, "#\n"
1716                 "# 40/80 column key mapping\n"
1717                 "#\n");
1718         fprintf(fp, "%s -4 0\n",
1719                 kbd_arch_keynum_to_keyname(key_ctrl_column4080));
1720         fprintf(fp, "\n");
1721     }
1722 
1723     if (key_ctrl_caps != -1) {
1724         fprintf(fp, "#\n"
1725                 "# CAPS (ASCII/DIN) key mapping\n"
1726                 "#\n");
1727         fprintf(fp, "%s -4 1\n",
1728                 kbd_arch_keynum_to_keyname(key_ctrl_caps));
1729         fprintf(fp, "\n");
1730     }
1731 
1732     fprintf(fp, "#\n"
1733                 "# joyport attached keypad key mapping\n"
1734                 "#\n");
1735     for (i = 0; i < KBD_JOY_KEYPAD_ROWS; ++i) {
1736         for (j = 0; j < KBD_JOY_KEYPAD_COLS; ++j) {
1737             if (key_joy_keypad[i][j] != -1) {
1738                 fprintf(fp, "%s -5 %d\n",
1739                     kbd_arch_keynum_to_keyname(key_joy_keypad[i][j]), (i * KBD_JOY_KEYPAD_COLS) + j);
1740             }
1741         }
1742     }
1743 #ifdef COMMON_JOYKEYS
1744     for (i = 0; i < JOYSTICK_KEYSET_NUM_KEYS; i++) {
1745         if (joykeys[JOYSTICK_KEYSET_IDX_A][i] != ARCHDEP_KEYBOARD_SYM_NONE) {
1746             fprintf(fp, "#\n"
1747                     "# Joystick keyset A mapping\n"
1748                     "#\n");
1749             for (i = 0; i < JOYSTICK_KEYSET_NUM_KEYS; i++) {
1750                 if (joykeys[JOYSTICK_KEYSET_IDX_A][i] != ARCHDEP_KEYBOARD_SYM_NONE) {
1751                     fprintf(fp, "%s -1 %d\n",
1752                         kbd_arch_keynum_to_keyname(joykeys[JOYSTICK_KEYSET_IDX_A][i]), i);
1753                 }
1754             }
1755             fprintf(fp, "\n");
1756             break;
1757         }
1758     }
1759 
1760     for (i = 0; i < JOYSTICK_KEYSET_NUM_KEYS; i++) {
1761         if (joykeys[JOYSTICK_KEYSET_IDX_B][i] != ARCHDEP_KEYBOARD_SYM_NONE) {
1762             fprintf(fp, "#\n"
1763                     "# Joystick keyset B mapping\n"
1764                     "#\n");
1765             for (i = 0; i < JOYSTICK_KEYSET_NUM_KEYS; i++) {
1766                 if (joykeys[JOYSTICK_KEYSET_IDX_B][i] != ARCHDEP_KEYBOARD_SYM_NONE) {
1767                     fprintf(fp, "%s -2 %d\n",
1768                         kbd_arch_keynum_to_keyname(joykeys[JOYSTICK_KEYSET_IDX_B][i]), i);
1769                 }
1770             }
1771             fprintf(fp, "\n");
1772             break;
1773         }
1774     }
1775 #endif
1776 
1777     fclose(fp);
1778 
1779     return 0;
1780 }
1781 
1782 /*-----------------------------------------------------------------------*/
1783 
1784 #define NUM_KEYBOARD_MAPPINGS 4
1785 
1786 static char *machine_keymap_res_name_list[NUM_KEYBOARD_MAPPINGS] = {
1787     "KeymapSymFile",
1788     "KeymapPosFile",
1789     "KeymapUserSymFile",
1790     "KeymapUserPosFile",
1791 };
1792 
1793 char *machine_keymap_file_list[NUM_KEYBOARD_MAPPINGS] = {
1794     NULL, NULL, NULL, NULL
1795 };
1796 
machine_get_keymap_res_name(int val)1797 char *machine_get_keymap_res_name(int val)
1798 {
1799     if ((val < 0) || (val >= NUM_KEYBOARD_MAPPINGS)) {
1800         return NULL;
1801     }
1802     return machine_keymap_res_name_list[val];
1803 }
1804 
machine_num_keyboard_mappings(void)1805 int machine_num_keyboard_mappings(void)
1806 {
1807     return NUM_KEYBOARD_MAPPINGS;
1808 }
1809 
1810 
1811 static int machine_keyboard_mapping = 0;
1812 static int machine_keyboard_type = 0;
1813 
1814 static int try_set_keymap_file(int atidx, int idx, int mapping, int type);
1815 
1816 #define KBD_SWITCH_DEFAULT      0
1817 #define KBD_SWITCH_MAPPING      1
1818 #define KBD_SWITCH_INDEX        2
1819 #define KBD_SWITCH_TYPE         3
1820 static int switch_keymap_file(int sw, int *idxp, int *mapp, int *typep);
1821 
1822 /* (re)load keymap at index */
load_keymap_file(int val)1823 static int load_keymap_file(int val)
1824 {
1825     const char *name, *resname;
1826 
1827     if ((val < 0) || (val > KBD_INDEX_LAST)) {
1828         return -1;
1829     }
1830 
1831     if (load_keymap_ok)
1832     {
1833         resname = machine_get_keymap_res_name(val);
1834         if (!resname) {
1835             return -1;
1836         }
1837 
1838         if (resources_get_string(resname, &name) < 0) {
1839             return -1;
1840         }
1841 
1842         DBG(("load_keymap_file(%d) calls keyboard_keymap_load(%s)\n", val, name));
1843         if (keyboard_keymap_load(name) >= 0) {
1844 
1845         } else {
1846             log_error(keyboard_log, "Cannot load keymap `%s'.", name ? name : "<none/null>");
1847             return -1;
1848         }
1849     }
1850     return 0;
1851 }
1852 
1853 /*-----------------------------------------------------------------------*/
1854 
1855 /* handle change of "KeymapXXXXFile" */
keyboard_set_keymap_file(const char * val,void * param)1856 int keyboard_set_keymap_file(const char *val, void *param)
1857 {
1858     int oldindex, newindex;
1859 
1860     newindex = vice_ptr_to_int(param);
1861 
1862     DBG(("keyboard_set_keymap_file '%s' newidx:%d\n", val, newindex));
1863 
1864     /* FIXME: remove */
1865     if (newindex >= machine_num_keyboard_mappings()) {
1866         return -1;
1867     }
1868 
1869     if (resources_get_int("KeymapIndex", &oldindex) < 0) {
1870         return -1;
1871     }
1872 
1873     if (util_string_set(&machine_keymap_file_list[newindex], val)) {
1874         return 0;
1875     }
1876 
1877     /* reset oldindex -> reload keymap file if this keymap is active */
1878     if (oldindex == newindex) {
1879         if (resources_set_int("KeymapIndex", oldindex) < 0) {
1880             return -1;
1881         }
1882     }
1883     return 0;
1884 }
1885 
1886 /* handle change of "KeymapIndex" */
keyboard_set_keymap_index(int val,void * param)1887 int keyboard_set_keymap_index(int val, void *param)
1888 {
1889     int mapping;
1890     int type;
1891 
1892     DBG(("*keyboard_set_keymap_index(%d)\n", val));
1893 
1894     if ((val < 0) || (val > KBD_INDEX_LAST)) {
1895         return -1;
1896     }
1897 
1898     mapping = machine_keyboard_mapping;
1899     type = machine_keyboard_type;
1900 
1901     DBG((">keyboard_set_keymap_index(idx:%d mapping:%d type:%d)\n", val, mapping, type));
1902 
1903     if (val < 2) {
1904         if (switch_keymap_file(KBD_SWITCH_INDEX, &val, &mapping, &type) < 0) {
1905             DBG(("<keyboard_set_keymap_index switch_keymap_file ERROR\n"));
1906             log_error(keyboard_log, "Default keymap not found, this should be fixed. Going on anyway...");
1907             /* return -1; */
1908             return 0; /* HACK: allow to start up when default keymap is missing */
1909         }
1910         machine_keyboard_mapping = mapping;
1911         machine_keyboard_type = type;
1912     }
1913 
1914     if (load_keymap_file(val) < 0) {
1915         DBG(("<keyboard_set_keymap_index load_keymap_file ERROR\n"));
1916         return -1;
1917     }
1918 
1919     DBG(("<keyboard_set_keymap_index OK (idx:%d mapping:%d type:%d)\n", val, mapping, type));
1920     machine_keymap_index = val;
1921     return 0;
1922 }
1923 
1924 /* handle change of "KeyboardType" */
keyboard_set_keyboard_type(int val,void * param)1925 static int keyboard_set_keyboard_type(int val, void *param)
1926 {
1927     int idx, mapping;
1928 
1929     mapping = machine_keyboard_mapping;
1930     idx = machine_keymap_index;
1931 
1932     DBG((">keyboard_set_keyboard_type(idx:%d mapping:%d type:%d)\n", idx, mapping, val));
1933     if (idx < 2) {
1934         if (switch_keymap_file(KBD_SWITCH_TYPE, &idx, &mapping, &val) < 0) {
1935             log_error(keyboard_log, "Default keymap not found, this should be fixed. Going on anyway...");
1936             /* return -1; */
1937             return 0; /* HACK: allow to start up when default keymap is missing */
1938         }
1939         machine_keymap_index = idx;
1940         machine_keyboard_mapping = mapping;
1941     }
1942 
1943     if (load_keymap_file(idx) < 0) {
1944         DBG(("<keyboard_set_keyboard_type load_keymap_file ERROR\n"));
1945         return -1;
1946     }
1947 
1948     machine_keyboard_type = val;
1949     DBG(("<keyboard_set_keyboard_type(%d)\n", val));
1950     return 0;
1951 }
1952 
1953 /* handle change if "KeyboardMapping" */
keyboard_set_keyboard_mapping(int val,void * param)1954 static int keyboard_set_keyboard_mapping(int val, void *param)
1955 {
1956     int type;
1957     int idx;
1958 
1959 
1960     type = machine_keyboard_type;
1961     idx = machine_keymap_index;
1962     DBG((">keyboard_set_keyboard_mapping(%d,%d,%d)\n", idx, type, val));
1963 
1964     if (idx < 2) {
1965         if (switch_keymap_file(KBD_SWITCH_MAPPING, &idx, &val, &type) < 0) {
1966             log_error(keyboard_log, "Default keymap not found, this should be fixed. Going on anyway...");
1967             /* return -1; */
1968             return 0; /* HACK: allow to start up when default keymap is missing */
1969         }
1970         machine_keymap_index = idx;
1971         machine_keyboard_type = type;
1972     }
1973 
1974     if (load_keymap_file(idx) < 0) {
1975         DBG(("<keyboard_set_keyboard_mapping load_keymap_file ERROR\n"));
1976         return -1;
1977     }
1978 
1979     machine_keyboard_mapping = val;
1980     DBG(("<keyboard_set_keyboard_mapping(%d,%d,%d)\n", idx, type, val));
1981 
1982     return 0;
1983 }
1984 
1985 /* return number of available keyboard maps for gives "type" and "index" (sym/pos) */
keyboard_get_num_mappings(void)1986 int keyboard_get_num_mappings(void)
1987 {
1988     return KBD_MAPPING_NUM;
1989 }
1990 
1991 /* (keep in sync with constants in keyboard.h) */
1992 static mapping_info_t kbdinfo[KBD_MAPPING_NUM + 1] = {
1993     { "American (us)", KBD_MAPPING_US, "" },    /* this must be first (=0) always */
1994     { "British (uk)", KBD_MAPPING_UK, "uk" },
1995     { "Danish (da)", KBD_MAPPING_DA, "da" },
1996     { "Dutch (nl)", KBD_MAPPING_NL, "nl" },
1997     { "Finnish (fi)", KBD_MAPPING_FI, "fi" },
1998     { "German (de)", KBD_MAPPING_DE, "de" },
1999     { "Italian (it)", KBD_MAPPING_IT, "it" },
2000     { "Norwegian (no)", KBD_MAPPING_NO, "no" },
2001     { "Swedish (se)", KBD_MAPPING_SE, "se" },
2002     { "Swiss (ch)", KBD_MAPPING_CH, "ch" },
2003     { NULL, 0, 0 }
2004 };
2005 
keyboard_get_info_list(void)2006 mapping_info_t *keyboard_get_info_list(void)
2007 {
2008     return &kbdinfo[0];
2009 }
2010 
keyboard_get_mapping_name(int mapping)2011 static char *keyboard_get_mapping_name(int mapping)
2012 {
2013     return kbdinfo[mapping].mapping_name;
2014 }
2015 
keyboard_get_keymap_name(int idx,int mapping,int type)2016 static char *keyboard_get_keymap_name(int idx, int mapping, int type)
2017 {
2018     char *sympos[2] = { "sym", "pos"};
2019     char *mapname;
2020     char *name = NULL, *tstr = NULL;
2021 
2022     DBG((">keyboard_get_keymap_name idx %d mapping %d type %d\n", idx, mapping, type));
2023     if (type >= 0) {
2024         tstr = machine_get_keyboard_type_name(type);
2025     }
2026     mapname = keyboard_get_mapping_name(mapping);
2027 
2028     /* <port>_<type>_<idx>_<mapping>.vkm */
2029     if ((mapping == 0) && (tstr == NULL)) {
2030         name = util_concat(KBD_PORT_PREFIX, "_", sympos[idx], ".vkm", NULL);
2031     } else if ((mapping != 0) && (tstr == NULL)) {
2032         name = util_concat(KBD_PORT_PREFIX, "_", sympos[idx], "_", mapname, ".vkm", NULL);
2033     } else if ((mapping == 0) && (tstr != NULL)) {
2034         name = util_concat(KBD_PORT_PREFIX, "_", tstr, "_", sympos[idx], ".vkm", NULL);
2035     } else if ((mapping != 0) && (tstr != NULL)) {
2036         name = util_concat(KBD_PORT_PREFIX, "_", tstr, "_", sympos[idx], "_", mapname, ".vkm", NULL);
2037     }
2038 
2039     DBG(("keyboard_get_keymap_name: (port:%s type:%s idx:%d mapping:%d) '%s' = '%s'\n",
2040                 KBD_PORT_PREFIX, tstr ? tstr : "-", idx, mapping,
2041                 idx ? "KeymapPosFile" : "KeymapSymFile", name));
2042 
2043     return name;
2044 }
2045 
2046 /** \brief  Check if a keymap exists for given layout / mapping / emulated keyboard
2047  *
2048  * \param[in]   sympos      Symbolic or Positional mapping , KBD_INDEX_SYM or KBD_INDEX_POS
2049  * \param[in]   hosttype    Type of Host Layout, KBD_MAPPING_... (mapping_info_t .mapping)
2050  * \param[in]   kbdtype     Emulated Keyboard type, KBD_TYPE_... (kbdtype_info_t .type) or -1 if no different types exist
2051  *
2052  * \return  0: ok !=0: error
2053  */
keyboard_is_keymap_valid(int sympos,int hosttype,int kbdtype)2054 int keyboard_is_keymap_valid(int sympos, int hosttype, int kbdtype)
2055 {
2056     char *name = NULL;
2057     char *complete_path;
2058     int res;
2059 
2060     name = keyboard_get_keymap_name(sympos, hosttype, kbdtype);
2061     res = sysfile_locate(name, &complete_path);
2062 
2063     lib_free(name);
2064     lib_free(complete_path);
2065     return res;
2066 }
2067 
2068 /** \brief  Check if a keymap exists for given host layout
2069  *
2070  * \param[in]   hosttype    Type of Host Layout, KBD_MAPPING_... (mapping_info_t .mapping)
2071  *
2072  * \return  0: ok !=0: error
2073  */
keyboard_is_hosttype_valid(int hosttype)2074 int keyboard_is_hosttype_valid(int hosttype)
2075 {
2076     int numtypes = machine_get_num_keyboard_types();
2077     kbdtype_info_t *typelist = machine_get_keyboard_info_list();
2078     int i, type;
2079 
2080     for (i = 0; i < numtypes; i++) {
2081         if (typelist) {
2082             type = typelist[i].type;
2083         } else {
2084             type = 0;
2085         }
2086         if ((keyboard_is_keymap_valid(KBD_INDEX_SYM, hosttype, type) == 0) ||
2087             (keyboard_is_keymap_valid(KBD_INDEX_POS, hosttype, type) == 0)) {
2088             return 0;
2089         }
2090     }
2091     return -1;
2092 }
2093 
try_set_keymap_file(int atidx,int idx,int mapping,int type)2094 static int try_set_keymap_file(int atidx, int idx, int mapping, int type)
2095 {
2096     char *name = NULL;
2097     char *complete_path;
2098 
2099     name = keyboard_get_keymap_name(idx, mapping, type);
2100 
2101     util_string_set(&machine_keymap_file_list[atidx], name);
2102     DBG(("try_set_keymap_file calls sysfile_locate(%s)\n", name));
2103     if (sysfile_locate(name, &complete_path) != 0) {
2104         DBG(("<try_set_keymap_file ERROR locating keymap `%s'.\n", name ? name : "(null)"));
2105         lib_free(name);
2106         lib_free(complete_path);
2107         return -1;
2108     }
2109     lib_free(name);
2110     lib_free(complete_path);
2111     DBG(("<try_set_keymap_file OK\n"));
2112     return 0;
2113 }
2114 
switch_keymap_file(int sw,int * idxp,int * mapp,int * typep)2115 static int switch_keymap_file(int sw, int *idxp, int *mapp, int *typep)
2116 {
2117     int type = *typep;
2118     int mapping = *mapp;
2119     int idx = *idxp;
2120     int atidx = *idxp;
2121 
2122     DBG((">switch_keymap_file idx %d mapping %d type %d\n", *idxp, *mapp, *typep));
2123     if(try_set_keymap_file(atidx, idx, mapping, type) >= 0) {
2124         goto ok;
2125     }
2126 
2127     /* when switching host layout or emulated keyboard type, try the "other"
2128        index first if the current one does not exist */
2129     if ((sw == KBD_SWITCH_MAPPING) || (sw == KBD_SWITCH_TYPE)) {
2130         switch (idx) {
2131             case KBD_INDEX_SYM:
2132                 if(try_set_keymap_file(atidx, KBD_INDEX_POS, mapping, type) >= 0) {
2133                     idx = KBD_INDEX_POS;
2134                     goto ok;
2135                 }
2136                 break;
2137             case KBD_INDEX_POS:
2138                 if(try_set_keymap_file(atidx, KBD_INDEX_SYM, mapping, type) >= 0) {
2139                     idx = KBD_INDEX_SYM;
2140                     goto ok;
2141                 }
2142                 break;
2143         }
2144     }
2145 
2146     /* if a positional map was not found, we cant really do any better
2147        than trying a symbolic map for the same keyboard instead */
2148     if (idx != KBD_INDEX_SYM) {
2149         idx = KBD_INDEX_SYM;
2150         if(try_set_keymap_file(atidx, idx, mapping, type) >= 0) {
2151             goto ok;
2152         }
2153     }
2154     /*  as last resort, always use <port>_sym.vkm (which MUST exist)  */
2155     /* type = -1; */ /* FIXME: use default type? */
2156     mapping = KBD_MAPPING_US;
2157     if(try_set_keymap_file(atidx, idx, mapping, -1) >= 0) {
2158         type = 0; /* FIXME */
2159         goto ok;
2160     }
2161     DBG(("<switch_keymap_file ERROR idx %d mapping %d type %d\n", idx, mapping, type));
2162     return -1;
2163 
2164 ok:
2165     DBG(("<switch_keymap_file OK idx %d mapping %d type %d\n", idx, mapping, type));
2166     *idxp = idx;
2167     *mapp = mapping;
2168     *typep = type;
2169     return 0;
2170 }
2171 
2172 /* called by keyboard_resources_init to create the default keymap(s)
2173    idx is the index to the resource for the setting ("KeymapIndex")
2174  */
keyboard_set_default_keymap_file(int idx)2175 static int keyboard_set_default_keymap_file(int idx)
2176 {
2177     int mapping = 0;
2178     int type = 0;
2179 
2180     DBG((">keyboard_set_default_keymap_file(%d)\n", idx));
2181 
2182     if ((idx != KBD_INDEX_SYM) && (idx != KBD_INDEX_POS)) {
2183         /* it's a user keymap, do not set a default */
2184         return -1;
2185     }
2186     /* host keyboard layout type */
2187     if (resources_get_int("KeyboardMapping", &mapping) < 0) {
2188         return -1;
2189     }
2190     /* emulated keyboard type */
2191     if (resources_get_int("KeyboardType", &type) < 0) {
2192         return -1;
2193     }
2194 
2195     if(switch_keymap_file(KBD_SWITCH_DEFAULT, &idx, &mapping, &type) < 0) {
2196         /* return -1; */
2197         DBG(("<keyboard_set_default_keymap_file(FAILURE: idx: %d type: %d mapping: %d)\n", idx, type, mapping));
2198         return 0; /* always return success to allow starting up without valid keymap */
2199     }
2200 
2201     machine_keymap_index = idx;
2202     machine_keyboard_type = type;
2203     machine_keyboard_mapping = mapping;
2204 
2205     DBG(("<keyboard_set_default_keymap_file(OK: idx: %d type: %d mapping: %d)\n", idx, type, mapping));
2206     return 0; /* success */
2207 }
2208 
2209 /*--------------------------------------------------------------------------*/
2210 
2211 static char *resources_string_d0 = NULL;
2212 static char *resources_string_d1 = NULL;
2213 static char *resources_string_d2 = NULL;
2214 static char *resources_string_d3 = NULL;
2215 
2216 static const resource_string_t resources_string[] = {
2217     { "KeymapSymFile", "", RES_EVENT_NO, NULL,
2218       &machine_keymap_file_list[KBD_INDEX_SYM],
2219       keyboard_set_keymap_file, (void *)KBD_INDEX_SYM },
2220     { "KeymapPosFile", "", RES_EVENT_NO, NULL,
2221       &machine_keymap_file_list[KBD_INDEX_POS],
2222       keyboard_set_keymap_file, (void *)KBD_INDEX_POS },
2223     { "KeymapUserSymFile", "", RES_EVENT_NO, NULL,
2224       &machine_keymap_file_list[KBD_INDEX_USERSYM],
2225       keyboard_set_keymap_file, (void *)KBD_INDEX_USERSYM },
2226     { "KeymapUserPosFile", "", RES_EVENT_NO, NULL,
2227       &machine_keymap_file_list[KBD_INDEX_USERPOS],
2228       keyboard_set_keymap_file, (void *)KBD_INDEX_USERPOS },
2229     RESOURCE_STRING_LIST_END
2230 };
2231 
2232 static const resource_int_t resources_int[] = {
2233     { "KeymapIndex", KBD_INDEX_SYM, RES_EVENT_NO, NULL,
2234       &machine_keymap_index, keyboard_set_keymap_index, NULL },
2235     { "KeyboardType", 0, RES_EVENT_NO, NULL,
2236       &machine_keyboard_type, keyboard_set_keyboard_type, NULL },
2237     { "KeyboardMapping", 0, RES_EVENT_NO, NULL,
2238       &machine_keyboard_mapping, keyboard_set_keyboard_mapping, NULL },
2239     { "KbdStatusbar", 0, RES_EVENT_NO, NULL,
2240       &kbd_statusbar_enabled, keyboard_set_keyboard_statusbar, NULL },
2241     RESOURCE_INT_LIST_END
2242 };
2243 
2244 /*--------------------------------------------------------------------------*/
2245 
keyboard_resources_init(void)2246 int keyboard_resources_init(void)
2247 {
2248     int nsym, npos, mapping, idx, type;
2249     const char *name;
2250 
2251     /* VSID doesn't have a keyboard */
2252     if (machine_class == VICE_MACHINE_VSID) {
2253         return 0;
2254     }
2255 
2256     if (resources_register_string(resources_string) < 0) {
2257         return -1;
2258     }
2259 
2260     if (resources_register_int(resources_int) < 0) {
2261         return -1;
2262     }
2263 
2264     npos = (machine_keymap_file_list[KBD_INDEX_POS] == NULL) || (machine_keymap_file_list[KBD_INDEX_POS][0] == 0);
2265     nsym = (machine_keymap_file_list[KBD_INDEX_SYM] == NULL) || (machine_keymap_file_list[KBD_INDEX_SYM][0] == 0);
2266 
2267     DBG((">>keyboard_resources_init(first start:%s)\n", (npos && nsym) ? "yes" : "no"));
2268 
2269     if (npos && nsym) {
2270         mapping = archdep_kbd_get_host_mapping();
2271         log_verbose("Setting up default keyboard mapping for host type %d (%s)",
2272                     mapping, keyboard_get_mapping_name(mapping));
2273         if (resources_set_int("KeymapIndex", KBD_INDEX_SYM) < 0) {
2274             /* return -1; */
2275         }
2276         /* host keyboard mapping */
2277         if (resources_set_int("KeyboardMapping", mapping) < 0) {
2278             /* return -1; */
2279         }
2280 
2281         keyboard_set_default_keymap_file(KBD_INDEX_POS);
2282         if (resources_get_string("KeymapPosFile", &name) < 0) {
2283             DBG(("<<keyboard_resources_init(error)\n"));
2284             return -1;
2285         }
2286         util_string_set(&resources_string_d1, name);
2287         util_string_set(&resources_string_d3, name);
2288 
2289         log_verbose("Default positional map is: %s", name);
2290         keyboard_set_default_keymap_file(KBD_INDEX_SYM);
2291         if (resources_get_string("KeymapSymFile", &name) < 0) {
2292             DBG(("<<keyboard_resources_init(error)\n"));
2293             return -1;
2294         }
2295         log_verbose("Default symbolic map is: %s", name);
2296 
2297         util_string_set(&resources_string_d0, name);
2298         util_string_set(&resources_string_d2, name);
2299 
2300         /* copy current values into the factory values */
2301         resources_set_default_string("KeymapSymFile", resources_string_d0);
2302         resources_set_default_string("KeymapPosFile", resources_string_d1);
2303         resources_set_default_string("KeymapUserSymFile", resources_string_d2);
2304         resources_set_default_string("KeymapUserPosFile", resources_string_d3);
2305 
2306         idx = type = mapping = 0;
2307         if (resources_get_int("KeymapIndex", &idx) < 0) {
2308             DBG(("<<keyboard_resources_init(error)\n"));
2309             return -1;
2310         }
2311         if (resources_get_int("KeyboardType", &type) < 0) {
2312             DBG(("<<keyboard_resources_init(error)\n"));
2313             return -1;
2314         }
2315         if (resources_get_int("KeyboardMapping", &mapping) < 0) {
2316             DBG(("<<keyboard_resources_init(error)\n"));
2317             return -1;
2318         }
2319         resources_set_default_int("KeymapIndex", idx);
2320         resources_set_default_int("KeyboardType", type);
2321         resources_set_default_int("KeyboardMapping", mapping);
2322     }
2323     DBG(("<<keyboard_resources_init(ok)\n"));
2324     return 0;
2325 }
2326 
keyboard_resources_shutdown(void)2327 static void keyboard_resources_shutdown(void)
2328 {
2329     /* VSID doesn't have a keyboard */
2330     if (machine_class == VICE_MACHINE_VSID) {
2331         return;
2332     }
2333     lib_free(machine_keymap_file_list[KBD_INDEX_SYM]);
2334     lib_free(machine_keymap_file_list[KBD_INDEX_POS]);
2335     lib_free(machine_keymap_file_list[KBD_INDEX_USERSYM]);
2336     lib_free(machine_keymap_file_list[KBD_INDEX_USERPOS]);
2337     lib_free(resources_string_d0);
2338     lib_free(resources_string_d1);
2339     lib_free(resources_string_d2);
2340     lib_free(resources_string_d3);
2341 }
2342 
2343 /*--------------------------------------------------------------------------*/
2344 
2345 static cmdline_option_t const cmdline_options[] =
2346 {
2347     { "-keymap", SET_RESOURCE, CMDLINE_ATTRIB_NEED_ARGS,
2348       NULL, NULL, "KeymapIndex", NULL,
2349       "<number>", "Specify index of keymap file (0=symbolic, 1=positional, 2=symbolic (user), 3=positional (user))" },
2350 /* FIXME: build description dynamically */
2351     { "-keyboardmapping", SET_RESOURCE, CMDLINE_ATTRIB_NEED_ARGS,
2352       NULL, NULL, "KeyboardMapping", NULL,
2353       "<number>", "Specify host keyboard layout" },
2354 /* FIXME: build description dynamically */
2355     { "-keyboardtype", SET_RESOURCE, CMDLINE_ATTRIB_NEED_ARGS,
2356       NULL, NULL, "KeyboardType", NULL,
2357       "<number>", "Specify emulated keyboard type" },
2358     { "-symkeymap", SET_RESOURCE, CMDLINE_ATTRIB_NEED_ARGS,
2359       NULL, NULL, "KeymapUserSymFile", NULL,
2360       "<Name>", "Specify name of symbolic keymap file" },
2361     { "-poskeymap", SET_RESOURCE, CMDLINE_ATTRIB_NEED_ARGS,
2362       NULL, NULL, "KeymapUserPosFile", NULL,
2363       "<Name>", "Specify name of positional keymap file" },
2364 
2365     /* enable keyboard debugging display in the statusbar */
2366     { "-kbdstatusbar", SET_RESOURCE, CMDLINE_ATTRIB_NONE,
2367         NULL, NULL, "KbdStatusbar", (resource_value_t)1,
2368         NULL, "Enable keyboard-status bar" },
2369 
2370     /* disable keyboard debugging display in the statusbar */
2371     { "+kbdstatusbar", SET_RESOURCE, CMDLINE_ATTRIB_NONE,
2372         NULL, NULL, "KbdStatusbar", (resource_value_t)0,
2373         NULL, "Enable keyboard-status bar" },
2374 
2375     CMDLINE_LIST_END
2376 };
2377 
keyboard_cmdline_options_init(void)2378 int keyboard_cmdline_options_init(void)
2379 {
2380     if (machine_class != VICE_MACHINE_VSID) {
2381         return cmdline_register_options(cmdline_options);
2382     }
2383     return 0;
2384 }
2385 
2386 /*--------------------------------------------------------------------------*/
2387 
keyboard_init(void)2388 void keyboard_init(void)
2389 {
2390     keyboard_log = log_open("Keyboard");
2391 
2392     keyboard_alarm = alarm_new(maincpu_alarm_context, "Keyboard",
2393                             keyboard_latch_handler, NULL);
2394     restore_alarm = alarm_new(maincpu_alarm_context, "Restore",
2395                             restore_alarm_triggered, NULL);
2396 
2397     kbd_arch_init();
2398 
2399     if (machine_class != VICE_MACHINE_VSID) {
2400         load_keymap_ok = 1;
2401         keyboard_set_keymap_index(machine_keymap_index, NULL);
2402     }
2403 }
2404 
keyboard_shutdown(void)2405 void keyboard_shutdown(void)
2406 {
2407     keyboard_keyconvmap_free();
2408     keyboard_resources_shutdown();      /* FIXME: perhaps call from elsewhere? */
2409 }
2410 
2411 /*--------------------------------------------------------------------------*/
2412 
2413 #define SNAP_MAJOR 1
2414 #define SNAP_MINOR 0
2415 #define SNAP_NAME  "KEYBOARD"
2416 
keyboard_snapshot_write_module(snapshot_t * s)2417 int keyboard_snapshot_write_module(snapshot_t *s)
2418 {
2419     snapshot_module_t *m;
2420 
2421     m = snapshot_module_create(s, SNAP_NAME, SNAP_MAJOR, SNAP_MINOR);
2422 
2423     if (m == NULL) {
2424         return -1;
2425     }
2426 
2427     if (0
2428         || SMW_DWA(m, (uint32_t *)keyarr, KBD_ROWS) < 0
2429         || SMW_DWA(m, (uint32_t *)rev_keyarr, KBD_COLS) < 0) {
2430         snapshot_module_close(m);
2431         return -1;
2432     }
2433 
2434     return snapshot_module_close(m);
2435 }
2436 
keyboard_snapshot_read_module(snapshot_t * s)2437 int keyboard_snapshot_read_module(snapshot_t *s)
2438 {
2439     uint8_t major_version, minor_version;
2440     snapshot_module_t *m;
2441 
2442     m = snapshot_module_open(s, SNAP_NAME, &major_version, &minor_version);
2443 
2444     if (m == NULL) {
2445         return 0;
2446     }
2447 
2448     /* Do not accept versions higher than current */
2449     if (snapshot_version_is_bigger(major_version, minor_version, SNAP_MAJOR, SNAP_MINOR)) {
2450         snapshot_set_error(SNAPSHOT_MODULE_HIGHER_VERSION);
2451         snapshot_module_close(m);
2452         return -1;
2453     }
2454 
2455     if (0
2456         || SMR_DWA(m, (uint32_t *)keyarr, KBD_ROWS) < 0
2457         || SMR_DWA(m, (uint32_t *)rev_keyarr, KBD_COLS) < 0) {
2458         snapshot_module_close(m);
2459         return -1;
2460     }
2461 
2462     return snapshot_module_close(m);
2463 }
2464