Xemu [doxygen]  hyppo 0a42be3a057156924bc1b626a687bd6e27349c45 @ Sat 19 Mar 02:15:11 CET 2022
c64_kbd_mapping.c
Go to the documentation of this file.
1 /* Part of the Xemu project, please visit: https://github.com/lgblgblgb/xemu
2  Copyright (C)2016-2020 LGB (Gábor Lénárt) <lgblgblgb@gmail.com>
3 
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
8 
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
13 
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
17 
18 #include "xemu/emutools.h"
19 #include "xemu/emutools_hid.h"
20 #include "xemu/c64_kbd_mapping.h"
21 
22 /* Definitions for "C64-like" systems (ie: C64, C65, M65).
23  * I was lazy to map some keys, see in the comments :)
24  * The mapping should be revised at some point, this was only a quick setup without too much work since then ...
25  * ... but anyway it's only a default map anyway, since HID can load custom keymaps now!
26 */
27 
28 // Comments on this table: for uncommented lines, it's a kinda trivial mapping, like '3' on PC is for sure, '3' on C64 ...
29 // Since, it's positional mapping, there is no need to talk about key '3' shifted, it simply means the result of shifted '3' on C64, that's all.
30 // For 'PC key', we assume the scancode, thus about the US PC keyboard layout, in general! [but this can be vary if OS remaps scancodes, who knows how SDL handles this ...]
31 // NOTE: The term "C65", "C65 keyboard" means C65 or M65 emulators. You can ask wow, then what left in Xemu not C65 kbd? Well, there is C64/GEOS emulataion "leftover", which is only C64 :)
32 // "SDL_SCANCODE_UNKNOWN" does not map a key, but user can still give a custom keymap config file to map those.
33 const struct KeyMappingDefault c64_key_map[] = {
34  // SDL SCANCODE POS. EMU-KEY-NAME
35  // ---------------------------- ---- ------------
36  { SDL_SCANCODE_BACKSPACE, 0x00, "DEL" }, // PC backspace -> C64 "INST/DEL"
37  { SDL_SCANCODE_RETURN, 0x01, "RETURN" }, // PC enter -> C64 return
38  // PC's cursor right is mapped as C64's cursor right. For PC's cursor LEFT, it's mapped as C64's cursor right AND shift pressed.
39  { SDL_SCANCODE_RIGHT, 0x02, "RIGHT" }, { SDL_SCANCODE_LEFT, 0x02 | 8, "LEFT*" }, // Cursor Left / Right (Horizontal) [real key on C65 with the "auto-shift" trick]
40  // Function keys. For some convience F1,F3,F5,F7 from PC is mapped to the same C64 key, and PC's F2,F4,F6,F8 is mapped as F1,F3,F5,F7 but with shift pressed as well
41  { SDL_SCANCODE_F7, 0x03, "F7" }, { SDL_SCANCODE_F8, 0x03 | 8, "F8*" }, // Real C65 does not have "F8" (but DOES have cursor up...), these are just for fun :)
42  { SDL_SCANCODE_F1, 0x04, "F1" }, { SDL_SCANCODE_F2, 0x04 | 8, "F2*" },
43  { SDL_SCANCODE_F3, 0x05, "F3" }, { SDL_SCANCODE_F4, 0x05 | 8, "F4*" },
44  { SDL_SCANCODE_F5, 0x06, "F5" }, { SDL_SCANCODE_F6, 0x06 | 8, "F6*" },
45  // PC's cursor down is mapped as C64's cursor down. For PC's cursor UP, it's mapped as C64's cursor down AND shift pressed.
46  { SDL_SCANCODE_DOWN, 0x07, "DOWN" }, { SDL_SCANCODE_UP, 0x07 | 8, "UP*" }, // Cursor Down / Up (Vertical) [real key on C65 with the "auto-shift" trick]
47  { SDL_SCANCODE_3, 0x10, "3" },
48  { SDL_SCANCODE_W, 0x11, "W" },
49  { SDL_SCANCODE_A, 0x12, "A" },
50  { SDL_SCANCODE_4, 0x13, "4" },
51  { SDL_SCANCODE_Z, 0x14, "Z" },
52  { SDL_SCANCODE_S, 0x15, "S" },
53  { SDL_SCANCODE_E, 0x16, "E" },
54  { SDL_SCANCODE_LSHIFT, 0x17, "LSHIFT" }, // PC Left shift -> C64 left shift
55  { SDL_SCANCODE_5, 0x20, "5" },
56  { SDL_SCANCODE_R, 0x21, "R" },
57  { SDL_SCANCODE_D, 0x22, "D" },
58  { SDL_SCANCODE_6, 0x23, "6" },
59  { SDL_SCANCODE_C, 0x24, "C" },
60  { SDL_SCANCODE_F, 0x25, "F" },
61  { SDL_SCANCODE_T, 0x26, "T" },
62  { SDL_SCANCODE_X, 0x27, "X" },
63  { SDL_SCANCODE_7, 0x30, "7" },
64  { SDL_SCANCODE_Y, 0x31, "Y" },
65  { SDL_SCANCODE_G, 0x32, "G" },
66  { SDL_SCANCODE_8, 0x33, "8" },
67  { SDL_SCANCODE_B, 0x34, "B" },
68  { SDL_SCANCODE_H, 0x35, "H" },
69  { SDL_SCANCODE_U, 0x36, "U" },
70  { SDL_SCANCODE_V, 0x37, "V" },
71  { SDL_SCANCODE_9, 0x40, "9" },
72  { SDL_SCANCODE_I, 0x41, "I" },
73  { SDL_SCANCODE_J, 0x42, "J" },
74  { SDL_SCANCODE_0, 0x43, "0" },
75  { SDL_SCANCODE_M, 0x44, "M" },
76  { SDL_SCANCODE_K, 0x45, "K" },
77  { SDL_SCANCODE_O, 0x46, "O" },
78  { SDL_SCANCODE_N, 0x47, "N" },
79  { SDL_SCANCODE_INSERT, 0x50, "PLUS" }, // PC "Insert" key -> C64 '+' (plus) key [FIXME: map something more sane as '+' ?]
80  { SDL_SCANCODE_P, 0x51, "P" },
81  { SDL_SCANCODE_L, 0x52, "L" },
82  { SDL_SCANCODE_MINUS, 0x53, "MINUS" },
83  { SDL_SCANCODE_PERIOD, 0x54, "PERIOD" },
84  { SDL_SCANCODE_APOSTROPHE, 0x55, "COLON" }, // mapped as ":"
85  { SDL_SCANCODE_LEFTBRACKET, 0x56, "AT" }, // FIXME: map something sane as @ ?
86  { SDL_SCANCODE_COMMA, 0x57, "COMMA" },
87  { SDL_SCANCODE_DELETE, 0x60, "POUND" }, // FIXME: map something sane as £ ?
88  { SDL_SCANCODE_RIGHTBRACKET, 0x61, "ASTERISK" }, // FIXME: map something sane as * ?
89  { SDL_SCANCODE_SEMICOLON, 0x62, "SEMICOLON" },
90  { SDL_SCANCODE_HOME, 0x63, "CLR" }, // PC "home" -> C64 "CLR/HOME"
91  { SDL_SCANCODE_RSHIFT, 0x64, "RSHIFT" }, // PC right shift -> C64 right shift
92  { SDL_SCANCODE_EQUALS, 0x65, "EQUALS" },
93  { SDL_SCANCODE_BACKSLASH, 0x66, "UARROW" }, // PC \ (backslash) -> C64 "up-arrow" symbol [which is the PI, when shifted ...]
94  { SDL_SCANCODE_SLASH, 0x67, "SLASH" },
95  { SDL_SCANCODE_1, 0x70, "1" },
96  { SDL_SCANCODE_GRAVE, 0x71, "LARROW" }, // FIXME: map something sane as <-- ?
97  { SDL_SCANCODE_LCTRL, 0x72, "CTRL" },
98  { SDL_SCANCODE_2, 0x73, "2" },
99  { SDL_SCANCODE_SPACE, 0x74, "SPACE" },
100  { SDL_SCANCODE_LALT, 0x75, "COMMODORE" }, // Commodore key, PC kbd sux, does not have C= key ... Mapping left ALT as the C= key
101 #ifndef C65_KEYBOARD
102  { SDL_SCANCODE_RALT, 0x75, "COMMODORE" }, // RALT is used as the real ALT on C65 kbd ... if no C65 keyboard is used, still, map RALT as Commodore key as well.
103 #endif
104  { SDL_SCANCODE_Q, 0x76, "Q" },
105  { SDL_SCANCODE_END, 0x77, "RUNSTOP" }, // C64 "RUN STOP" key, we map PC 'END' as this key
106 #ifndef C65_KEYBOARD
107  { SDL_SCANCODE_ESCAPE, 0x77, "RUNSTOP" }, // C64 "RUN STOP" can be also accessed as PC 'ESC' ... On C65 kbd, this is not done, and leaving ESC as ESC, you can still use END key as RUN/STOP there
108 #endif
109  // Not a real kbd-matrix key
110 #ifndef C65_KEYBOARD
111  { SDL_SCANCODE_TAB, RESTORE_KEY_POS, "RESTORE" }, // PC TAB -> C64 "restore", but NOT on C65 as it has a TAB key, which needs it!
112 #endif
113  { SDL_SCANCODE_PAGEDOWN, RESTORE_KEY_POS, "RESTORE" }, // PC PageDown as Restore
114 #ifdef C65_KEYBOARD
115  // Not a real kbd-matrix key
116  // currently not used (not just here as UNKNOWN but not emulated either in C65/M65 emu part), since it's not clear for me, if this key is hardware/mechanical-latching, or not (only done in software) ...
117  { SDL_SCANCODE_UNKNOWN, CAPSLOCK_KEY_POS, "CAPSLOCK" },
118 #endif
119 #ifdef C65_KEYBOARD
120  // C65 (and thus M65 too) keyboard is basically the same as C64, however there are extra keys which are handled differently than the "C64-compatible" keys.
121  // Thus, if requested with macro C65_KEYBOARD defined, we have some extra "virtual" matrix positions for those keys here.
122  { SDL_SCANCODE_UNKNOWN, SCRL_KEY_POS, "NOSCROLL" }, // NO SCROLL: FIXME: where should we map this key to?
123  { SDL_SCANCODE_TAB, TAB_KEY_POS, "TAB" }, // TAB
124  { SDL_SCANCODE_RALT, ALT_KEY_POS, "ALT" }, // ALT on C65: right alt (AltGr) on PC [left ALT on PC is used as the commodore key]
125  { SDL_SCANCODE_PAGEUP, C65_KEYBOARD_EXTRA_POS + 3, "HELP" }, // HELP: FIXME: where should we map this key to?
126  { SDL_SCANCODE_UNKNOWN, C65_KEYBOARD_EXTRA_POS + 4, "F9" }, // F9/F10: FIXME: where should we map this key to?
127  { SDL_SCANCODE_UNKNOWN, C65_KEYBOARD_EXTRA_POS + 5, "F11" }, // F11/F12: FIXME: where should we map this key to?
128  { SDL_SCANCODE_UNKNOWN, C65_KEYBOARD_EXTRA_POS + 6, "F13" }, // F13/F14: FIXME: where should we map this key to?
129  { SDL_SCANCODE_ESCAPE, C65_KEYBOARD_EXTRA_POS + 7, "ESC" }, // ESC
130 #endif
131  // **** Emulates joystick with keypad
133  // **** this must be the last line: end of mapping table ****
134  { 0, -1 }
135 };
136 
137 int joystick_emu = 1;
138 
139 
140 void c64_toggle_joy_emu ( void )
141 {
142  if (joystick_emu == 1)
143  joystick_emu = 2;
144  else if (joystick_emu == 2)
145  joystick_emu = 1;
146  if (joystick_emu)
147  DEBUGPRINT("Joystick emulation for Joy#%d" NL, joystick_emu);
148 }
149 
150 
152 {
153  return
154  0xE0 |
155  (hid_read_joystick_up ( 0, 1 ) & (is_mouse_grab() ? hid_read_mouse_button_right(0, 1) : 1)) |
156  hid_read_joystick_down ( 0, 2 ) |
157  hid_read_joystick_left ( 0, 4 ) |
158  hid_read_joystick_right ( 0, 8 ) |
160  ;
161 }
162 
163 
164 #ifdef FAKE_TYPING_SUPPORT
165 
166 #ifdef C65_FAKE_TYPING_LOAD_SEQS
167 const Uint8 fake_typing_for_go64[] = {
168  0x32,0x46,0x23,0x13,0x01,0x31,0x01, 0xFF // GO64 <RETURN> Y <RETURN> <END_MARKER>
169 };
170 const Uint8 fake_typing_for_load64[] = {
171  0x32,0x46,0x23,0x13,0x01,0x31,0x01, // GO64 <RETURN> Y <RETURN>
172 #ifdef MEGA65
173  0x51,0xFE,0x46,0xFE,0x43,0x57,0x23,0x20,0x01,0x01, // P <TOGGLE_SHIFT> O <TOGGGLE_SHIFT> 0,65 <RETURN>
174 #endif
175  0x52,0xFE,0x46,0x73,0xFE,0x61,0xFE,0x73,0xFE,0x01, // L <TOGGLE_SHIFT> O 2 <TOGGLE_SHIFT> * <TOGGLE_SHIFT> 2 <RETURN>
176 #ifdef MEGA65
177  0x51,0xFE,0x46,0xFE,0x43,0x57,0x23,0x13,0x01,0x01, // P <TOGGLE_SHIFT> O <TOGGGLE_SHIFT> 0,64 <RETURN>
178 #endif
179  0x21,0x36,0x47,0x01, // RUN <RETURN>
180  0xFF // <END_MARKER>
181 };
182 const Uint8 fake_typing_for_load65[] = {
183  //0x21,0x36,0x47,0xFE,0x73,0xFE,0x61,0xFE,0x73,0xFE,0x01, // RUN"*"
184  //0xFF
185 #ifdef MEGA65
186  0x51,0x46,0x45,0x16,0x43,0x57,0x23,0x20,0x01,0x01, // POKE 0,65 <RETURN>
187 #endif
188  0x52,0xFE,0x46,0x73,0xFE,0x61,0xFE,0x73,0xFE,0x01, // L <TOGGLE_SHIFT> O 2 <TOGGLE_SHIFT> * <TOGGLE_SHIFT> 2 <RETURN>
189 #ifdef MEGA65
190  0x51,0x46,0x45,0x16,0x43,0x57,0x23,0x13,0x01,0x01, // POKE 0,64 <RETURN>
191 #endif
192  0x21,0x36,0x47,0x01, // RUN <RETURN>
193  0xFF // <END_MARKER>
194 };
195 #endif
196 
197 static struct {
198  int attention;
199  const Uint8 *typing;
200  int virtual_shift;
201 } kbd_inject;
202 int c64_fake_typing_enabled = 0;
203 
204 
205 void c64_register_fake_typing ( const Uint8 *keys )
206 {
207  c64_fake_typing_enabled = 1;
208  kbd_inject.attention = 0;
209  kbd_inject.typing = keys;
210  kbd_inject.virtual_shift = 0;
211 }
212 
213 
214 void c64_stop_fake_typing ( void )
215 {
216  if (XEMU_UNLIKELY(c64_fake_typing_enabled)) {
217  c64_fake_typing_enabled = 0;
219  }
220 }
221 
222 
223 void c64_handle_fake_typing_internals ( Uint8 keysel )
224 {
225  // It seems, both of C64 and C65 ROM uses this for keyboard scanning.
226  // Now, we have to check if we need to "inject" keypresses (eg for auto-load) but also,
227  // that if the machine itself is in the state of watching the keyboard at this point or eg not yet.
228  // For the second task, we want to use a routine in c64_keyboard_mapping.c (in xemu common code)
229  // so it's shared with emulators based on the C64-scheme on keyboard handling, ie C65 emulator in Xemu
230  // (or later even eg C128, or C64). Probably that can be generalized even more later, ie with different
231  // matrix based scenarios as well.
232  //printf("SCAN: on B, sel=%02X effect=%02X" NL, (cia1.PRA | (~cia1.DDRA)) & 0xFF, (cia1.PRB | (~cia1.DDRB)) & 0xFF);
233  kbd_inject.attention++;
234  if (kbd_inject.attention > 25) {
235  kbd_inject.attention = 0;
237  if (kbd_inject.virtual_shift)
239  if (*kbd_inject.typing != 0xFF) {
240  if (*kbd_inject.typing == 0xFE) {
241  kbd_inject.virtual_shift = !kbd_inject.virtual_shift;
242  KBD_SET_KEY(VIRTUAL_SHIFT_POS, kbd_inject.virtual_shift);
243  } else
244  KBD_PRESS_KEY(*kbd_inject.typing);
245  kbd_inject.typing++;
246  } else {
247  c64_fake_typing_enabled = 0;
249  }
250  }
251 #if 0
252  if (kbd_inject.next_ok) {
253  kbd_inject.next_ok = 0;
254  }
255  Uint8 mask = (cia1.PRA | (~cia1.DDRA)) & 0xFF;
256  switch (mask) {
257  case 0xFF:
258  break;
259  case 0x00:
260  kbd_inject.attention++;
261  break;
262  case 0xFE: case 0xFD: case 0xFB: case 0xF7:
263  case 0xEF: case 0xDF: case 0xBF: case 0x7F:
264  kbd_inject.checked_lines &= mask;
265  kbd_inject.attention++;
266  break;
267  default:
268  printf("UNKNOWN SCAN SELECTOR: %02X" NL, mask);
269  break;
270  }
271  if (!kbd_inject.checked_lines) {
272  kbd_inject.next_ok = 1;
273  kbd_inject.checked_lines = 0xFF;
274  }
275  SDL_Event sdlevent = {};
276  sdlevent.type = SDL_KEYDOWN;
277  sdlevent.key.repeat = 0;
278  sdlevent.key.windowID = sdl_winid;
279  sdlevent.key.state = SDL_PRESSED;
280  //if (event->key.repeat == 0
281  //#ifdef CONFIG_KBD_SELECT_FOCUS
282  //&& (event->key.windowID == sdl_winid || event->key.windowID == 0)
283  //hid_key_event(event->key.keysym.scancode, event->key.state == SDL_PRESSED);
284  //sdlevent.key.keysym.sym = SDLK_1;
285  // event->key.keysym.scancode
286  sdlevent.key.keysym.scancode = SDL_SCANCODE_A;
287  //SDL_PushEvent(&sdlevent);
288  //printf("ACTIVE SCAN-LIKE STUFF" NL);
289  //do_inject = 0;
290 #endif
291 }
292 
293 #endif
RESTORE_KEY_POS
#define RESTORE_KEY_POS
Definition: c64_kbd_mapping.h:31
hid_read_joystick_down
int hid_read_joystick_down(int on, int off)
Definition: emutools_hid.c:461
emutools.h
hid_read_mouse_button_right
int hid_read_mouse_button_right(int on, int off)
Definition: emutools_hid.c:515
c64_key_map
const struct KeyMappingDefault c64_key_map[]
Definition: c64_kbd_mapping.c:33
hid_read_mouse_button_left
int hid_read_mouse_button_left(int on, int off)
Definition: emutools_hid.c:509
KBD_CLEAR_MATRIX
#define KBD_CLEAR_MATRIX()
Definition: emutools_hid.h:45
joystick_emu
int joystick_emu
Definition: c64_kbd_mapping.c:137
is_mouse_grab
SDL_bool is_mouse_grab(void)
Definition: emutools.c:145
hid_read_joystick_left
int hid_read_joystick_left(int on, int off)
Definition: emutools_hid.c:467
Uint8
uint8_t Uint8
Definition: fat32.c:51
c64_toggle_joy_emu
void c64_toggle_joy_emu(void)
Definition: c64_kbd_mapping.c:140
STD_XEMU_SPECIAL_KEYS
#define STD_XEMU_SPECIAL_KEYS
Definition: emutools_hid.h:108
DEBUGPRINT
#define DEBUGPRINT(...)
Definition: emutools_basicdefs.h:171
VIRTUAL_SHIFT_POS
#define VIRTUAL_SHIFT_POS
Definition: commodore_lcd.c:84
c64_get_joy_state
Uint8 c64_get_joy_state(void)
Definition: c64_kbd_mapping.c:151
KBD_SET_KEY
#define KBD_SET_KEY(a, state)
Definition: emutools_hid.h:48
NL
#define NL
Definition: fat32.c:37
KeyMappingDefault
Definition: emutools_hid.h:24
hid_read_joystick_button
int hid_read_joystick_button(int on, int off)
Definition: emutools_hid.c:479
hid_read_joystick_up
int hid_read_joystick_up(int on, int off)
Definition: emutools_hid.c:455
CAPSLOCK_KEY_POS
#define CAPSLOCK_KEY_POS
Definition: c64_kbd_mapping.h:32
mask
int mask
Definition: dma65.c:83
emutools_hid.h
KBD_PRESS_KEY
#define KBD_PRESS_KEY(a)
Definition: emutools_hid.h:46
XEMU_UNLIKELY
#define XEMU_UNLIKELY(__x__)
Definition: emutools_basicdefs.h:125
hid_read_joystick_right
int hid_read_joystick_right(int on, int off)
Definition: emutools_hid.c:473
c64_kbd_mapping.h
sdl_winid
Uint32 sdl_winid
Definition: screen.c:49