1 /*
2 Copyright (c) 2009-2011 Tero Lindeman (kometbomb)
3
4 Permission is hereby granted, free of charge, to any person
5 obtaining a copy of this software and associated documentation
6 files (the "Software"), to deal in the Software without
7 restriction, including without limitation the rights to use,
8 copy, modify, merge, publish, distribute, sublicense, and/or sell
9 copies of the Software, and to permit persons to whom the
10 Software is furnished to do so, subject to the following
11 conditions:
12
13 The above copyright notice and this permission notice shall be
14 included in all copies or substantial portions of the Software.
15
16 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
18 OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19 NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
20 HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
21 WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
22 FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
23 OTHER DEALINGS IN THE SOFTWARE.
24 */
25
26
27 #include "key.h"
28 #include "gui/menu.h"
29 #include <unistd.h>
30 #include <dirent.h>
31 #include <sys/stat.h>
32 #include "action.h"
33 #include "mused.h"
34 #include "keytab.h"
35 #include <string.h>
36 #include "theme.h"
37
38 extern Mused mused;
39
40 #define MAX_KEYMAPS 64
41 #define MAX_KEYTRANS 500
42
43 Menu keymapmenu[MAX_KEYMAPS + 1];
44 extern const Menu prefsmenu[];
45 static KeyTran keytrans[MAX_KEYTRANS];
46
47
translate_key_event(SDL_KeyboardEvent * e)48 void translate_key_event(SDL_KeyboardEvent *e)
49 {
50 const int allowed = KMOD_SHIFT|KMOD_CTRL|KMOD_ALT;
51
52 for (int i = 0 ; i < MAX_KEYTRANS && !(keytrans[i].from_key == 0 && keytrans[i].from_mod == 0 && keytrans[i].from_scancode == 0) ; ++i)
53 {
54 if ((keytrans[i].focus == mused.focus || keytrans[i].focus == -1) &&
55 ((keytrans[i].type == KEYSYM && e->keysym.sym == keytrans[i].from_key) ||
56 (keytrans[i].type == SCANCODE && e->keysym.scancode == keytrans[i].from_scancode)) &&
57 ((e->keysym.mod & allowed) == keytrans[i].from_mod))
58 {
59 e->keysym.sym = keytrans[i].to_key;
60 e->keysym.mod = keytrans[i].to_mod;
61 break;
62 }
63 }
64 }
65
66
enum_keymaps()67 void enum_keymaps()
68 {
69 memset(keymapmenu, 0, sizeof(keymapmenu));
70
71 // TODO: remove copypastecode and write enum_dir() function that takes a handler
72
73 int maps = 0;
74
75 keymapmenu[maps].parent = prefsmenu;
76 keymapmenu[maps].text = strdup("Default");
77 keymapmenu[maps].action = load_keymap_action;
78 keymapmenu[maps].p1 = (void*)keymapmenu[maps].text;
79 ++maps;
80
81 char path[1000];
82 snprintf(path, sizeof(path) - 1, "%s/key", query_resource_directory());
83 DIR *dir = opendir(path);
84 debug("Enumerating keymaps at %s", path);
85
86 if (!dir)
87 {
88 warning("Could not enumerate keymaps at %s", path);
89 return;
90 }
91
92 struct dirent *de = NULL;
93
94 while ((de = readdir(dir)) != NULL)
95 {
96 char fullpath[1000];
97
98 snprintf(fullpath, sizeof(fullpath) - 1, "%s/key/%s", query_resource_directory(), de->d_name);
99 struct stat attribute;
100
101 if (stat(fullpath, &attribute) != -1 && !(attribute.st_mode & S_IFDIR))
102 {
103 if (maps >= MAX_KEYMAPS)
104 {
105 warning("Maximum keymaps exceeded");
106 break;
107 }
108
109 keymapmenu[maps].parent = prefsmenu;
110 keymapmenu[maps].text = strdup(de->d_name);
111 keymapmenu[maps].action = load_keymap_action;
112 keymapmenu[maps].p1 = (void*)keymapmenu[maps].text;
113 ++maps;
114 }
115 }
116
117 debug("Got %d keymaps", maps);
118
119 closedir(dir);
120 }
121
122
update_keymap_menu()123 void update_keymap_menu()
124 {
125 for (int i = 0 ; keymapmenu[i].text ; ++i)
126 {
127 if (strcmp(mused.keymapname, (char*)keymapmenu[i].p1) == 0)
128 {
129 keymapmenu[i].flags |= MENU_BULLET;
130 }
131 else
132 keymapmenu[i].flags &= ~MENU_BULLET;
133 }
134 }
135
136
parse_key(const char * keys,int * key,int * mod,int * scancode)137 int parse_key(const char *keys, int *key, int *mod, int *scancode)
138 {
139 *mod = 0;
140 *key = 0;
141
142 if (scancode)
143 *scancode = 0;
144
145 char *temp = strdup(keys);
146 int done = 0;
147 char *tok = strtok(temp, " \t");
148
149 do
150 {
151 if (!tok) break;
152 int found = 0;
153
154 for (int i = 0 ; keydefs[i].name ; ++i)
155 {
156 if (strcasecmp(tok, keydefs[i].name) == 0)
157 {
158 if (*key != 0)
159 {
160 warning("More than one key (%s, was %d) specified", tok, *key);
161 done = 1;
162 }
163
164 *key = keydefs[i].key;
165 found = 1;
166 break;
167 }
168 }
169
170 for (int i = 0 ; moddefs[i].name ; ++i)
171 {
172 if (strcasecmp(tok, moddefs[i].name) == 0)
173 {
174 *mod |= moddefs[i].key;
175 found = 1;
176 break;
177 }
178 }
179
180 if (scancode)
181 {
182 int _scancode = 0;
183
184 if (sscanf(tok, "S_%x", &_scancode) == 1)
185 {
186 debug("Found scancode %x", _scancode);
187 *scancode = _scancode;
188 found = 1;
189 }
190 }
191
192 if (!found && strlen(tok) > 0)
193 {
194 warning("Unknown token %s", tok);
195 break;
196 }
197
198 tok = strtok(NULL, " \t");
199 }
200 while (!done);
201
202 free(temp);
203
204 if (*key == 0)
205 {
206 warning("No keys specified");
207 *mod = 0;
208 }
209
210 return (*key != 0 || (scancode == NULL || *scancode != 0));
211 }
212
213
parse_keys(const char * from,const char * to,KeyTran * tran)214 int parse_keys(const char *from, const char *to, KeyTran *tran)
215 {
216 if (!parse_key(from, &tran->from_key, &tran->from_mod, &tran->from_scancode)) return 0;
217
218 if (!parse_key(to, &tran->to_key, &tran->to_mod, NULL)) return 0;
219
220 if (tran->from_scancode)
221 tran->type = SCANCODE;
222 else
223 tran->type = KEYSYM;
224
225 return 1;
226 }
227
228
load_keymap(const char * name)229 void load_keymap(const char *name)
230 {
231 memset(keytrans, 0, sizeof(keytrans));
232
233 char tmpname[100] = {0};
234 strncpy(tmpname, name, sizeof(tmpname) - 1);
235
236 if (strcmp(name, "Default") == 0)
237 {
238 strncpy(mused.keymapname, tmpname, sizeof(mused.keymapname) - 1);
239 update_keymap_menu();
240 return;
241 }
242
243 char fullpath[3000] = {0};
244 snprintf(fullpath, sizeof(fullpath) - 1, "%s/key/%s", query_resource_directory(), tmpname);
245
246 strncpy(mused.keymapname, tmpname, sizeof(mused.keymapname) - 1);
247 update_keymap_menu();
248
249 debug("Loading keymap '%s'", fullpath);
250
251 FILE *f = fopen(fullpath, "rt");
252 int trans = 0;
253
254 if (f)
255 {
256 int lnr = 1;
257 int focus = -1;
258
259 do
260 {
261 char line[100], from[100], to[100];
262 if (trans >= MAX_KEYTRANS)
263 {
264 warning("Max keytrans exceeded\n");
265 break;
266 }
267
268 if (!fgets(line, sizeof(line) - 1, f)) break;
269
270 if (line[0] == '#')
271 continue;
272 else if (sscanf(line, "%*[[]%64[^]]%*[]]", from) == 1)
273 {
274 if (strcasecmp(from, "global") == 0)
275 {
276 focus = -1;
277 }
278 else if (strcasecmp(from, "pattern") == 0)
279 {
280 focus = EDITPATTERN;
281 }
282 else if (strcasecmp(from, "sequence") == 0)
283 {
284 focus = EDITSEQUENCE;
285 }
286 else if (strcasecmp(from, "instrument") == 0)
287 {
288 focus = EDITINSTRUMENT;
289 }
290 else
291 warning("Unknown GUI focus \"%s\" on line %d", from, lnr);
292 }
293 else if (sscanf(line, "%99[^=]=%99[^\r\n]", from, to) == 2 && parse_keys(from, to, &keytrans[trans]))
294 {
295 keytrans[trans].focus = focus;
296 ++trans;
297 }
298 else
299 {
300 warning("Keymap line %d is malformed", lnr);
301 }
302
303 ++lnr;
304 }
305 while (1);
306
307 fclose(f);
308 }
309 else
310 {
311 debug("Keymap loading failed");
312 }
313
314 debug("Got %d keytrans", trans);
315 }
316