1 /***************************************************************************
3 * ZXEmuT -- ZX Spectrum Emulator with Tcl scripting
5 * Copyright (C) 2012-2022 Ketmar Dark <ketmar@ketmar.no-ip.org>
7 * This program is free software: you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation, version 3 of the License ONLY.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program. If not, see <http://www.gnu.org/licenses/>.
19 **************************************************************************/
24 {SDLK_BACKSPACE
, "BACKSPACE"},
26 {SDLK_CLEAR
, "CLEAR"},
27 {SDLK_RETURN
, "RETURN"},
28 {SDLK_RETURN
, "ENTER"},
29 {SDLK_PAUSE
, "PAUSE"},
30 {SDLK_ESCAPE
, "ESCAPE"},
32 {SDLK_SPACE
, "SPACE"},
33 {SDLK_EXCLAIM
, "EXCLAIM"},
35 {SDLK_QUOTEDBL
, "QUOTEDBL"},
36 {SDLK_QUOTEDBL
, "\""},
39 {SDLK_DOLLAR
, "DOLLAR"},
41 {SDLK_AMPERSAND
, "AMPERSAND"},
42 {SDLK_AMPERSAND
, "&"},
43 {SDLK_QUOTE
, "QUOTE"},
45 {SDLK_LEFTPAREN
, "LEFTPAREN"},
46 {SDLK_LEFTPAREN
, "("},
47 {SDLK_RIGHTPAREN
, "RIGHTPAREN"},
48 {SDLK_RIGHTPAREN
, ")"},
49 {SDLK_ASTERISK
, "ASTERISK"},
53 {SDLK_COMMA
, "COMMA"},
55 {SDLK_MINUS
, "MINUS"},
57 {SDLK_PERIOD
, "PERIOD"},
59 {SDLK_SLASH
, "SLASH"},
71 {SDLK_COLON
, "COLON"},
73 {SDLK_SEMICOLON
, "SEMICOLON"},
74 {SDLK_SEMICOLON
, ";"},
77 {SDLK_EQUALS
, "EQUALS"},
79 {SDLK_GREATER
, "GREATER"},
81 {SDLK_QUESTION
, "QUESTION"},
85 {SDLK_LEFTBRACKET
, "LEFTBRACKET"},
86 {SDLK_LEFTBRACKET
, "["},
87 {SDLK_BACKSLASH
, "BACKSLASH"},
88 {SDLK_BACKSLASH
, "\\"},
89 {SDLK_RIGHTBRACKET
, "RIGHTBRACKET"},
90 {SDLK_RIGHTBRACKET
, "]"},
91 {SDLK_CARET
, "CARET"},
92 {SDLK_UNDERSCORE
, "UNDERSCORE"},
93 {SDLK_UNDERSCORE
, "_"},
94 {SDLK_BACKQUOTE
, "BACKQUOTE"},
95 {SDLK_BACKQUOTE
, "`"},
96 {SDLK_BACKQUOTE
, "TILDA"},
97 {SDLK_BACKQUOTE
, "~"},
124 {SDLK_DELETE
, "DELETE"},
125 {SDLK_DELETE
, "DEL"},
137 {SDLK_KP_PERIOD
, "KP_PERIOD"},
138 {SDLK_KP_DIVIDE
, "KP_DIVIDE"},
139 {SDLK_KP_MULTIPLY
, "KP_MULTIPLY"},
140 {SDLK_KP_MINUS
, "KP_MINUS"},
141 {SDLK_KP_PLUS
, "KP_PLUS"},
142 {SDLK_KP_ENTER
, "KP_ENTER"},
143 {SDLK_KP_EQUALS
, "KP_EQUALS"},
147 {SDLK_RIGHT
, "RIGHT"},
149 {SDLK_INSERT
, "INSERT"},
152 {SDLK_PAGEUP
, "PAGEUP"},
153 {SDLK_PAGEUP
, "PGUP"},
154 {SDLK_PAGEDOWN
, "PAGEDOWN"},
155 {SDLK_PAGEDOWN
, "PGDOWN"},
156 {SDLK_PAGEDOWN
, "PGDN"},
174 {SDLK_NUMLOCK
, "NUMLOCK"},
175 {SDLK_CAPSLOCK
, "CAPSLOCK"},
176 {SDLK_SCROLLOCK
, "SCROLLOCK"},
178 {SDLK_RSHIFT
, "RSHIFT"},
179 {SDLK_LSHIFT
, "LSHIFT"},
180 {SDLK_RCTRL
, "RCTRL"},
181 {SDLK_LCTRL
, "LCTRL"},
184 {SDLK_RMETA
, "RMETA"},
185 {SDLK_LMETA
, "LMETA"},
186 {SDLK_LSUPER
, "LHYPER"},
187 {SDLK_RSUPER
, "LHYPER"},
189 {SDLK_COMPOSE
, "COMPOSE"},
192 {SDLK_PRINT
, "PRINT"},
193 {SDLK_SYSREQ
, "SYSREQ"},
194 {SDLK_BREAK
, "BREAK"},
196 {SDLK_POWER
, "POWER"},
204 ////////////////////////////////////////////////////////////////////////////////
205 SDLJimBinding
*sdlJimBindings
= NULL
;
208 ////////////////////////////////////////////////////////////////////////////////
209 static void zxBindSDLK (uint16_t sdlk
, const char *zxkeyname
, const char *zxkeyname1
) {
210 int keyno
= zxFindKeyByName(zxkeyname
), keyno1
= zxFindKeyByName(zxkeyname1
);
212 zxKeyBinds
[sdlk
] = 0;
213 if (keyno
>= 0 || keyno1
>= 0) {
214 if (keyno
< 0) { keyno
= keyno1
; keyno1
= -1; }
215 if (keyno
>= 0) zxKeyBinds
[sdlk
] = (zxKeyInfo
[keyno
].port
<<8)|zxKeyInfo
[keyno
].mask
;
217 uint32_t n
= (zxKeyInfo
[keyno1
].port
<<8)|zxKeyInfo
[keyno1
].mask
;
219 zxKeyBinds
[sdlk
] |= n
<<16;
225 ////////////////////////////////////////////////////////////////////////////////
226 static uint16_t sdlFindKeyCode (const char *name
) {
227 if (name
!= NULL
&& name
[0]) {
228 for (unsigned f
= 0; sdlKeyNames
[f
].name
!= NULL
; ++f
) {
229 if (strcasecmp(name
, sdlKeyNames
[f
].name
) == 0) return sdlKeyNames
[f
].code
;
236 static const char *sdlFindKeyName (uint16_t code
) {
237 for (unsigned f
= 0; sdlKeyNames
[f
].name
!= NULL
; ++f
) {
238 if (sdlKeyNames
[f
].code
== code
) return sdlKeyNames
[f
].name
;
244 static const char *sdlBuildEmacsKeyName (SDL_KeyboardEvent
*key
) {
245 static char buf
[128];
246 if (!key
) { buf
[0] = 0; return buf
; }
249 if (key
->keysym
.mod
&KMOD_CTRL
) { if (bpos
) buf
[bpos
++] = '-'; buf
[bpos
++] = 'C'; }
250 if (key
->keysym
.mod
&KMOD_SHIFT
) { if (bpos
) buf
[bpos
++] = '-'; buf
[bpos
++] = 'S'; }
251 if (key
->keysym
.mod
&KMOD_ALT
) { if (bpos
) buf
[bpos
++] = '-'; buf
[bpos
++] = 'M'; }
252 if (bpos
) buf
[bpos
++] = '-';
254 const char *kname
= sdlFindKeyName(key
->keysym
.sym
);
255 if (kname
[0] && !kname
[1] && kname
[0] >= 'a' && kname
[0] <= 'z') {
256 buf
[bpos
++] = kname
[0]-32;
259 bpos
+= strlen(kname
);
266 static SDLJimBinding
*sdlFindBinding (SDLJimBinding
*list
, const SDLJimBinding
*bind
, SDLJimBinding
**pprev
) {
267 SDLJimBinding
*prev
= NULL
;
269 if (pprev
) *pprev
= NULL
;
270 for (SDLJimBinding
*res
= list
; res
!= NULL
; res
= res
->next
) {
271 if (res
->sdlk
== bind
->sdlk
&& res
->modvalue
== bind
->modvalue
) {
272 if (pprev
) *pprev
= prev
;
281 SDLJimBinding
*sdlFindKeyBind (SDLJimBinding
*list
, uint16_t sdlk
, uint16_t modvalue
) {
282 //fprintf(stderr, "====\n");
283 modvalue
&= KMOD_CTRL
|KMOD_SHIFT
|KMOD_ALT
|KMOD_META
;
284 for (SDLJimBinding
*res
= list
; res
!= NULL
; res
= res
->next
) {
285 //fprintf(stderr, "BIND:[0x%04x;0x%04x] == [0x%04x;0x%04x]\n", res->sdlk, res->modvalue, sdlk, modvalue);
286 if (res
->sdlk
== sdlk
) {
287 uint16_t mv
= modvalue
;
289 if ((res
->modvalue
&KMOD_CTRL
) == KMOD_CTRL
&& (mv
&KMOD_CTRL
)) mv
|= KMOD_CTRL
;
290 if ((res
->modvalue
&KMOD_SHIFT
) == KMOD_SHIFT
&& (mv
&KMOD_SHIFT
)) mv
|= KMOD_SHIFT
;
291 if ((res
->modvalue
&KMOD_ALT
) == KMOD_ALT
&& (mv
&KMOD_ALT
)) mv
|= KMOD_ALT
;
292 if ((res
->modvalue
&KMOD_META
) == KMOD_META
&& (mv
&KMOD_META
)) mv
|= KMOD_META
;
293 if (res
->modvalue
== mv
) return res
;
300 static void sdlClearBindings (Jim_Interp
*interp
, SDLJimBinding
*list
) {
301 while (list
!= NULL
) {
302 SDLJimBinding
*bind
= list
;
305 if (bind
->action
!= NULL
) Jim_DecrRefCount(interp
, bind
->action
);
311 // cmdname mods... key action
312 static SDLJimBinding
*sdlParseBinding (int argc
, Jim_Obj
*const *argv
, int hasaction
) {
314 uint16_t modvalue
= 0;
317 //memset(&bind, 0, sizeof(bind));
318 if (argc
< 3) return NULL
;
319 for (int f
= 1; f
< argc
-hasaction
; ++f
) {
320 const char *a0
= Jim_String(argv
[f
]);
321 //fprintf(stderr, "sdlParseBinding: f=%d; [%s]\n", f, a0);
322 if (strcasecmp(a0
, "ctrl") == 0) modvalue
|= KMOD_CTRL
;
323 else if (strcasecmp(a0
, "lctrl") == 0) modvalue
|= KMOD_LCTRL
;
324 else if (strcasecmp(a0
, "rctrl") == 0) modvalue
|= KMOD_RCTRL
;
325 else if (strcasecmp(a0
, "alt") == 0) modvalue
|= KMOD_ALT
;
326 else if (strcasecmp(a0
, "lalt") == 0) modvalue
|= KMOD_LALT
;
327 else if (strcasecmp(a0
, "ralt") == 0) modvalue
|= KMOD_RALT
;
328 else if (strcasecmp(a0
, "shift") == 0) modvalue
|= KMOD_SHIFT
;
329 else if (strcasecmp(a0
, "lshift") == 0) modvalue
|= KMOD_LSHIFT
;
330 else if (strcasecmp(a0
, "rshift") == 0) modvalue
|= KMOD_RSHIFT
;
331 else if (strcasecmp(a0
, "meta") == 0) modvalue
|= KMOD_META
;
334 cprintf("%s: double key name ('%s')\n", Jim_String(argv
[0]), a0
);
337 if ((sdlk
= sdlFindKeyCode(a0
)) == 0) {
338 cprintf("%s: unknown key name ('%s')\n", Jim_String(argv
[0]), a0
);
345 cprintf("%s: no key name\n", Jim_String(argv
[0]));
349 if ((bind
= malloc(sizeof(*bind
))) != NULL
) {
351 bind
->modvalue
= modvalue
;
353 bind
->action
= Jim_DuplicateObj(jim
, argv
[argc
-1]);
354 Jim_IncrRefCount(bind
->action
);
365 ////////////////////////////////////////////////////////////////////////////////
367 // zxbind sdlkey zxkey [zxkey]
370 const char *a0
, *a1
, *a2
;
372 if (jimapiDisableCompletion(interp
, argc
, argv
)) return JIM_OK
;
374 // this should be "zxbind clear"
375 if (strcasecmp("clear", Jim_String(argv
[1])) == 0) {
376 memset(zxKeyBinds
, 0, sizeof(zxKeyBinds
));
377 Jim_SetResultBool(interp
, 1);
382 if (argc
< 3 || argc
> 4) { Jim_WrongNumArgs(interp
, 1, argv
, "string"); return JIM_ERR
; }
383 a0
= Jim_String(argv
[1]);
384 a1
= Jim_String(argv
[2]);
385 a2
= (argc
> 3 ? Jim_String(argv
[3]) : NULL
);
386 if ((sdlk
= sdlFindKeyCode(a0
)) == 0) {
387 //cprintf("zxbind: unknown pc key: '%s'\n", a0);
388 jim_SetResStrf(interp
, "%s: unknown pc key: '%s'", Jim_String(argv
[0]), a0
);
392 zxBindSDLK(sdlk
, a1
, a2
);
393 Jim_SetResultBool(interp
, 1);
399 JIMAPI_FN(zxunbind
) {
403 if (jimapiDisableCompletion(interp
, argc
, argv
)) return JIM_OK
;
404 if (argc
!= 2) { Jim_WrongNumArgs(interp
, 1, argv
, "string"); return JIM_ERR
; }
405 a0
= Jim_GetString(argv
[1], &l0
);
406 if ((sdlk
= sdlFindKeyCode(a0
)) == 0) {
407 jim_SetResStrf(interp
, "%s: unknown pc key: '%s'", Jim_String(argv
[0]), a0
);
410 zxBindSDLK(sdlk
, NULL
, NULL
);
411 Jim_SetResultBool(interp
, 1);
416 ////////////////////////////////////////////////////////////////////////////////
418 // bind sdlkey string
420 SDLJimBinding
*bind
, *prev
, *old
;
422 if (jimapiDisableCompletion(interp
, argc
, argv
)) return JIM_OK
;
424 if (strcasecmp("clear", Jim_String(argv
[1])) == 0) {
425 sdlClearBindings(interp
, sdlJimBindings
);
426 sdlJimBindings
= NULL
;
427 Jim_SetResultBool(interp
, 1);
432 if (argc
< 3) { Jim_WrongNumArgs(interp
, 1, argv
, "string"); return JIM_ERR
; }
433 if ((bind
= sdlParseBinding(argc
, argv
, 1)) == NULL
) {
434 jim_SetResStrf(interp
, "%s: can't parse arguments", Jim_String(argv
[0]));
438 // replace old binding if there is any
439 if ((old
= sdlFindBinding(sdlJimBindings
, bind
, &prev
)) != NULL
) {
440 if (old
->action
!= NULL
) Jim_DecrRefCount(interp
, old
->action
);
441 old
->action
= bind
->action
;
445 bind
->next
= sdlJimBindings
;
446 sdlJimBindings
= bind
;
449 //Jim_IncrRefCount(bind->action);
450 Jim_SetResultBool(interp
, 1);
457 SDLJimBinding
*bind
, *prev
, *old
;
459 if (jimapiDisableCompletion(interp
, argc
, argv
)) return JIM_OK
;
460 if (argc
< 2) { Jim_WrongNumArgs(interp
, 1, argv
, "string"); return JIM_ERR
; }
461 if ((bind
= sdlParseBinding(argc
, argv
, 0)) == NULL
) {
462 jim_SetResStrf(interp
, "%s: can't parse arguments", Jim_String(argv
[0]));
466 // remove old binding if there is any
467 if ((old
= sdlFindBinding(sdlJimBindings
, bind
, &prev
)) != NULL
) {
469 if (prev
!= NULL
) prev
->next
= old
->next
; else sdlJimBindings
= old
->next
;
470 if (old
->action
!= NULL
) Jim_DecrRefCount(interp
, old
->action
);
472 Jim_SetResultBool(interp
, 1);
474 Jim_SetResultBool(interp
, 0);