1 /*
2  * vkbd.c - SDL virtual keyboard.
3  *
4  * Written by
5  *  Hannu Nuotio <hannu.nuotio@tut.fi>
6  *
7  * Based on code by
8  *  Mike Dawson <mike@gp2x.org>
9  *
10  * This file is part of VICE, the Versatile Commodore Emulator.
11  * See README for copyright notice.
12  *
13  *  This program is free software; you can redistribute it and/or modify
14  *  it under the terms of the GNU General Public License as published by
15  *  the Free Software Foundation; either version 2 of the License, or
16  *  (at your option) any later version.
17  *
18  *  This program is distributed in the hope that it will be useful,
19  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
20  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
21  *  GNU General Public License for more details.
22  *
23  *  You should have received a copy of the GNU General Public License
24  *  along with this program; if not, write to the Free Software
25  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
26  *  02111-1307  USA.
27  *
28  */
29 
30 #include "vice.h"
31 
32 #include <stdio.h>
33 
34 #include "joy.h"
35 #include "kbd.h"
36 #include "keyboard.h"
37 #include "menu_common.h"
38 #include "types.h"
39 #include "ui.h"
40 #include "uimenu.h"
41 #include "uipoll.h"
42 #include "videoarch.h"
43 #include "vkbd.h"
44 
45 int sdl_vkbd_state = 0;
46 
47 /* ------------------------------------------------------------------ */
48 /* static functions/variables */
49 
50 static int vkbd_pos_x = 0;
51 static int vkbd_pos_y = 0;
52 static int vkbd_pos_max_x = 0;
53 static int vkbd_pos_max_y = 0;
54 
55 static vkbd_t *vkbd = NULL;
56 static int vkbd_w = 0;
57 static int vkbd_h = 0;
58 
59 static int vkbd_x = 0;
60 static int vkbd_y = 0;
61 
62 static int vkbd_move = 0;
63 
64 static int vkbd_shiftflags;
65 
UI_MENU_CALLBACK(custom_shift_callback)66 static UI_MENU_CALLBACK(custom_shift_callback)
67 {
68     int flag = (1 << (vice_ptr_to_int(param)));
69 
70     if (activated) {
71         vkbd_shiftflags ^= flag;
72     } else {
73         if (vkbd_shiftflags & flag) {
74             return sdl_menu_text_tick;
75         }
76     }
77     return NULL;
78 }
79 
80 static const ui_menu_entry_t define_shift_options_menu[] = {
81     { "Virtual shift",
82       MENU_ENTRY_OTHER,
83       custom_shift_callback,
84       (ui_callback_data_t)0 },
85     { "Left shift",
86       MENU_ENTRY_OTHER,
87       custom_shift_callback,
88       (ui_callback_data_t)1 },
89     { "Right shift",
90       MENU_ENTRY_OTHER,
91       custom_shift_callback,
92       (ui_callback_data_t)2 },
93     { "Allow shift",
94       MENU_ENTRY_OTHER,
95       custom_shift_callback,
96       (ui_callback_data_t)3 },
97     { "Deshift shift",
98       MENU_ENTRY_OTHER,
99       custom_shift_callback,
100       (ui_callback_data_t)4 },
101     { "Allow other",
102       MENU_ENTRY_OTHER,
103       custom_shift_callback,
104       (ui_callback_data_t)5 },
105     { "Alt map",
106       MENU_ENTRY_OTHER,
107       custom_shift_callback,
108       (ui_callback_data_t)8 },
109     SDL_MENU_LIST_END
110 };
111 
112 static const ui_menu_entry_t shift_menu[] = {
113     { "Define shift options",
114       MENU_ENTRY_SUBMENU,
115       submenu_radio_callback,
116       (ui_callback_data_t)define_shift_options_menu },
117     SDL_MENU_LIST_END
118 };
119 
120 #define VKBD_COMMAND_MOVE  0xff
121 #define VKBD_COMMAND_CLOSE 0xfe
122 
sdl_vkbd_key_press(int value,int shift)123 static void sdl_vkbd_key_press(int value, int shift)
124 {
125     int mr, mc, neg;
126     uint8_t b, sb;
127 
128     b = vkbd->keytable[vkbd_x + vkbd_y * vkbd_w];
129 
130     if ((b == VKBD_COMMAND_CLOSE) && (value)) {
131         sdl_vkbd_close();
132         return;
133     }
134 
135     if (b == VKBD_COMMAND_MOVE) {
136         if (value && shift) {
137             sdl_vkbd_close();
138         } else {
139             vkbd_move = value;
140         }
141         return;
142     }
143 
144     neg = b & 0x08;
145 
146     if (shift && !neg) {
147         sb = vkbd->shift;
148         mc = (int)(sb & 0xf);
149         mr = (int)((sb >> 4) & 0xf);
150         keyboard_set_keyarr(mr, mc, value);
151     }
152 
153     mc = (int)(b & 0x7);
154     mr = (int)((b >> 4) & 0xf);
155 
156     if (neg) {
157         mr = -mr;
158     }
159 
160     keyboard_set_keyarr_any(mr, mc, value);
161 }
162 
sdl_vkbd_key_map(void)163 static void sdl_vkbd_key_map(void)
164 {
165     int mr, mc, neg, i, j;
166     uint8_t b;
167     SDL_Event e;
168     int unmap = 0;
169     char keyname[10];
170 
171     b = vkbd->keytable[vkbd_x + vkbd_y * vkbd_w];
172 
173     if (b == VKBD_COMMAND_CLOSE) {
174         return;
175     }
176     sdl_vkbd_state &= SDL_VKBD_REPAINT;
177 
178     sdl_ui_activate_pre_action();
179 
180     /* Use blank for unmapping */
181     if (b == VKBD_COMMAND_MOVE) {
182         unmap = 1;
183     } else {
184         /* get the key name for displaying */
185         for (j = vkbd_x; (j > -1) && (vkbd->keytable[j + vkbd_y * vkbd_w] == b); --j) {
186         }
187         ++j;
188 
189         for (i = 0; ((i + j) < vkbd_w) && (vkbd->keytable[i + j + vkbd_y * vkbd_w] == b); ++i) {
190             keyname[i] = vkbd->keyb[vkbd_y][i + j];
191         }
192 
193         keyname[i] = 0;
194     }
195 
196     neg = b & 0x08;
197     mc = (int)(b & 0x7);
198     mr = (int)((b >> 4) & 0xf);
199 
200     if (neg) {
201         mr = -mr;
202     }
203 
204     e = sdl_ui_poll_event("key or joystick event", unmap ? "(unmap)" : keyname, SDL_POLL_KEYBOARD | SDL_POLL_MODIFIER | SDL_POLL_JOYSTICK, 5);
205 
206     /* TODO check if key/event is suitable */
207     switch (e.type) {
208         case SDL_KEYDOWN:
209             if (!unmap) {
210                 vkbd_shiftflags = (1 << 3);
211                 sdl_ui_external_menu_activate((ui_menu_entry_t *)shift_menu);
212                 keyboard_set_map_any((signed long)SDL2x_to_SDL1x_Keys(e.key.keysym.sym), mr, mc, vkbd_shiftflags);
213             } else {
214                 keyboard_set_unmap_any((signed long)SDL2x_to_SDL1x_Keys(e.key.keysym.sym));
215             }
216             break;
217 #ifdef HAVE_SDL_NUMJOYSTICKS
218         case SDL_JOYAXISMOTION:
219         case SDL_JOYBUTTONDOWN:
220         case SDL_JOYHATMOTION:
221             if (unmap) {
222                 sdljoy_unset(e);
223             } else {
224                 sdljoy_set_keypress(e, mr, mc);
225             }
226             break;
227 #endif
228         default:
229             break;
230     }
231 
232     sdl_ui_activate_post_action();
233     sdl_vkbd_state = SDL_VKBD_ACTIVE;
234 }
235 
sdl_vkbd_move(int * var,int amount,int min,int max)236 static inline void sdl_vkbd_move(int *var, int amount, int min, int max)
237 {
238     *var += amount;
239 
240     if (*var < min) {
241         *var = max - 1;
242     } else if (*var >= max) {
243         *var = min;
244     }
245 
246     sdl_vkbd_state |= SDL_VKBD_REPAINT;
247 }
248 
249 /* ------------------------------------------------------------------ */
250 /* External interface */
251 
sdl_vkbd_set_vkbd(const vkbd_t * machine_vkbd)252 void sdl_vkbd_set_vkbd(const vkbd_t *machine_vkbd)
253 {
254     vkbd = (vkbd_t *)machine_vkbd;
255 
256     if (vkbd == NULL) {
257         return;
258     }
259 
260     for (vkbd_h = 0; vkbd->keyb[vkbd_h] != NULL; ++vkbd_h) {
261     }
262 
263     if (vkbd_h > 0) {
264         for (vkbd_w = 0; vkbd->keyb[0][vkbd_w] != 0; ++vkbd_w) {
265         }
266     }
267 }
268 
sdl_vkbd_activate(void)269 void sdl_vkbd_activate(void)
270 {
271     menu_draw_t *limits = NULL;
272 
273     if (vkbd == NULL) {
274         return;
275     }
276 
277     sdl_ui_init_draw_params();
278     limits = sdl_ui_get_menu_param();
279 
280     vkbd_pos_max_x = limits->max_text_x - vkbd_w + 1;
281     vkbd_pos_max_y = limits->max_text_y - vkbd_h + 1;
282 
283     if (vkbd_pos_x >= vkbd_pos_max_x) {
284         vkbd_pos_x = vkbd_pos_max_x - 1;
285     }
286 
287     if (vkbd_pos_y >= vkbd_pos_max_y) {
288         vkbd_pos_y = vkbd_pos_max_y - 1;
289     }
290 
291     sdl_vkbd_state = SDL_VKBD_ACTIVE | SDL_VKBD_REPAINT;
292     vkbd_move = 0;
293 }
294 
sdl_vkbd_close(void)295 void sdl_vkbd_close(void)
296 {
297     keyboard_key_clear();
298     sdl_vkbd_state = SDL_VKBD_REPAINT;
299 }
300 
sdl_vkbd_draw(void)301 void sdl_vkbd_draw(void)
302 {
303     int i;
304     sdl_ui_set_active_font(MENU_FONT_MONITOR);
305 
306     for (i = 0; i < vkbd_h; ++i) {
307         sdl_ui_print(vkbd->keyb[i], vkbd_pos_x, vkbd_pos_y + i);
308     }
309 
310     sdl_ui_invert_char(vkbd_pos_x + vkbd_x, vkbd_pos_y + vkbd_y);
311 
312     sdl_ui_set_active_font(MENU_FONT_ASCII);
313 
314 }
315 
sdl_vkbd_process(ui_menu_action_t input)316 int sdl_vkbd_process(ui_menu_action_t input)
317 {
318     int retval = 1;
319 
320     switch (input) {
321         case MENU_ACTION_UP:
322             if (vkbd_move) {
323                 sdl_vkbd_move(&vkbd_pos_y, -1, 0, vkbd_pos_max_y);
324             } else {
325                 sdl_vkbd_move(&vkbd_y, -1, 0, vkbd_h);
326             }
327             break;
328         case MENU_ACTION_DOWN:
329             if (vkbd_move) {
330                 sdl_vkbd_move(&vkbd_pos_y, 1, 0, vkbd_pos_max_y);
331             } else {
332                 sdl_vkbd_move(&vkbd_y, 1, 0, vkbd_h);
333             }
334             break;
335         case MENU_ACTION_LEFT:
336             if (vkbd_move) {
337                 sdl_vkbd_move(&vkbd_pos_x, -1, 0, vkbd_pos_max_x);
338             } else {
339                 sdl_vkbd_move(&vkbd_x, -1, 0, vkbd_w);
340             }
341             break;
342         case MENU_ACTION_RIGHT:
343             if (vkbd_move) {
344                 sdl_vkbd_move(&vkbd_pos_x, 1, 0, vkbd_pos_max_x);
345             } else {
346                 sdl_vkbd_move(&vkbd_x, 1, 0, vkbd_w);
347             }
348             break;
349         case MENU_ACTION_SELECT:
350             sdl_vkbd_key_press(1, 0);
351             break;
352         case MENU_ACTION_SELECT_RELEASE:
353             sdl_vkbd_key_press(0, 0);
354             break;
355         case MENU_ACTION_CANCEL:
356             sdl_vkbd_key_press(1, 1);
357             break;
358         case MENU_ACTION_CANCEL_RELEASE:
359             sdl_vkbd_key_press(0, 1);
360             break;
361         case MENU_ACTION_MAP:
362             sdl_vkbd_key_map();
363             retval = 0;
364             break;
365         case MENU_ACTION_EXIT:
366             sdl_vkbd_close();
367             retval = 0;
368             break;
369         default:
370             retval = 0;
371             break;
372     }
373 
374     return retval;
375 }
376 
377 /* ------------------------------------------------------------------ */
378 /* virtual keyboards */
379 
380 static const char *keyb_c64[] = {
381     "X \x5f 1234567890+-\x5ch del  F1",
382     "ctrl QWERTYUIOP@*\x5e rstr F3",
383     "r/s   ASDFGHJKL:;= rtrn F5",
384     "c= sh  ZXCVBNM,./v> sh  F7",
385     "        space             ",
386     NULL
387 };
388 
389 static const uint8_t keytable_c64[] =
390     "\xfe\xff\x71\xff\x70\x73\x10\x13\x20\x23\x30\x33\x40\x43\x50\x53\x60\x63\xff\x00\x00\x00\xff\xff\x04\x04"
391     "\x72\x72\x72\x72\xff\x76\x11\x16\x21\x26\x31\x36\x41\x46\x51\x56\x61\x66\xff\x38\x38\x38\x38\xff\x05\x05"
392     "\x77\x77\x77\xff\xff\xff\x12\x15\x22\x25\x32\x35\x42\x45\x52\x55\x62\x65\xff\x01\x01\x01\x01\xff\x06\x06"
393     "\x75\x75\xff\x17\x17\xff\xff\x14\x27\x24\x37\x34\x47\x44\x57\x54\x67\x07\x02\xff\x64\x64\xff\xff\x03\x03"
394     "\xff\xff\xff\xff\xff\xff\xff\xff\x74\x74\x74\x74\x74\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff";
395 
396 static const uint8_t keytable_vic20[] =
397     "\xfe\xff\x01\xff\x00\x07\x10\x17\x20\x27\x30\x37\x40\x47\x50\x57\x60\x67\xff\x70\x70\x70\xff\xff\x74\x74"
398     "\x02\x02\x02\x02\xff\x06\x11\x16\x21\x26\x31\x36\x41\x46\x51\x56\x61\x66\xff\x38\x38\x38\x38\xff\x75\x75"
399     "\x03\x03\x03\xff\xff\xff\x12\x15\x22\x25\x32\x35\x42\x45\x52\x55\x62\x65\xff\x71\x71\x71\x71\xff\x76\x76"
400     "\x05\x05\xff\x13\x13\xff\xff\x14\x23\x24\x33\x34\x43\x44\x53\x54\x63\x73\x72\xff\x64\x64\xff\xff\x77\x77"
401     "\xff\xff\xff\xff\xff\xff\xff\xff\x04\x04\x04\x04\x04\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff";
402 
403 vkbd_t vkbd_c64 = {
404     keyb_c64,
405     keytable_c64,
406     '\x17'
407 };
408 
409 vkbd_t vkbd_vic20 = {
410     keyb_c64,
411     keytable_vic20,
412     '\x13'
413 };
414 
415 static const char *keyb_c64dtv[] = {
416     "X \x5f 1234567890+-\x5ch del  F1",
417     "ctrl QWERTYUIOP@*\x5e rstr F3",
418     "r/s   ASDFGHJKL:;= rtrn F5",
419     "c= sh  ZXCVBNM,./v> sh  F7",
420     "        space      ABCD R ",
421     NULL
422 };
423 
424 static const uint8_t keytable_c64dtv[] =
425     "\xfe\xff\x71\xff\x70\x73\x10\x13\x20\x23\x30\x33\x40\x43\x50\x53\x60\x63\xff\x00\x00\x00\xff\xff\x04\x04"
426     "\x72\x72\x72\x72\xff\x76\x11\x16\x21\x26\x31\x36\x41\x46\x51\x56\x61\x66\xff\x38\x38\x38\x38\xff\x05\x05"
427     "\x77\x77\x77\xff\xff\xff\x12\x15\x22\x25\x32\x35\x42\x45\x52\x55\x62\x65\xff\x01\x01\x01\x01\xff\x06\x06"
428     "\x75\x75\xff\x17\x17\xff\xff\x14\x27\x24\x37\x34\x47\x44\x57\x54\x67\x07\x02\xff\x64\x64\xff\xff\x03\x03"
429     "\xff\xff\xff\xff\xff\xff\xff\xff\x74\x74\x74\x74\x74\xff\xff\xff\xff\xff\xff\x04\x00\x01\x02\xff\x03\xff";
430 
431 vkbd_t vkbd_c64dtv = {
432     keyb_c64dtv,
433     keytable_c64dtv,
434     '\x17'
435 };
436 
437 static const char *keyb_c128[] = {
438     "X etac hldn \x5ev<> f1 f3 f5 f7",
439     "  \x5f 1234567890+-\x5ch  del 789+",
440     "ctrl QWERTYUIOP@*\x5e rstr 456-",
441     "r/s   ASDFGHJKL:;= rtrn 123e",
442     "c= sh  ZXCVBNM,./v> sh  0 .e",
443     "         space              ",
444     NULL
445 };
446 
447 static const uint8_t keytable_c128[] =
448     "\xfe\xff\x90\x83\xa0\x49\xff\x80\x93\x48\xa7\xff\xa3\xa4\xa5\xa6\xff\x04\x04\xff\x05\x05\xff\x06\x06\xff\x03\x03"
449     "\xff\xff\x71\xff\x70\x73\x10\x13\x20\x23\x30\x33\x40\x43\x50\x53\x60\x63\xff\xff\x00\x00\x00\xff\x86\x81\x96\x91"
450     "\x72\x72\x72\x72\xff\x76\x11\x16\x21\x26\x31\x36\x41\x46\x51\x56\x61\x66\xff\x38\x38\x38\x38\xff\x85\x82\x95\x92"
451     "\x77\x77\x77\xff\xff\xff\x12\x15\x22\x25\x32\x35\x42\x45\x52\x55\x62\x65\xff\x01\x01\x01\x01\xff\x87\x84\x97\x94"
452     "\x75\x75\xff\x17\x17\xff\xff\x14\x27\x24\x37\x34\x47\x44\x57\x54\x67\x07\x02\xff\x64\x64\xff\xff\xa1\xff\xa2\x94"
453     "\xff\xff\xff\xff\xff\xff\xff\xff\xff\x74\x74\x74\x74\x74\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff";
454 
455 vkbd_t vkbd_c128 = {
456     keyb_c128,
457     keytable_c128,
458     '\x17'
459 };
460 
461 static const char *keyb_plus4[] = {
462     "X  F1 F2 F3 Help       ",
463     "esc 1234567890+-=h  del",
464     "ctrl QWERTYUIOP@\x5c* ctrl",
465     "rs sh ASDFGHJKL:; rtrn ",
466     "c=  sh ZXCVBNM,./ sh \x5e ",
467     "         space      \x5fv>",
468     NULL
469 };
470 
471 static const uint8_t keytable_plus4[] =
472     "\xfe\xff\xff\x04\x04\xff\x05\x05\xff\x06\x06\xff\x03\x03\x03\x03\xff\xff\xff\xff\xff\xff\xff"
473     "\x64\x64\x64\xff\x70\x73\x10\x13\x20\x23\x30\x33\x40\x43\x66\x56\x65\x71\xff\xff\x00\x00\x00"
474     "\x72\x72\x72\x72\xff\x76\x11\x16\x21\x26\x31\x36\x41\x46\x51\x07\x02\x61\xff\x72\x72\x72\x72"
475     "\x77\x77\xff\x17\x17\xff\x12\x15\x22\x25\x32\x35\x42\x45\x52\x55\x62\xff\x01\x01\x01\x01\xff"
476     "\x75\x75\xff\xff\x17\x17\xff\x14\x27\x24\x37\x34\x47\x44\x57\x54\x67\xff\x17\x17\xff\x53\xff"
477     "\xff\xff\xff\xff\xff\xff\xff\xff\xff\x74\x74\x74\x74\x74\xff\xff\xff\xff\xff\xff\x60\x50\x63";
478 
479 vkbd_t vkbd_plus4 = {
480     keyb_plus4,
481     keytable_plus4,
482     '\x17'
483 };
484 
485 static const char *keyb_cbm2[] = {
486     "X f1234567890 v\x5e<> conr/s",
487     "esc 1234567890-=\x5ci/d ?c*/",
488     "tab  QWERTYUIOP()rtn 789-",
489     "shift ASDFGHJKL;'_rt 456+",
490     " shift ZXCVBNM,./sc= 123e",
491     "    ctrl space       0.0e",
492     NULL
493 };
494 
495 static const uint8_t keytable_cbm2[] =
496     "\xfe\xff\x80\x80\x90\xa0\xb0\xc0\xd0\xe0\xf0\x00\x10\xff\x20\x30\x31\x32\xff\x40\x50\x60\x70\x70\x70"
497     "\x70\x70\x70\xff\x91\xa1\xb1\xc1\xd1\xd2\xe1\xf1\x01\x11\x12\x21\x22\x33\x33\x33\xff\x41\x51\x61\x71"
498     "\x82\x82\x82\xff\xff\x92\xa2\xb2\xc2\xc3\xd3\xe2\xf2\x02\x13\x14\x23\x24\x24\x24\xff\x42\x52\x62\x72"
499     "\x84\x84\x84\x84\x84\xff\x93\xa3\xb3\xb4\xc4\xd4\xe3\xf3\x03\x04\x15\x25\x24\x24\xff\x43\x53\x63\x73"
500     "\xff\x84\x84\x84\x84\x84\xff\x94\xa4\xa5\xb5\xc5\xd5\xe4\xf4\xf5\x05\x83\x34\x34\xff\x44\x54\x64\x74"
501     "\xff\xff\xff\xff\x85\x85\x85\x85\xff\xe5\xe5\xe5\xe5\xe5\xff\xff\xff\xff\xff\xff\xff\x45\x55\x65\x74";
502 
503 vkbd_t vkbd_cbm2 = {
504     keyb_cbm2,
505     keytable_cbm2,
506     '\x84'
507 };
508 
509 /* FIXME: support all PET keyboards (see pet-resources.h) */
510 
511 static const char *keyb_pet_uk[] = {
512     "X \x5f 1234567890:-\x5e> r/s  789",
513     "tab QWERTYUIOP\x5b\\v del   456",
514     "esc ASDFGHJKL;@\x5d  rtrn  123",
515     "rvs sh ZXCVBNM,./ sh rh 0 .",
516     "        space              ",
517     NULL
518 };
519 
520 static const uint8_t keytable_pet_uk[] =
521     "\xfe\xff\x90\xff\x10\x00\x91\x11\x01\x92\x12\x02\x93\x13\x95\x03\x15\x05\xff\x20\x20\x20\xff\xff\x14\x04\x17"
522     "\x40\x40\x40\xff\x50\x41\x51\x42\x52\x43\x53\x45\x55\x46\x56\x44\x54\xff\x47\x47\x47\xff\xff\xff\x57\x27\x37"
523     "\x20\x20\x20\xff\x30\x21\x31\x22\x32\x23\x33\x25\x35\x26\x36\x24\xff\xff\x34\x34\x34\x34\xff\xff\x87\x77\x67"
524     "\x80\x80\x80\xff\x60\x60\xff\x70\x81\x61\x71\x62\x72\x83\x73\x63\x86\xff\x66\x66\xff\x76\x84\xff\x74\xff\x64"
525     "\xff\xff\xff\xff\xff\xff\xff\xff\x74\x74\x74\x74\x74\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff";
526 
527 vkbd_t vkbd_pet_uk = {
528     keyb_pet_uk,
529     keytable_pet_uk,
530     '\x60'
531 };
532 
533 static const char *keyb_pet_gr[] = {
534     "X   @!\"#$%'&\\()\x5f[]    hv<i",
535     "rvs QWERTYUIOP\x5e<>     789/",
536     "    ASDFGHJKL: rs rtn 456*",
537     " sh ZXCVBNM,;? sh     123+",
538     "        space         0.-=",
539     NULL
540 };
541 
542 static const uint8_t keytable_pet_gr[] =
543     "\xfe\xff\xff\xff\x81\x00\x10\x01\x11\x02\x12\x03\x13\x04\x14\x05\x91\x82\xff\xff\xff\xff\x06\x16\x07\x18"
544     "\x90\x90\x90\xff\x20\x30\x21\x31\x22\x32\x23\x33\x24\x34\x25\x93\x84\xff\xff\xff\xff\xff\x26\x36\x27\x37"
545     "\xff\xff\xff\xff\x40\x50\x41\x51\x42\x52\x43\x53\x44\x54\xff\x94\x94\xff\x65\x65\x65\xff\x46\x56\x47\xff"
546     "\xff\x80\x80\xff\x60\x70\x61\x71\x62\x72\x63\x73\x64\x74\xff\x85\x85\xff\xff\xff\xff\xff\x66\x76\x67\x77"
547     "\xff\xff\xff\xff\xff\xff\xff\xff\x92\x92\x92\x92\x92\xff\xff\xff\xff\xff\xff\xff\xff\xff\x86\x96\x87\x97";
548 
549 vkbd_t vkbd_pet_gr = {
550     keyb_pet_gr,
551     keytable_pet_gr,
552     '\x80'
553 };
554