Branch data Line data Source code
1 : : #ifdef RUN_TESTS
2 : : # include <gtest/gtest.h>
3 : : #endif
4 : : /** @file keysym.cc
5 : : * @brief Defines InterpretInput()
6 : : */
7 : :
8 : : #include <unordered_map>
9 : : #include <cstdio> // sprintf
10 : :
11 : : #include "keysym.hh"
12 : : #include "ctype.hh"
13 : :
14 : : /** Define mappings between SDL keys and ESC[ sequences */
15 : : static const std::unordered_map<int, std::pair<int/*num*/,char/*letter*/>> lore
16 : : {
17 : : { SDLK_F1, {1,'P'} }, { SDLK_LEFT, {1,'D'} },
18 : : { SDLK_F2, {1,'Q'} }, { SDLK_RIGHT, {1,'C'} },
19 : : { SDLK_F3, {1,'R'} }, { SDLK_UP, {1,'A'} },
20 : : { SDLK_F4, {1,'S'} }, { SDLK_DOWN, {1,'B'} },
21 : : { SDLK_F5, {15,'~'} }, { SDLK_HOME, {1,'H'} },
22 : : { SDLK_F6, {17,'~'} }, { SDLK_END, {1,'F'} },
23 : : { SDLK_F7, {18,'~'} }, { SDLK_INSERT, {2,'~'} },
24 : : { SDLK_F8, {19,'~'} }, { SDLK_DELETE, {3,'~'} },
25 : : { SDLK_F9, {20,'~'} }, { SDLK_PAGEUP, {5,'~'} },
26 : : { SDLK_F10, {21,'~'} }, { SDLK_PAGEDOWN, {6,'~'} },
27 : : { SDLK_F11, {23,'~'} },
28 : : { SDLK_F12, {24,'~'} },
29 : : };
30 : : /** Mappings between SDL keys and ASCII sequences */
31 : : static const std::unordered_map<int, char> lore2
32 : : {
33 : : { SDLK_a, 'a' }, { SDLK_b, 'b' }, { SDLK_c, 'c' }, { SDLK_d, 'd' },
34 : : { SDLK_e, 'e' }, { SDLK_f, 'f' }, { SDLK_g, 'g' }, { SDLK_h, 'h' },
35 : : { SDLK_i, 'i' }, { SDLK_j, 'j' }, { SDLK_k, 'k' }, { SDLK_l, 'l' },
36 : : { SDLK_m, 'm' }, { SDLK_n, 'n' }, { SDLK_o, 'o' }, { SDLK_p, 'p' },
37 : : { SDLK_q, 'q' }, { SDLK_r, 'r' }, { SDLK_s, 's' }, { SDLK_t, 't' },
38 : : { SDLK_u, 'u' }, { SDLK_v, 'v' }, { SDLK_w, 'w' }, { SDLK_x, 'x' },
39 : : { SDLK_y, 'y' }, { SDLK_z, 'z' }, { SDLK_ESCAPE, '\33' },
40 : : { SDLK_0, '0' }, { SDLK_1, '1' }, { SDLK_2, '2' }, { SDLK_3, '3' },
41 : : { SDLK_4, '4' }, { SDLK_5, '5' }, { SDLK_6, '6' }, { SDLK_7, '7' },
42 : : { SDLK_8, '8' }, { SDLK_9, '9' }, { SDLK_PERIOD, '.' },
43 : : { SDLK_COMMA, ',' }, { SDLK_SLASH, '-' },
44 : : { SDLK_RETURN, '\r' }, { SDLK_BACKSPACE, '\177' }, { SDLK_TAB, '\t' },
45 : : { SDLK_SPACE, ' ' }, { SDLK_KP_ENTER, '\r' },
46 : : };
47 : :
48 : 552 : std::string InterpretInput(bool shift, bool alt, bool ctrl, SDL_Keycode sym)
49 : : {
50 [ + + ]: 552 : if(auto i = lore.find(sym); i != lore.end())
51 : : {
52 [ + + ]: 173 : const auto& d = i->second;
53 : 173 : unsigned delta = 1 + shift*1 + alt*2 + ctrl*4, len;
54 : 173 : char bracket = '[', Buf[16];
55 [ + + ]: 173 : if(d.second >= 'P' && d.second <= 'S') bracket = 'O';
56 [ + + + + ]: 173 : if(d.second >= 'A' && d.second <= 'D' && delta == 1) bracket = 'O'; // less requires this for up&down, alsamixer requires this for left&right
57 [ + + ]: 173 : if(delta != 1)
58 : 158 : len = std::sprintf(Buf, "\33%c%d;%d%c", bracket, d.first, delta, d.second);
59 [ + + ]: 15 : else if(d.first == 1)
60 : 7 : len = std::sprintf(Buf, "\33%c%c", bracket, d.second);
61 : : else
62 : 8 : len = std::sprintf(Buf, "\33%c%d%c", bracket, d.first, d.second);
63 : 173 : return std::string(Buf,len);
64 : : }
65 : :
66 [ + + ]: 379 : if(auto i = lore2.find(sym); i != lore2.end())
67 : : {
68 [ + + ]: 367 : char32_t cval = i->second;
69 : 367 : bool digit = cval >= '0' && cval <= '9', alpha = cval >= 'a' && cval <= 'z';
70 [ + + ]: 367 : if(shift && alpha) cval &= ~0x20; // Turn uppercase
71 [ + + ]: 367 : if(ctrl && digit) cval = "01\0\33\34\35\36\37\1779"[cval-'0'];
72 [ + + + + ]: 367 : if(ctrl && i->second=='\177') cval = '\b';
73 [ + + ]: 363 : else if(ctrl && !digit) cval &= 0x1F; // Turn into a control character
74 : : // CTRL a..z becomes 01..1A
75 : : // CTRL 0..9 becomes 10..19, should become xx,xx,00,1B-1F,7F,xx
76 [ + + ]: 367 : if(alt) cval |= 0x80; // Add ALT
77 [ + + + + ]: 367 : if((!alpha && !digit) || ctrl||alt)
78 : : {
79 : : //std::fprintf(stderr, "lore input(%c)(%d) with keysym=%d\n", char(cval), int(cval), sym);
80 [ + + + + ]: 293 : if(shift && cval == '\t')
81 [ + - ]: 4 : return std::string("\33[Z", 3);
82 : : else
83 [ + - ]: 289 : return ToUTF8(std::u32string_view(&cval,1));
84 : : }
85 : : }
86 : :
87 : 552 : return {};
88 : : }
89 : :
90 : :
91 : : #ifdef RUN_TESTS
92 : 3 : TEST(keysym, control_keys)
93 : : {
94 : 2 : EXPECT_EQ(InterpretInput(false,false,false, SDLK_F1), "\033OP");
95 : 2 : EXPECT_EQ(InterpretInput(true, false,false, SDLK_F1), "\033O1;2P");
96 : 2 : EXPECT_EQ(InterpretInput(false,false, true, SDLK_F1), "\033O1;5P");
97 : 2 : EXPECT_EQ(InterpretInput(true, false, true, SDLK_F1), "\033O1;6P");
98 : 2 : EXPECT_EQ(InterpretInput(true, true, true, SDLK_F1), "\033O1;8P");
99 : 2 : EXPECT_EQ(InterpretInput(false,false,false, SDLK_INSERT), "\033[2~");
100 : 2 : EXPECT_EQ(InterpretInput(false,false,false, SDLK_DELETE), "\033[3~");
101 : 2 : EXPECT_EQ(InterpretInput(false,false,false, SDLK_PAGEUP), "\033[5~");
102 : 2 : EXPECT_EQ(InterpretInput(false,false,false, SDLK_PAGEDOWN), "\033[6~");
103 : 1 : }
104 : 3 : TEST(keysym, regular_keys)
105 : : {
106 : : // Alphabetic input is disabled in order to not conflict with SDL TextInput
107 : 2 : EXPECT_EQ(InterpretInput(false,false,false, SDLK_a), "");
108 : 2 : EXPECT_EQ(InterpretInput(true, false,false, SDLK_a), "");
109 : 2 : EXPECT_EQ(InterpretInput(false,false, true, SDLK_c), "\3"); // ctrl-c
110 : 2 : EXPECT_EQ(InterpretInput(false,false,false, SDLK_TAB), "\t");
111 : 2 : EXPECT_EQ(InterpretInput(true,false,false, SDLK_TAB), "\033[Z");
112 : 2 : EXPECT_EQ(InterpretInput(false,false,false, SDLK_RETURN), "\r");
113 : 2 : EXPECT_EQ(InterpretInput(false,false,false, SDLK_SPACE), " ");
114 : 1 : }
115 : : #endif
|