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