fix missing dlfcn.h include
[rofl0r-df-libgraphics.git] / g_src / enabler_input.cpp
blobbe54d5d0cd26e87a838dfa6c6069536a2030f2d7
1 #include <SDL/SDL.h>
2 #include <map>
3 #include <vector>
4 #include <iostream>
5 #include <sstream>
6 #include <algorithm>
7 #include <stdlib.h>
8 #include <math.h>
9 using namespace std;
11 #include "enabler_input.h"
12 #include "init.h"
13 extern initst init;
14 #include "platform.h"
15 #include "files.h"
16 #include "find_files.h"
17 #include "svector.h"
18 #include "curses.h"
20 // The timeline events we actually pass back from get_input. Well, no,
21 // that's just k, but..
22 struct Event {
23 Repeat r;
24 InterfaceKey k;
25 int repeats; // Starts at 0, increments once per repeat
26 int serial;
27 int time;
28 int tick; // The sim-tick at which we last returned this event
29 bool macro; // Created as part of macro playback.
31 bool operator== (const Event &other) const {
32 if (r != other.r) return false;
33 if (k != other.k) return false;
34 if (repeats != other.repeats) return false;
35 if (serial != other.serial) return false;
36 if (time != other.time) return false;
37 if (macro != other.macro) return false;
38 return true;
41 // We sort by time first, and then serial number.
42 // The order of the other bits is unimportant.
43 bool operator< (const Event &o) const {
44 if (time != o.time) return time < o.time;
45 if (serial != o.serial) return serial < o.serial;
46 if (r != o.r) return r < o.r;
47 if (k != o.k) return k < o.k;
48 if (repeats != o.repeats) return repeats < o.repeats;
49 if (macro != o.macro) return macro < o.macro;
50 return false;
54 // Used to decide which key-binding to display. As a heuristic, we
55 // prefer whichever display string is shortest.
56 struct less_sz {
57 bool operator() (const string &a, const string &b) const {
58 if (a.size() < b.size()) return true;
59 if (a.size() > b.size()) return false;
60 return a < b;
64 // These change dynamically in the normal process of DF
65 static int last_serial = 0; // Input serial number, to differentiate distinct physical presses
66 static set<Event> timeline; // A timeline of pending key events (for next get_input)
67 static set<EventMatch> pressed_keys; // Keys we consider "pressed"
68 static int modState; // Modifier state
70 // These do not change as part of the normal dynamics of DF, only at startup/when editing.
71 static multimap<EventMatch,InterfaceKey> keymap;
72 static map<InterfaceKey,Repeat> repeatmap;
73 static map<InterfaceKey,set<string,less_sz> > keydisplay; // Used only for display, not for meaning
75 // Macro recording
76 static bool macro_recording = false;
77 static macro active_macro; // Active macro
78 static map<string,macro> macros;
79 static Time macro_end = 0; // Time at which the currently playing macro will end
81 // Prefix command state
82 static bool in_prefix_command = false;
83 static string prefix_command;
85 // Keybinding editing
86 static bool key_registering = false;
87 static list<EventMatch> stored_keys;
89 // Interface-file last loaded
90 static string interfacefile;
93 // Returns an unused serial number
94 static Time next_serial() {
95 return ++last_serial;
98 static void update_keydisplay(InterfaceKey binding, string display) {
99 // Need to filter out space/tab, for obvious reasons.
100 if (display == " ") display = "Space";
101 if (display == "\t") display = "Tab";
102 map<InterfaceKey,set<string,less_sz> >::iterator it = keydisplay.find(binding);
103 if (it == keydisplay.end()) {
104 set<string,less_sz> s; s.insert(display);
105 keydisplay[binding] = s;
106 } else {
107 keydisplay[binding].insert(display);
111 static void assertgood(ifstream &s) {
112 if (s.eof())
113 MessageBox(NULL, "EOF while parsing keyboard bindings", 0, 0);
114 else if (!s.good())
115 MessageBox(NULL, "I/O error while parsing keyboard bindings", 0, 0);
116 else
117 return;
118 abort();
121 // Decodes an UTF-8 encoded string into a /single/ UTF-8 character,
122 // discarding any overflow. Returns 0 on parse error.
123 int decode_utf8(const string &s) {
124 int unicode = 0, length, i;
125 if (s.length() == 0) return 0;
126 length = decode_utf8_predict_length(s[0]);
127 switch (length) {
128 case 1: unicode = s[0]; break;
129 case 2: unicode = s[0] & 0x1f; break;
130 case 3: unicode = s[0] & 0x0f; break;
131 case 4: unicode = s[0] & 0x07; break;
132 default: return 0;
135 // Concatenate the follow-up bytes
136 if (s.length() < length) return 0;
137 for (i = 1; i < length; i++) {
138 if ((s[i] & 0xc0) != 0x80) return 0;
139 unicode = (unicode << 6) | (s[i] & 0x3f);
141 return unicode;
144 // Returns the length of an utf-8 sequence, based on its first byte
145 int decode_utf8_predict_length(char byte) {
146 if ((byte & 0x80) == 0) return 1;
147 if ((byte & 0xe0) == 0xc0) return 2;
148 if ((byte & 0xf0) == 0xe0) return 3;
149 if ((byte & 0xf8) == 0xf0) return 4;
150 return 0; // Invalid start byte
153 // Encode an arbitrary unicode value as a string. Returns an empty
154 // string if the value is out of range.
155 string encode_utf8(int unicode) {
156 string s;
157 int i;
158 if (unicode < 0 || unicode > 0x10ffff) return ""; // Out of range for utf-8
159 else if (unicode <= 0x007f) { // 1-byte utf-8
160 s.resize(1, 0);
162 else if (unicode <= 0x07ff) { // 2-byte utf-8
163 s.resize(2, 0);
164 s[0] = 0xc0;
166 else if (unicode <= 0xffff) { // 3-byte utf-8
167 s.resize(3, 0);
168 s[0] = 0xe0;
170 else { // 4-byte utf-8
171 s.resize(4, 0);
172 s[0] = 0xf0;
175 // Build up the string, right to left
176 for (i = s.length()-1; i > 0; i--) {
177 s[i] = 0x80 | (unicode & 0x3f);
178 unicode >>= 6;
180 // Finally, what's left goes in the low bits of s[0]
181 s[0] |= unicode;
182 return s;
185 string translate_mod(Uint8 mod) {
186 string ret;
187 if (mod & 1) ret += "Shift+";
188 if (mod & 2) ret += "Ctrl+";
189 if (mod & 4) ret += "Alt+";
190 return ret;
193 static string display(const EventMatch &match) {
194 ostringstream ret;
195 ret << translate_mod(match.mod);
196 switch (match.type) {
197 case type_unicode: ret << (char)match.unicode; break;
198 case type_key: {
199 map<SDLKey,string>::iterator it = sdlNames.left.find(match.key);
200 if (it != sdlNames.left.end())
201 ret << it->second;
202 else
203 ret << "SDL+" << (int)match.key;
204 break;
206 case type_button:
207 ret << "Button " << (int)match.button;
208 break;
210 return ret.str();
213 static string translate_repeat(Repeat r) {
214 switch (r) {
215 case REPEAT_NOT: return "REPEAT_NOT";
216 case REPEAT_SLOW: return "REPEAT_SLOW";
217 case REPEAT_FAST: return "REPEAT_FAST";
218 default: return "REPEAT_BROKEN";
222 // Update the modstate, since SDL_getModState doesn't /work/ for alt
223 static void update_modstate(const SDL_Event &e) {
224 if (e.type == SDL_KEYUP) {
225 switch (e.key.keysym.sym) {
226 case SDLK_RSHIFT:
227 case SDLK_LSHIFT:
228 modState &= ~1;
229 break;
230 case SDLK_RCTRL:
231 case SDLK_LCTRL:
232 modState &= ~2;
233 break;
234 case SDLK_RALT:
235 case SDLK_LALT:
236 modState &= ~4;
237 break;
239 } else if (e.type == SDL_KEYDOWN) {
240 switch (e.key.keysym.sym) {
241 case SDLK_RSHIFT:
242 case SDLK_LSHIFT:
243 modState |= 1;
244 break;
245 case SDLK_RCTRL:
246 case SDLK_LCTRL:
247 modState |= 2;
248 break;
249 case SDLK_RALT:
250 case SDLK_LALT:
251 modState |= 4;
252 break;
257 // Converts SDL mod states to ours, collapsing left/right shift/alt/ctrl
258 Uint8 getModState() {
259 return modState;
262 // Not sure what to call this, but it ain't using regexes.
263 static bool parse_line(const string &line, const string &regex, vector<string> &parts) {
264 parts.clear();
265 parts.push_back(line);
266 int bytes;
267 for (int l = 0, r = 0; r < regex.length();) {
268 switch (regex[r]) {
269 case '*': // Read until ], : or the end of the line, but at least one character.
271 const int start = l;
272 for (; l < line.length() && (l == start || (line[l] != ']' && line[l] != ':')); l++)
274 parts.push_back(line.substr(start, l - start));
275 r++;
277 break;
278 default:
279 if (line[l] != regex[r]) return false;
280 r++; l++;
281 break;
284 // We've made it this far, clearly the string parsed
285 return true;
288 void enabler_inputst::load_keybindings(const string &file) {
289 cout << "Loading bindings from " << file << endl;
290 interfacefile = file;
291 ifstream s(file.c_str());
292 if (!s.good()) {
293 MessageBox(NULL, (file + " not found, or I/O error encountered").c_str(), 0, 0);
294 abort();
297 list<string> lines;
298 while (s.good()) {
299 string line;
300 getline(s, line);
301 lines.push_back(line);
304 static const string bind("[BIND:*:*]");
305 static const string sym("[SYM:*:*]");
306 static const string key("[KEY:*]");
307 static const string button("[BUTTON:*:*]");
309 list<string>::iterator line = lines.begin();
310 vector<string> match;
312 while (line != lines.end()) {
313 if (parse_line(*line, bind, match)) {
314 map<string,InterfaceKey>::iterator it = bindingNames.right.find(match[1]);
315 if (it != bindingNames.right.end()) {
316 InterfaceKey binding = it->second;
317 // Parse repeat data
318 if (match[2] == "REPEAT_FAST")
319 repeatmap[(InterfaceKey)binding] = REPEAT_FAST;
320 else if (match[2] == "REPEAT_SLOW")
321 repeatmap[(InterfaceKey)binding] = REPEAT_SLOW;
322 else if (match[2] == "REPEAT_NOT")
323 repeatmap[(InterfaceKey)binding] = REPEAT_NOT;
324 else {
325 repeatmap[(InterfaceKey)binding] = REPEAT_NOT;
326 cout << "Broken repeat request: " << match[2] << endl;
328 ++line;
329 // Add symbols/keys/buttons
330 while (line != lines.end()) {
331 EventMatch matcher;
332 // SDL Keys
333 if (parse_line(*line, sym, match)) {
334 map<string,SDLKey>::iterator it = sdlNames.right.find(match[2]);
335 if (it != sdlNames.right.end()) {
336 matcher.mod = atoi(string(match[1]).c_str());
337 matcher.type = type_key;
338 matcher.key = it->second;
339 keymap.insert(pair<EventMatch,InterfaceKey>(matcher, (InterfaceKey)binding));
340 update_keydisplay(binding, display(matcher));
341 } else {
342 cout << "Unknown SDLKey: " << match[2] << endl;
344 ++line;
345 } // Unicode
346 else if (parse_line(*line, key, match)) {
347 matcher.type = type_unicode;
348 matcher.unicode = decode_utf8(match[1]);
349 matcher.mod = KMOD_NONE;
350 if (matcher.unicode) {
351 keymap.insert(make_pair(matcher, (InterfaceKey)binding));
352 if (matcher.unicode < 256) {
353 // This unicode key is part of the latin-1 mapped portion of unicode, so we can
354 // actually display it. Nice.
355 char c[2] = {char(matcher.unicode), 0};
356 update_keydisplay(binding, display(matcher));
358 } else {
359 cout << "Broken unicode: " << *line << endl;
361 ++line;
362 } // Mouse buttons
363 else if (parse_line(*line, button, match)) {
364 matcher.type = type_button;
365 string str = match[2];
366 matcher.button = atoi(str.c_str());
367 if (matcher.button) {
368 matcher.mod = atoi(string(match[1]).c_str());
369 keymap.insert(pair<EventMatch,InterfaceKey>(matcher, (InterfaceKey)binding));
370 update_keydisplay(binding, display(matcher));
371 } else {
372 cout << "Broken button (should be [BUTTON:#:#]): " << *line << endl;
374 ++line;
375 } else {
376 break;
379 } else {
380 cout << "Unknown binding: " << match[1] << endl;
381 ++line;
383 } else {
384 // Retry with next line
385 ++line;
390 void enabler_inputst::save_keybindings(const string &file) {
391 cout << "Saving bindings to " << file << endl;
392 string temporary = file + ".partial";
393 ofstream s(temporary.c_str());
394 multimap<InterfaceKey,EventMatch> map;
395 InterfaceKey last_key = INTERFACEKEY_NONE;
397 if (!s.good()) {
398 string t = "Failed to open " + temporary + " for writing";
399 MessageBox(NULL, t.c_str(), 0, 0);
400 s.close();
401 return;
403 // Invert keyboard map
404 for (multimap<EventMatch,InterfaceKey>::iterator it = keymap.begin(); it != keymap.end(); ++it)
405 map.insert(pair<InterfaceKey,EventMatch>(it->second,it->first));
406 // Insert an empty line for the benefit of note/wordpad
407 s << endl;
408 // And write.
409 for (multimap<InterfaceKey,EventMatch>::iterator it = map.begin(); it != map.end(); ++it) {
410 if (!s.good()) {
411 MessageBox(NULL, "I/O error while writing keyboard mapping", 0, 0);
412 s.close();
413 return;
415 if (it->first != last_key) {
416 last_key = it->first;
417 s << "[BIND:" << bindingNames.left[it->first] << ":"
418 << translate_repeat(repeatmap[it->first]) << "]" << endl;
420 switch (it->second.type) {
421 case type_unicode:
422 s << "[KEY:" << encode_utf8(it->second.unicode) << "]" << endl;
423 break;
424 case type_key:
425 s << "[SYM:" << (int)it->second.mod << ":" << sdlNames.left[it->second.key] << "]" << endl;
426 break;
427 case type_button:
428 s << "[BUTTON:" << (int)it->second.mod << ":" << (int)it->second.button << "]" << endl;
429 break;
432 s.close();
433 replace_file(temporary, file);
436 void enabler_inputst::save_keybindings() {
437 save_keybindings(interfacefile);
440 void enabler_inputst::add_input(SDL_Event &e, Uint32 now) {
441 // Before we can use this input, there are some issues to deal with:
442 // - SDL provides unicode translations only for key-press events, not
443 // releases. We need to keep track of pressed keys, and generate
444 // unicode release events whenever any modifiers are hit, or if
445 // that raw keycode is released.
446 // - Generally speaking, when modifiers are hit/released, we discard those
447 // events and generate press/release events for all pressed non-modifiers.
448 // - It's possible for multiple events to be generated on the same tick.
449 // These are of course separate keypresses, and must be kept separate.
450 // That's what the serial is for.
452 set<EventMatch>::iterator pkit;
453 list<pair<KeyEvent, int> > synthetics;
454 update_modstate(e);
456 // Convert modifier state changes
457 if ((e.type == SDL_KEYUP || e.type == SDL_KEYDOWN) &&
458 (e.key.keysym.sym == SDLK_RSHIFT ||
459 e.key.keysym.sym == SDLK_LSHIFT ||
460 e.key.keysym.sym == SDLK_RCTRL ||
461 e.key.keysym.sym == SDLK_LCTRL ||
462 e.key.keysym.sym == SDLK_RALT ||
463 e.key.keysym.sym == SDLK_LALT )) {
464 for (pkit = pressed_keys.begin(); pkit != pressed_keys.end(); ++pkit) {
465 // Release currently pressed keys
466 KeyEvent synth;
467 synth.release = true;
468 synth.match = *pkit;
469 synthetics.push_back(make_pair(synth, next_serial()));
470 // Re-press them, with new modifiers, if they aren't unicode. We can't re-translate unicode.
471 if (synth.match.type != type_unicode) {
472 synth.release = false;
473 synth.match.mod = getModState();
474 if (!key_registering) // We don't want extras when registering keys
475 synthetics.push_back(make_pair(synth, next_serial()));
478 } else {
479 // It's not a modifier. If this is a key release, then we still need
480 // to find and release pressed unicode keys with this scancode
481 if (e.type == SDL_KEYUP) {
482 for (pkit = pressed_keys.begin(); pkit != pressed_keys.end(); ++pkit) {
483 if (pkit->type == type_unicode && pkit->scancode == e.key.keysym.scancode) {
484 KeyEvent synth;
485 synth.release = true;
486 synth.match = *pkit;
487 synthetics.push_back(make_pair(synth, next_serial()));
491 // Since it's not a modifier, we also pass on symbolic/button
492 // (always) and unicode (if defined) events
494 // However, since SDL ignores(?) ctrl and alt when translating to
495 // unicode, we want to ignore unicode events if those are set.
496 const int serial = next_serial();
498 KeyEvent real;
499 real.release = (e.type == SDL_KEYUP || e.type == SDL_MOUSEBUTTONUP) ? true : false;
500 real.match.mod = getModState();
501 if (e.type == SDL_MOUSEBUTTONUP || e.type == SDL_MOUSEBUTTONDOWN) {
502 real.match.type = type_button;
503 real.match.scancode = 0;
504 real.match.button = e.button.button;
505 synthetics.push_back(make_pair(real, serial));
507 if (e.type == SDL_KEYUP || e.type == SDL_KEYDOWN) {
508 real.match.type = type_key;
509 real.match.scancode = e.key.keysym.scancode;
510 real.match.key = e.key.keysym.sym;
511 synthetics.push_back(make_pair(real, serial));
513 if (e.type == SDL_KEYDOWN && e.key.keysym.unicode && getModState() < 2) {
514 real.match.mod = KMOD_NONE;
515 real.match.type = type_unicode;
516 real.match.scancode = e.key.keysym.scancode;
517 real.match.unicode = e.key.keysym.unicode;
518 synthetics.push_back(make_pair(real, serial));
520 if (e.type == SDL_QUIT) {
521 // This one, we insert directly into the timeline.
522 Event e = {REPEAT_NOT, (InterfaceKey)INTERFACEKEY_OPTIONS, 0, next_serial(), now, 0};
523 timeline.insert(e);
527 list<pair<KeyEvent, int> >::iterator lit;
528 for (lit = synthetics.begin(); lit != synthetics.end(); ++lit) {
529 // Add or remove the key from pressed_keys, keeping that up to date
530 if (lit->first.release) pressed_keys.erase(lit->first.match);
531 else pressed_keys.insert(lit->first.match);
532 // And pass the event on deeper.
533 add_input_refined(lit->first, now, lit->second);
537 // Input encoding:
538 // 1 and up are ncurses symbols, as returned by getch.
539 // -1 and down are unicode values.
540 // esc is true if this key was part of an escape sequence.
541 #ifdef CURSES
542 void enabler_inputst::add_input_ncurses(int key, Time now, bool esc) {
543 // TODO: Deal with shifted arrow keys, etc. See man 5 terminfo and tgetent.
545 EventMatch sdl, uni; // Each key may provoke an unicode event, an "SDL-key" event, or both
546 const int serial = next_serial();
547 sdl.type = type_key;
548 uni.type = type_unicode;
549 sdl.scancode = uni.scancode = 0; // We don't use this.. hang on, who does? ..nobody. FIXME!
550 sdl.mod = uni.mod = 0;
551 sdl.key = SDLK_UNKNOWN;
552 uni.unicode = 0;
554 if (esc) { // Escape sequence, meaning alt was held. I hope.
555 sdl.mod = uni.mod = DFMOD_ALT;
558 if (key == -10) { // Return
559 sdl.key = SDLK_RETURN;
560 uni.unicode = '\n';
561 } else if (key == -9) { // Tab
562 sdl.key = SDLK_TAB;
563 uni.unicode = '\t';
564 } else if (key == -27) { // If we see esc here, it's the actual esc key. Hopefully.
565 sdl.key = SDLK_ESCAPE;
566 } else if (key == -127) { // Backspace/del
567 sdl.key = SDLK_BACKSPACE;
568 } else if (key < 0 && key >= -26) { // Control-a through z (but not ctrl-j, or ctrl-i)
569 sdl.mod |= DFMOD_CTRL;
570 sdl.key = (SDLKey)(SDLK_a + (-key) - 1);
571 } else if (key <= -32 && key >= -126) { // ASCII character set
572 uni.unicode = -key;
573 sdl.key = (SDLKey)-key; // Most of this maps directly to SDL keys, except..
574 if (sdl.key > 64 && sdl.key < 91) { // Uppercase
575 sdl.key = (SDLKey)(sdl.key + 32); // Maps to lowercase, and
576 sdl.mod |= DFMOD_SHIFT; // Add shift.
578 } else if (key < -127) { // Unicode, no matching SDL keys
579 uni.unicode = -key;
580 } else if (key > 0) { // Symbols such as arrow-keys, etc, no matching unicode.
581 switch (key) {
582 case KEY_DOWN: sdl.key = SDLK_DOWN; break;
583 case KEY_UP: sdl.key = SDLK_UP; break;
584 case KEY_LEFT: sdl.key = SDLK_LEFT; break;
585 case KEY_RIGHT: sdl.key = SDLK_RIGHT; break;
586 case KEY_BACKSPACE: sdl.key = SDLK_BACKSPACE; break;
587 case KEY_F(1): sdl.key = SDLK_F1; break;
588 case KEY_F(2): sdl.key = SDLK_F2; break;
589 case KEY_F(3): sdl.key = SDLK_F3; break;
590 case KEY_F(4): sdl.key = SDLK_F4; break;
591 case KEY_F(5): sdl.key = SDLK_F5; break;
592 case KEY_F(6): sdl.key = SDLK_F6; break;
593 case KEY_F(7): sdl.key = SDLK_F7; break;
594 case KEY_F(8): sdl.key = SDLK_F8; break;
595 case KEY_F(9): sdl.key = SDLK_F9; break;
596 case KEY_F(10): sdl.key = SDLK_F10; break;
597 case KEY_F(11): sdl.key = SDLK_F11; break;
598 case KEY_F(12): sdl.key = SDLK_F12; break;
599 case KEY_F(13): sdl.key = SDLK_F13; break;
600 case KEY_F(14): sdl.key = SDLK_F14; break;
601 case KEY_F(15): sdl.key = SDLK_F15; break;
602 case KEY_DC: sdl.key = SDLK_DELETE; break;
603 case KEY_NPAGE: sdl.key = SDLK_PAGEDOWN; break;
604 case KEY_PPAGE: sdl.key = SDLK_PAGEUP; break;
605 case KEY_ENTER: sdl.key = SDLK_RETURN; break;
609 // We may be registering a new mapping, in which case we skip the
610 // rest of this function.
611 if (key_registering) {
612 if (uni.unicode) {
613 stored_keys.push_back(uni);
615 if (sdl.key) {
616 stored_keys.push_back(sdl);
618 Event e; e.r = REPEAT_NOT; e.repeats = 0; e.time = now; e.serial = serial; e.k = INTERFACEKEY_KEYBINDING_COMPLETE; e.tick = enabler.simticks.read();
619 timeline.insert(e);
620 key_registering = false;
621 return;
624 // Key repeat is handled by the terminal, and we don't get release
625 // events anyway.
626 KeyEvent kev; kev.release = false;
627 Event e; e.r = REPEAT_NOT; e.repeats = 0; e.time = now;
628 if (sdl.key) {
629 set<InterfaceKey> events = key_translation(sdl);
630 for (set<InterfaceKey>::iterator k = events.begin(); k != events.end(); ++k) {
631 e.serial = serial;
632 e.k = *k;
633 timeline.insert(e);
636 if (uni.unicode) {
637 set<InterfaceKey> events = key_translation(uni);
638 for (set<InterfaceKey>::iterator k = events.begin(); k != events.end(); ++k) {
639 e.serial = serial;
640 e.k = *k;
641 timeline.insert(e);
645 #endif
647 void enabler_inputst::add_input_refined(KeyEvent &e, Uint32 now, int serial) {
648 // We may be registering a new mapping, in which case we skip the
649 // rest of this function.
650 if (key_registering && !e.release) {
651 stored_keys.push_back(e.match);
652 Event e; e.r = REPEAT_NOT; e.repeats = 0; e.time = now; e.serial = serial; e.k = INTERFACEKEY_KEYBINDING_COMPLETE; e.tick = enabler.simticks.read();
653 timeline.insert(e);
654 return;
657 // If this is a key-press event, we add it to the timeline. If it's
658 // a release, we remove any pending repeats, but not those that
659 // haven't repeated yet (which are on their first cycle); those we
660 // just set to non-repeating.
661 set<InterfaceKey> keys = key_translation(e.match);
662 if (e.release) {
663 set<Event>::iterator it = timeline.begin();
664 while (it != timeline.end()) {
665 set<Event>::iterator el = it++;
666 if (keys.count(el->k)) {
667 if (el->repeats) {
668 timeline.erase(el);
669 } else {
670 Event new_el = *el;
671 new_el.r = REPEAT_NOT;
672 timeline.erase(el);
673 timeline.insert(new_el);
677 } else {
678 set<InterfaceKey>::iterator key;
679 // As policy, when the user hits a non-repeating key we'd want to
680 // also cancel any keys that are currently repeating. This allows
681 // for easy recovery from stuck keys.
683 // Unfortunately, each key may be bound to multiple
684 // commands. So, lacking information on which commands are
685 // accepted at the moment, there is no way we can know if it's
686 // okay to cancel repeats unless /all/ the bindings are
687 // non-repeating.
688 for (set<InterfaceKey>::iterator k = keys.begin(); k != keys.end(); ++k) {
689 Event e = {key_repeat(*k), *k, 0, serial, now, enabler.simticks.read()};
690 timeline.insert(e);
692 // if (cancel_ok) {
693 // // Set everything on the timeline to non-repeating
694 // multimap<Time,Event>::iterator it;
695 // for (it = timeline.begin(); it != timeline.end(); ++it) {
696 // it->second.r = REPEAT_NOT;
697 // }
702 void enabler_inputst::clear_input() {
703 timeline.clear();
704 pressed_keys.clear();
705 modState = 0;
706 last_serial = 0;
709 set<InterfaceKey> enabler_inputst::get_input(Time now) {
710 // We walk the timeline, returning all events corresponding to a
711 // single physical keypress, and inserting repeats relative to the
712 // current time, not when the events we're now returning were
713 // *supposed* to happen.
715 set<InterfaceKey> input;
716 set<Event>::iterator ev = timeline.begin();
717 if (ev == timeline.end() || ev->time > now) {
718 return input; // No input (yet).
721 const Time first_time = ev->time;
722 const int first_serial = ev->serial;
723 int simtick = enabler.simticks.read();
724 bool event_from_macro = false;
725 while (ev != timeline.end() && ev->time == first_time && ev->serial == first_serial) {
726 // Avoid recording macro-sources events as macro events.
727 if (ev->macro) event_from_macro = true;
728 // To make sure the user had a chance to cancel (by lifting the key), we require there
729 // to be at least three simulation ticks before the first repeat.
730 if (ev->repeats == 1 && ev->tick > simtick - 3) {
731 } else {
732 input.insert(ev->k);
734 // Schedule a repeat
735 Event next = *ev;
736 next.repeats++;
737 switch (next.r) {
738 case REPEAT_NOT:
739 break;
740 case REPEAT_SLOW:
741 if (ev->repeats == 0) {
742 next.time = now + init.input.hold_time;
743 timeline.insert(next);
744 break;
746 case REPEAT_FAST:
747 double accel = 1;
748 if (ev->repeats >= init.input.repeat_accel_start) {
749 // Compute acceleration
750 accel = MIN(init.input.repeat_accel_limit,
751 sqrt(double(next.repeats - init.input.repeat_accel_start) + 16) - 3);
753 next.time = now + double(init.input.repeat_time) / accel;
754 timeline.insert(next);
755 break;
757 // Delete the event from the timeline and iterate
758 timeline.erase(ev++);
760 #ifdef DEBUG
761 if (input.size() && !init.display.flag.has_flag(INIT_DISPLAY_FLAG_TEXT)) {
762 cout << "Returning input:\n";
763 set<InterfaceKey>::iterator it;
764 for (it = input.begin(); it != input.end(); ++it)
765 cout << " " << GetKeyDisplay(*it) << ": " << GetBindingDisplay(*it) << endl;
767 #endif
768 // It could be argued that the "record event" step of recording
769 // belongs in add_input, not here. I don't hold with this
770 // argument. The whole point is to record events as the user seems
771 // them happen.
772 if (macro_recording && !event_from_macro) {
773 set<InterfaceKey> macro_input = input;
774 macro_input.erase(INTERFACEKEY_RECORD_MACRO);
775 macro_input.erase(INTERFACEKEY_PLAY_MACRO);
776 macro_input.erase(INTERFACEKEY_SAVE_MACRO);
777 macro_input.erase(INTERFACEKEY_LOAD_MACRO);
778 if (macro_input.size())
779 active_macro.push_back(macro_input);
781 return input;
784 set<InterfaceKey> enabler_inputst::key_translation(EventMatch &match) {
785 set<InterfaceKey> bindings;
786 pair<multimap<EventMatch,InterfaceKey>::iterator,multimap<EventMatch,InterfaceKey>::iterator> its;
788 for (its = keymap.equal_range(match); its.first != its.second; ++its.first)
789 bindings.insert((its.first)->second);
791 return bindings;
794 string enabler_inputst::GetKeyDisplay(int binding) {
795 map<InterfaceKey,set<string,less_sz> >::iterator it = keydisplay.find(binding);
796 if (it != keydisplay.end() && it->second.size())
797 return *it->second.begin();
798 else {
799 cout << "Missing binding displayed: " + bindingNames.left[binding] << endl;
800 return "?";
804 string enabler_inputst::GetBindingDisplay(int binding) {
805 map<InterfaceKey,string>::iterator it = bindingNames.left.find(binding);
806 if (it != bindingNames.left.end())
807 return it->second;
808 else
809 return "NO BINDING";
812 string enabler_inputst::GetBindingTextDisplay(int binding) {
813 map<InterfaceKey,string>::iterator it = displayNames.left.find(binding);
814 if (it !=displayNames.left.end())
815 return it->second;
816 else
817 return "NO BINDING";
820 Repeat enabler_inputst::key_repeat(InterfaceKey binding) {
821 map<InterfaceKey,Repeat>::iterator it = repeatmap.find(binding);
822 if (it != repeatmap.end())
823 return it->second;
824 else
825 return REPEAT_NOT;
828 void enabler_inputst::key_repeat(InterfaceKey binding, Repeat repeat) {
829 repeatmap[binding] = repeat;
832 void enabler_inputst::record_input() {
833 active_macro.clear();
834 macro_recording = true;
837 void enabler_inputst::record_stop() {
838 macro_recording = false;
841 bool enabler_inputst::is_recording() {
842 return macro_recording;
845 void enabler_inputst::play_macro() {
846 Time now = SDL_GetTicks();
847 for(set<Event>::iterator i = timeline.begin(); i != timeline.end(); i++){
848 now = MAX(now, (*i).time);
850 for (macro::iterator sim = active_macro.begin(); sim != active_macro.end(); ++sim) {
851 Event e; e.r = REPEAT_NOT; e.repeats = 0; e.serial = next_serial(); e.time = now;
852 e.macro = true; // Avoid exponential macro blowup.
853 for (set<InterfaceKey>::iterator k = sim->begin(); k != sim->end(); ++k) {
854 e.k = *k;
855 timeline.insert(e);
856 now += init.input.macro_time;
859 macro_end = MAX(macro_end, now);
862 bool enabler_inputst::is_macro_playing() {
863 return SDL_GetTicks() <= macro_end;
866 // Replaces any illegal letters.
867 static string filter_filename(string name, char replacement) {
868 for (int i = 0; i < name.length(); i++) {
869 switch (name[i]) {
870 case '<': name[i] = replacement; break;
871 case '>': name[i] = replacement; break;
872 case ':': name[i] = replacement; break;
873 case '"': name[i] = replacement; break;
874 case '/': name[i] = replacement; break;
875 case '\\': name[i] = replacement; break;
876 case '|': name[i] = replacement; break;
877 case '?': name[i] = replacement; break;
878 case '*': name[i] = replacement; break;
880 if (name[i] <= 31) name[i] = replacement;
882 return name;
885 void enabler_inputst::load_macro_from_file(const string &file) {
886 ifstream s(file.c_str());
887 char buf[100];
888 s.getline(buf, 100);
889 string name(buf);
890 if (macros.find(name) != macros.end()) return; // Already got it.
892 macro macro;
893 set<InterfaceKey> group;
894 for(;;) {
895 s.getline(buf, 100);
896 if (!s.good()) {
897 MessageBox(NULL, "I/O error while loading macro", 0, 0);
898 s.close();
899 return;
901 string line(buf);
902 if (line == "End of macro") {
903 if (group.size()) macro.push_back(group);
904 break;
905 } else if (line == "\tEnd of group") {
906 if (group.size()) macro.push_back(group);
907 group.clear();
908 } else if (line.substr(0,2) != "\t\t" ) {
909 if( line.substr(1).find("\t") != string::npos) {
910 // expecting /t##/tCMD for a repeated command
911 istringstream ss(line.substr(1));
912 int count;
913 string remainingline;
915 if(ss >> count) {
916 ss >> remainingline;
917 if(remainingline.size()) {
918 for(int i=0; i < count; i++) {
919 map<string,InterfaceKey>::iterator it = bindingNames.right.find(remainingline);
920 if (it == bindingNames.right.end()) {
921 cout << "Binding name unknown while loading macro: " << line.substr(1) << endl;
922 } else {
923 group.insert(it->second);
924 if (group.size()) macro.push_back(group);
925 group.clear();
929 else {
930 cout << "Binding missing while loading macro: " << line.substr(1) << endl;
932 } else {
933 cout << "Quantity not numeric or Unexpected tab(s) while loading macro: " << line.substr(1) << endl;
936 else
938 // expecting /tCMD for a non-grouped command
939 map<string,InterfaceKey>::iterator it = bindingNames.right.find(line.substr(1));
940 if (it == bindingNames.right.end()) {
941 cout << "Binding name unknown while loading macro: " << line.substr(1) << endl;
942 } else {
943 group.insert(it->second);
944 if (group.size()) macro.push_back(group);
945 group.clear();
948 } else {
949 map<string,InterfaceKey>::iterator it = bindingNames.right.find(line.substr(2));
950 if (it == bindingNames.right.end())
951 cout << "Binding name unknown while loading macro: " << line.substr(2) << endl;
952 else
953 group.insert(it->second);
956 if (s.good())
957 macros[name] = macro;
958 else
959 MessageBox(NULL, "I/O error while loading macro", 0, 0);
960 s.close();
963 void enabler_inputst::save_macro_to_file(const string &file, const string &name, const macro &macro) {
964 ofstream s(file.c_str());
965 s << name << endl;
966 for (macro::const_iterator group = macro.begin(); group != macro.end(); ++group) {
967 for (set<InterfaceKey>::const_iterator key = group->begin(); key != group->end(); ++key)
968 s << "\t\t" << bindingNames.left[*key] << endl;
969 s << "\tEnd of group" << endl;
971 s << "End of macro" << endl;
972 s.close();
975 list<string> enabler_inputst::list_macros() {
976 // First, check for unloaded macros
977 svector<char*> files;
978 find_files_by_pattern("data/init/macros/*.mak", files);
979 for (int i = 0; i < files.size(); i++) {
980 string file(files[i]);
981 delete files[i];
982 file = "data/init/macros/" + file;
983 load_macro_from_file(file);
985 // Then return all in-memory macros
986 list<string> ret;
987 for (map<string,macro>::iterator it = macros.begin(); it != macros.end(); ++it)
988 ret.push_back(it->first);
989 return ret;
992 void enabler_inputst::load_macro(string name) {
993 if (macros.find(name) != macros.end())
994 active_macro = macros[name];
995 else
996 macros.clear();
999 void enabler_inputst::save_macro(string name) {
1000 macros[name] = active_macro;
1001 save_macro_to_file("data/init/macros/" + filter_filename(name, '_') + ".mak", name, active_macro);
1004 void enabler_inputst::delete_macro(string name) {
1005 map<string,macro>::iterator it = macros.find(name);
1006 if (it != macros.end()) macros.erase(it);
1007 // TODO: Store the filename it was loaded from instead
1008 string filename = "data/init/macros/" + filter_filename(name, '_') + ".mak";
1009 remove(filename.c_str());
1013 // Sets the next key-press to be stored instead of executed.
1014 void enabler_inputst::register_key() {
1015 key_registering = true;
1016 stored_keys.clear();
1019 // Returns a description of stored keys. Max one of each type.
1020 list<RegisteredKey> enabler_inputst::getRegisteredKey() {
1021 key_registering = false;
1022 list<RegisteredKey> ret;
1023 for (list<EventMatch>::iterator it = stored_keys.begin(); it != stored_keys.end(); ++it) {
1024 struct RegisteredKey r = {it->type, display(*it)};
1025 ret.push_back(r);
1027 return ret;
1030 // Binds one of the stored keys to key
1031 void enabler_inputst::bindRegisteredKey(MatchType type, InterfaceKey key) {
1032 for (list<EventMatch>::iterator it = stored_keys.begin(); it != stored_keys.end(); ++it) {
1033 if (it->type == type) {
1034 keymap.insert(pair<EventMatch,InterfaceKey>(*it, key));
1035 update_keydisplay(key, display(*it));
1040 bool enabler_inputst::is_registering() {
1041 return key_registering;
1045 list<EventMatch> enabler_inputst::list_keys(InterfaceKey key) {
1046 list<EventMatch> ret;
1047 // Oh, now this is inefficient.
1048 for (multimap<EventMatch,InterfaceKey>::iterator it = keymap.begin(); it != keymap.end(); ++it)
1049 if (it->second == key) ret.push_back(it->first);
1050 return ret;
1053 void enabler_inputst::remove_key(InterfaceKey key, EventMatch ev) {
1054 for (multimap<EventMatch,InterfaceKey>::iterator it = keymap.find(ev);
1055 it != keymap.end() && it->first == ev;
1056 ++it) {
1057 if (it->second == key) keymap.erase(it++);
1059 // Also remove the key from key displaying, assuming we can find it
1060 map<InterfaceKey,set<string,less_sz> >::iterator it = keydisplay.find(key);
1061 if (it != keydisplay.end())
1062 it->second.erase(display(ev));
1065 bool enabler_inputst::prefix_building() {
1066 return in_prefix_command;
1069 void enabler_inputst::prefix_toggle() {
1070 in_prefix_command = !in_prefix_command;
1071 prefix_command.clear();
1074 void enabler_inputst::prefix_add_digit(char digit) {
1075 prefix_command.push_back(digit);
1076 #ifdef DEBUG
1077 cout << "Built prefix to " << prefix_command << endl;
1078 #endif
1079 if (atoi(prefix_command.c_str()) > 99)
1080 prefix_command = "99"; // Let's not go overboard here.
1083 int enabler_inputst::prefix_end() {
1084 if (prefix_command.size()) {
1085 int repeats = atoi(prefix_command.c_str());
1086 prefix_toggle();
1087 return repeats;
1088 } else {
1089 return 1;
1093 string enabler_inputst::prefix() {
1094 return prefix_command;