1 /////////////////////////////////////////////////////////////////////////
2 // $Id: keymap.cc 14095 2021-01-30 18:47:25Z sshwarts $
3 /////////////////////////////////////////////////////////////////////////
4 //
5 // Copyright (C) 2002-2021 The Bochs Project
6 //
7 // This library is free software; you can redistribute it and/or
8 // modify it under the terms of the GNU Lesser General Public
9 // License as published by the Free Software Foundation; either
10 // version 2 of the License, or (at your option) any later version.
11 //
12 // This library is distributed in the hope that it will be useful,
13 // but WITHOUT ANY WARRANTY; without even the implied warranty of
14 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 // Lesser General Public License for more details.
16 //
17 // You should have received a copy of the GNU Lesser General Public
18 // License along with this library; if not, write to the Free Software
19 // Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
20
21 /////////////////////////////////////////////////////////////////////////
22 //
23 // Todo
24 // . Currently supported by sdl, wxGTK and x11. Check if other guis need mapping.
25 // . Tables look-up should be optimised.
26 //
27
28 #include "param_names.h"
29 #include "bochs.h"
30 #include "gui.h"
31 #include "keymap.h"
32
33 // Table of bochs "BX_KEY_*" symbols
34 // the table must be in BX_KEY_* order
35 const char *bx_key_symbol[BX_KEY_NBKEYS] = {
36 "BX_KEY_CTRL_L", "BX_KEY_SHIFT_L", "BX_KEY_F1",
37 "BX_KEY_F2", "BX_KEY_F3", "BX_KEY_F4",
38 "BX_KEY_F5", "BX_KEY_F6", "BX_KEY_F7",
39 "BX_KEY_F8", "BX_KEY_F9", "BX_KEY_F10",
40 "BX_KEY_F11", "BX_KEY_F12", "BX_KEY_CTRL_R",
41 "BX_KEY_SHIFT_R", "BX_KEY_CAPS_LOCK", "BX_KEY_NUM_LOCK",
42 "BX_KEY_ALT_L", "BX_KEY_ALT_R", "BX_KEY_A",
43 "BX_KEY_B", "BX_KEY_C", "BX_KEY_D",
44 "BX_KEY_E", "BX_KEY_F", "BX_KEY_G",
45 "BX_KEY_H", "BX_KEY_I", "BX_KEY_J",
46 "BX_KEY_K", "BX_KEY_L", "BX_KEY_M",
47 "BX_KEY_N", "BX_KEY_O", "BX_KEY_P",
48 "BX_KEY_Q", "BX_KEY_R", "BX_KEY_S",
49 "BX_KEY_T", "BX_KEY_U", "BX_KEY_V",
50 "BX_KEY_W", "BX_KEY_X", "BX_KEY_Y",
51 "BX_KEY_Z", "BX_KEY_0", "BX_KEY_1",
52 "BX_KEY_2", "BX_KEY_3", "BX_KEY_4",
53 "BX_KEY_5", "BX_KEY_6", "BX_KEY_7",
54 "BX_KEY_8", "BX_KEY_9", "BX_KEY_ESC",
55 "BX_KEY_SPACE", "BX_KEY_SINGLE_QUOTE", "BX_KEY_COMMA",
56 "BX_KEY_PERIOD", "BX_KEY_SLASH", "BX_KEY_SEMICOLON",
57 "BX_KEY_EQUALS", "BX_KEY_LEFT_BRACKET", "BX_KEY_BACKSLASH",
58 "BX_KEY_RIGHT_BRACKET", "BX_KEY_MINUS", "BX_KEY_GRAVE",
59 "BX_KEY_BACKSPACE", "BX_KEY_ENTER", "BX_KEY_TAB",
60 "BX_KEY_LEFT_BACKSLASH", "BX_KEY_PRINT", "BX_KEY_SCRL_LOCK",
61 "BX_KEY_PAUSE", "BX_KEY_INSERT", "BX_KEY_DELETE",
62 "BX_KEY_HOME", "BX_KEY_END", "BX_KEY_PAGE_UP",
63 "BX_KEY_PAGE_DOWN", "BX_KEY_KP_ADD", "BX_KEY_KP_SUBTRACT",
64 "BX_KEY_KP_END", "BX_KEY_KP_DOWN", "BX_KEY_KP_PAGE_DOWN",
65 "BX_KEY_KP_LEFT", "BX_KEY_KP_RIGHT", "BX_KEY_KP_HOME",
66 "BX_KEY_KP_UP", "BX_KEY_KP_PAGE_UP", "BX_KEY_KP_INSERT",
67 "BX_KEY_KP_DELETE", "BX_KEY_KP_5", "BX_KEY_UP",
68 "BX_KEY_DOWN", "BX_KEY_LEFT", "BX_KEY_RIGHT",
69 "BX_KEY_KP_ENTER", "BX_KEY_KP_MULTIPLY", "BX_KEY_KP_DIVIDE",
70 "BX_KEY_WIN_L", "BX_KEY_WIN_R", "BX_KEY_MENU",
71 "BX_KEY_ALT_SYSREQ", "BX_KEY_CTRL_BREAK", "BX_KEY_INT_BACK",
72 "BX_KEY_INT_FORWARD", "BX_KEY_INT_STOP", "BX_KEY_INT_MAIL",
73 "BX_KEY_INT_SEARCH", "BX_KEY_INT_FAV", "BX_KEY_INT_HOME",
74 "BX_KEY_POWER_MYCOMP", "BX_KEY_POWER_CALC", "BX_KEY_POWER_SLEEP",
75 "BX_KEY_POWER_POWER", "BX_KEY_POWER_WAKE",
76 };
77
78 bx_keymap_c bx_keymap;
79
80 #define LOG_THIS bx_keymap.
81
bx_keymap_c(void)82 bx_keymap_c::bx_keymap_c(void)
83 {
84 put("KEYMAP");
85
86 keymapCount = 0;
87 keymapTable = (BXKeyEntry *)NULL;
88 }
89
~bx_keymap_c(void)90 bx_keymap_c::~bx_keymap_c(void)
91 {
92 if(keymapTable != NULL) {
93 free(keymapTable);
94 keymapTable = (BXKeyEntry *)NULL;
95 }
96 keymapCount = 0;
97 }
98
loadKeymap(Bit32u stringToSymbol (const char *))99 void bx_keymap_c::loadKeymap(Bit32u stringToSymbol(const char*))
100 {
101 if (SIM->get_param_bool(BXPN_KBD_USEMAPPING)->get()) {
102 loadKeymap(stringToSymbol, SIM->get_param_string(BXPN_KBD_KEYMAP)->getptr());
103 }
104 }
105
isKeymapLoaded()106 bool bx_keymap_c::isKeymapLoaded ()
107 {
108 return (keymapCount > 0);
109 }
110
111
112 ///////////////////
113 // I'll add these to the keymap object in a minute.
114 static unsigned char *lineptr = NULL;
115 static int lineCount;
116
init_parse()117 static void init_parse()
118 {
119 lineCount = 0;
120 }
121
init_parse_line(char * line_to_parse)122 static void init_parse_line(char *line_to_parse)
123 {
124 // chop off newline
125 lineptr = (unsigned char *)line_to_parse;
126 char *nl;
127 if ((nl = strchr(line_to_parse,'\n')) != NULL) {
128 *nl = 0;
129 }
130 }
131
get_next_word(char * output)132 static Bit32s get_next_word(char *output)
133 {
134 char *copyp = output;
135 // find first nonspace
136 while (*lineptr && isspace(*lineptr))
137 lineptr++;
138 if (!*lineptr)
139 return -1; // nothing but spaces until end of line
140 if (*lineptr == '#')
141 return -1; // nothing but a comment
142 // copy nonspaces into the output
143 while (*lineptr && !isspace(*lineptr))
144 *copyp++ = *lineptr++;
145 *copyp=0; // null terminate the copy
146 // there must be at least one nonspace, since that's why we stopped the
147 // first loop!
148 BX_ASSERT (copyp != output);
149 return 0;
150 }
151
get_next_keymap_line(FILE * fp,char * bxsym,char * modsym,Bit32s * ascii,char * hostsym)152 static Bit32s get_next_keymap_line(FILE *fp, char *bxsym, char *modsym, Bit32s *ascii, char *hostsym)
153 {
154 char line[256];
155 char buf[256];
156
157 buf[0] = 0;
158 while (1) {
159 lineCount++;
160 if (!fgets(line, sizeof(line)-1, fp)) return -1; // EOF
161 line[sizeof(line) - 1] = '\0';
162 init_parse_line(line);
163 if (get_next_word(bxsym) >= 0) {
164 modsym[0] = 0;
165 char *p;
166 if ((p = strchr(bxsym, '+')) != NULL) {
167 *p = 0; // truncate bxsym.
168 p++; // move one char beyond the +
169 strcpy(modsym, p); // copy the rest to modsym
170 }
171 if (get_next_word(buf) < 0) {
172 BX_PANIC(("keymap line %d: expected 3 columns", lineCount));
173 return -1;
174 }
175 if (buf[0] == '\'' && buf[2] == '\'' && buf[3] == 0) {
176 *ascii = (Bit8u) buf[1];
177 } else if (!strcmp(buf, "space")) {
178 *ascii = ' ';
179 } else if (!strcmp(buf, "return")) {
180 *ascii = '\n';
181 } else if (!strcmp(buf, "tab")) {
182 *ascii = '\t';
183 } else if (!strcmp(buf, "backslash")) {
184 *ascii = '\\';
185 } else if (!strcmp(buf, "apostrophe")) {
186 *ascii = '\'';
187 } else if (!strcmp(buf, "none")) {
188 *ascii = -1;
189 } else {
190 BX_PANIC(("keymap line %d: ascii equivalent is \"%s\" but it must be char constant like 'x', or one of space,tab,return,none", lineCount, buf));
191 }
192 if (get_next_word(hostsym) < 0) {
193 BX_PANIC (("keymap line %d: expected 3 columns", lineCount));
194 return -1;
195 }
196 return 0;
197 }
198 // no words on this line, keep reading.
199 }
200 }
201
loadKeymap(Bit32u stringToSymbol (const char *),const char * filename)202 void bx_keymap_c::loadKeymap(Bit32u stringToSymbol(const char*), const char* filename)
203 {
204 FILE *keymapFile;
205 char baseSym[256], modSym[256], hostSym[256];
206 Bit32s ascii = 0;
207 Bit32u baseKey, modKey, hostKey;
208 struct stat status;
209
210 if (stat(filename, &status)) {
211 BX_PANIC(("Can not stat keymap file '%s'.",filename));
212 }
213
214 if (!(S_ISREG(status.st_mode))) {
215 BX_PANIC(("Keymap file '%s' is not a file",filename));
216 }
217
218 if((keymapFile = fopen(filename,"r"))==NULL) {
219 BX_PANIC(("Can not open keymap file '%s'.",filename));
220 }
221
222 BX_INFO(("Loading keymap from '%s'",filename));
223 init_parse();
224
225 // Read keymap file one line at a time
226 while(1) {
227 if (get_next_keymap_line (keymapFile,
228 baseSym, modSym, &ascii, hostSym) < 0) { break; }
229
230 // convert X_KEY_* symbols to values
231 baseKey = convertStringToBXKey(baseSym);
232 modKey = convertStringToBXKey(modSym);
233 hostKey = 0;
234 if (stringToSymbol != NULL)
235 hostKey = stringToSymbol(hostSym);
236
237 BX_DEBUG(("baseKey='%s' (%d), modSym='%s' (%d), ascii=%d, guisym='%s' (%d)", baseSym, baseKey, modSym, modKey, ascii, hostSym, hostKey));
238
239 // Check if data is valid
240 if (baseKey==BX_KEYMAP_UNKNOWN) {
241 BX_PANIC (("line %d: unknown BX_KEY constant '%s'",lineCount,baseSym));
242 continue;
243 }
244
245 if (hostKey==BX_KEYMAP_UNKNOWN) {
246 BX_PANIC (("line %d: unknown host key name '%s' (wrong keymap ?)",lineCount,hostSym));
247 continue;
248 }
249
250 keymapTable=(BXKeyEntry*)realloc(keymapTable,(keymapCount+1) * sizeof(BXKeyEntry));
251
252 if (keymapTable==NULL)
253 BX_PANIC(("Can not allocate memory for keymap table."));
254
255 keymapTable[keymapCount].baseKey=baseKey;
256 keymapTable[keymapCount].modKey=modKey;
257 keymapTable[keymapCount].ascii=ascii;
258 keymapTable[keymapCount].hostKey=hostKey;
259
260 keymapCount++;
261 }
262
263 BX_INFO(("Loaded %d symbols",keymapCount));
264
265 fclose(keymapFile);
266 }
267
convertStringToBXKey(const char * string)268 Bit32u bx_keymap_c::convertStringToBXKey(const char* string)
269 {
270 // We look through the bx_key_symbol table to find the searched string
271 for (Bit16u i=0; i<BX_KEY_NBKEYS; i++) {
272 if (strcmp(string,bx_key_symbol[i])==0) {
273 return i;
274 }
275 }
276
277 // Key is not known
278 return BX_KEYMAP_UNKNOWN;
279 }
280
findHostKey(Bit32u key)281 BXKeyEntry *bx_keymap_c::findHostKey(Bit32u key)
282 {
283 // We look through the keymap table to find the searched key
284 for (Bit16u i=0; i<keymapCount; i++) {
285 if (keymapTable[i].hostKey == key) {
286 BX_DEBUG (("key 0x%02x matches hostKey for entry #%d", key, i));
287 return &keymapTable[i];
288 }
289 }
290 BX_DEBUG(("key %02x matches no entries", key));
291
292 // Return default
293 return NULL;
294 }
295
findAsciiChar(Bit8u ch)296 BXKeyEntry *bx_keymap_c::findAsciiChar(Bit8u ch)
297 {
298 BX_DEBUG (("findAsciiChar (0x%02x)", ch));
299
300 // We look through the keymap table to find the searched key
301 for (Bit16u i=0; i<keymapCount; i++) {
302 if (keymapTable[i].ascii == ch) {
303 BX_DEBUG (("key %02x matches ascii for entry #%d", ch, i));
304 return &keymapTable[i];
305 }
306 }
307 BX_DEBUG (("key 0x%02x matches no entries", ch));
308
309 // Return default
310 return NULL;
311 }
312
getBXKeyName(Bit32u key)313 const char *bx_keymap_c::getBXKeyName(Bit32u key)
314 {
315 return bx_key_symbol[key & 0x7fffffff];
316 }
317