Branch data Line data Source code
1 : : #ifdef RUN_TESTS
2 : : # include <gtest/gtest.h>
3 : : #endif
4 : : /** @file ui.cc
5 : : * @brief User interface.
6 : : */
7 : :
8 : : #include <unordered_map>
9 : : #include <cstdlib>
10 : : #include <string>
11 : : #include <vector>
12 : : #include <cstdio>
13 : : #include <cmath>
14 : :
15 : : #include "ui.hh"
16 : :
17 : : #include <SDL.h>
18 : : #include <SDL_syswm.h>
19 : :
20 : : #ifdef SDL_VIDEO_DRIVER_X11
21 : : # include <X11/Xlib.h>
22 : : #endif
23 : : #ifdef SDL_VIDEO_DRIVER_WINDOWS
24 : : # include <Utilapiset.h>
25 : : #endif
26 : :
27 : : namespace
28 : : {
29 : : std::unordered_map<SDL_Keycode, bool> keys; ///< List of currently depressed keys
30 : :
31 : : SDL_Window* window = nullptr;
32 : : SDL_Renderer* renderer = nullptr;
33 : : SDL_Texture* texture = nullptr;
34 : : unsigned cells_horiz, cell_width_pixels, pixels_width, bufpixels_width, texturewidth;
35 : : unsigned cells_vert, cell_height_pixels, pixels_height, bufpixels_height, textureheight;
36 : : std::vector<std::uint32_t> pixbuf;
37 : : // Scale factor
38 : : float ScaleX = 1.f;
39 : : float ScaleY = 1.f;
40 : :
41 : 3 : void SDL_ReInitialize(unsigned cells_horizontal, unsigned cells_vertical)
42 : : {
43 : 3 : cells_horiz = cells_horizontal;
44 : 3 : cells_vert = cells_vertical;
45 [ + + ]: 3 : cell_width_pixels = ui.GetCellSize().first;
46 : 3 : cell_height_pixels = ui.GetCellSize().second;
47 : 3 : pixels_width = cells_horizontal * cell_width_pixels,
48 : 3 : pixels_height = cells_vertical * cell_height_pixels;
49 : 3 : bufpixels_width = cells_horizontal * ui.GetCellSize().first;
50 : 3 : bufpixels_height = cells_vertical * ui.GetCellSize().second;
51 : :
52 [ + + ]: 3 : if(!ui.IsHeadless())
53 : : {
54 : 2 : bool had_window = window;
55 [ + + ]: 2 : if(!window)
56 : : {
57 : 1 : window = SDL_CreateWindow("that terminal",
58 : : //0,0,
59 : : SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED,
60 : 1 : pixels_width*ScaleX, pixels_height*ScaleY,
61 : : SDL_WINDOW_RESIZABLE);
62 : : }
63 : : else
64 : : {
65 : 1 : SDL_SetWindowSize(window, pixels_width*ScaleX, pixels_height*ScaleY);
66 : : }
67 [ + + ]: 2 : if(!renderer)
68 : : {
69 : 1 : renderer = SDL_CreateRenderer(window, -1, 0);
70 : : }
71 : :
72 [ + + - + : 2 : if(texture && (texturewidth<bufpixels_width || textureheight<bufpixels_height))
- - ]
73 : : {
74 : 1 : SDL_DestroyTexture(texture);
75 : 1 : texture = nullptr;
76 : : }
77 [ + - ]: 2 : if(!texture)
78 : : {
79 : 2 : texture = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_BGRA32,
80 : : SDL_TEXTUREACCESS_STREAMING,
81 : 2 : texturewidth = bufpixels_width,
82 : 2 : textureheight = bufpixels_height);
83 : : }
84 : :
85 : 2 : int w,h;
86 : 2 : SDL_GetWindowSize(window, &w,&h);
87 : 2 : ScaleX = w/(float)pixels_width;
88 : 2 : ScaleY = h/(float)pixels_height;
89 : :
90 [ + + ]: 2 : if(!had_window)
91 : 1 : SDL_StartTextInput();
92 : : }
93 : :
94 : 3 : pixbuf.resize(bufpixels_width*bufpixels_height);
95 : :
96 : 3 : fprintf(stderr, "Cells: %ux%u, pix sizes: %ux%u (%u), pixels: %ux%u, buf: %ux%u scale:%gx%g\n",
97 : : cells_horiz,cells_vert,
98 : 3 : cell_width_pixels,cell_height_pixels, ui.GetCellSize().second,
99 : : pixels_width,pixels_height,
100 : : bufpixels_width,bufpixels_height,
101 : : ScaleX, ScaleY);
102 : 3 : }
103 : :
104 : :
105 : : }
106 : :
107 : 2 : void UI::BeepOn()
108 : : {
109 [ + + ]: 3 : if(IsHeadless()) return;
110 : :
111 : 1 : SDL_SysWMinfo info = {};
112 : 1 : SDL_VERSION(&info.version);
113 [ - + ]: 1 : if(!SDL_GetWindowWMInfo(window,&info))
114 : 0 : fprintf(stderr, "GetWindowWMInfo failed %s\n", SDL_GetError());
115 : :
116 : : #ifdef SDL_VIDEO_DRIVER_X11
117 [ + - ]: 1 : if(info.subsystem == SDL_SYSWM_X11)
118 : : {
119 [ + - ]: 1 : if(auto display = info.info.x11.display)
120 : : {
121 : 1 : XKeyboardControl ctrl = {};
122 : 1 : ctrl.bell_percent = 100;
123 : 1 : ctrl.bell_pitch = 440;
124 : 1 : ctrl.bell_duration = 50;
125 : 1 : XChangeKeyboardControl(display, KBBellPitch|KBBellPercent|KBBellDuration, &ctrl);
126 : 1 : XBell(display, 100);
127 : 1 : return;
128 : : }
129 : : }
130 : : #endif
131 : : #ifdef SDL_VIDEO_DRIVER_WINDOWS
132 : : if(info.subsystem == SDL_SYSWM_WINDOWS)
133 : : {
134 : : Beep(440, 50);
135 : : return;
136 : : }
137 : : #endif
138 : : // Unknown video driver.
139 : : // TODO: Create an audio interface.
140 : : // TODO: Synthesize beep.
141 : : }
142 : :
143 : 3 : void UI::SetWindowTitle(std::string_view str)
144 : : {
145 [ + + ]: 3 : if(window)
146 [ + - ]: 2 : SDL_SetWindowTitle(window, std::string(str).c_str()); // Ensure nul-terminated
147 : 3 : }
148 : :
149 : 2 : void UI::SetIconName(std::string_view)
150 : : {
151 : : /* Unimplemented */
152 : 2 : }
153 : :
154 : 3 : void UI::ResizeTo(unsigned cellx,unsigned celly, unsigned width,unsigned height)
155 : : {
156 : 3 : VidCellWidth = cellx;
157 : 3 : VidCellHeight = celly;
158 : 3 : WindowWidth = width;
159 : 3 : WindowHeight = height;
160 : 3 : SDL_ReInitialize(WindowWidth, WindowHeight);
161 : 3 : }
162 : :
163 : 3 : void UI::PresentGraphics(const std::uint32_t* pixbuf)
164 : : {
165 [ + + + - ]: 3 : if(ui.IsHeadless() || !window)
166 : 1 : return;
167 : :
168 : 2 : SDL_Rect rect;
169 : 2 : rect.x=0; rect.w=bufpixels_width;
170 : 2 : rect.y=0; rect.h=0;
171 : 2 : unsigned errors = 0;
172 : 4 : auto RenderFlushLines = [&]()
173 : : {
174 [ - + ]: 2 : if(!rect.h) return;
175 : :
176 : 2 : int w,h;
177 : 2 : SDL_GetWindowSize(window, &w,&h);
178 : :
179 : 2 : SDL_Rect trect;
180 : 2 : trect.x = rect.x * w / bufpixels_width;
181 : 2 : trect.y = rect.y * h / bufpixels_height;
182 : 2 : trect.w = (rect.x + rect.w) * w / bufpixels_width - trect.x;
183 : 2 : trect.h = (rect.y + rect.h) * h / bufpixels_height - trect.y;
184 : :
185 [ - + ]: 2 : if(SDL_UpdateTexture(texture, &rect,
186 : 2 : &pixbuf[0] + rect.y*bufpixels_width,
187 : 2 : bufpixels_width*sizeof(pixbuf[0]))) ++errors;
188 [ - + ]: 2 : if(SDL_RenderCopy(renderer, texture, &rect, &trect)) ++errors;
189 : :
190 : 2 : rect.y += rect.h;
191 : 2 : rect.h = 0;
192 : 2 : };
193 : 242 : auto RenderAddLine = [&](unsigned line)
194 : : {
195 [ + - - + ]: 240 : if(line > unsigned(rect.y+rect.h+15) || line < unsigned(rect.y))
196 : : {
197 : 0 : RenderFlushLines();
198 : : }
199 [ + + ]: 240 : if(!rect.h) { rect.y = line; rect.h = 1; }
200 : 238 : else rect.h = line+1-rect.y;
201 : 242 : };
202 : :
203 [ + + ]: 242 : for(unsigned y=0; y<cells_vert*VidCellHeight; ++y)
204 : 240 : RenderAddLine(y);
205 : :
206 : 2 : RenderFlushLines();
207 : :
208 [ + - ]: 2 : if(rect.y) { SDL_RenderPresent(renderer); }
209 : : }
210 : :
211 : 4858 : UI::EventType UI::HandleEvents(bool permit_text_input)
212 : : {
213 [ + + ]: 4858 : std::string outbuffer, pending_input;
214 : 9716 : auto retval = [&](auto&& v) -> UI::EventType
215 : : {
216 [ + - ]: 9716 : return std::pair(std::move(outbuffer) + std::move(pending_input),
217 : 4858 : std::move(v));
218 : 4858 : };
219 [ + + ]: 4858 : if(!IsHeadless())
220 [ + + ]: 5455 : for(SDL_Event ev; SDL_PollEvent(&ev); )
221 : : {
222 [ + + + + : 617 : switch(ev.type)
+ ]
223 : : {
224 : 10 : case SDL_WINDOWEVENT:
225 [ + + ]: 10 : switch(ev.window.event)
226 : : {
227 : 6 : case SDL_WINDOWEVENT_EXPOSED:
228 : 6 : case SDL_WINDOWEVENT_RESIZED:
229 : 6 : case SDL_WINDOWEVENT_SIZE_CHANGED:
230 : 6 : {
231 [ + - ]: 6 : if(!Allow_Windows_Bigger_Than_Desktop)
232 : : {
233 : 6 : int w,h;
234 [ + - ]: 6 : SDL_GetWindowSize(window, &w,&h);
235 [ + - ]: 6 : return retval(std::pair<int,int>(w/ScaleX, h/ScaleY));
236 : : }
237 : : break;
238 : : }
239 : : default:
240 : : break;
241 : : }
242 : : break;
243 : 1 : case SDL_QUIT:
244 [ + - ]: 1 : return retval(true); // quit
245 : 1 : case SDL_TEXTINPUT:
246 : : //std::fprintf(stderr, "Text input(%s)\n", ev.text.text);
247 [ + - ]: 1 : if(permit_text_input)
248 : : {
249 [ + - ]: 1 : pending_input.clear(); // Overrides any input events from SDL_KEYDOWN
250 [ + - + - ]: 5456 : outbuffer += ev.text.text;
251 : : }
252 : : break;
253 : 602 : case SDL_KEYDOWN:
254 : 602 : case SDL_KEYUP:
255 : 602 : {
256 [ + - ]: 602 : keys[ev.key.keysym.sym] = (ev.type == SDL_KEYDOWN);
257 [ + - + + ]: 602 : if(permit_text_input && ev.type == SDL_KEYDOWN)
258 : : {
259 [ + - + + : 548 : bool shift = keys[SDLK_LSHIFT] || keys[SDLK_RSHIFT];
+ - - + ]
260 [ + - + + : 548 : bool alt = keys[SDLK_LALT] || keys[SDLK_RALT];
+ - - + ]
261 [ + - + + : 548 : bool ctrl = keys[SDLK_LCTRL] || keys[SDLK_RCTRL];
+ - - + ]
262 [ + + + + ]: 548 : if(!shift && !alt && !ctrl)
263 [ + + + + : 67 : switch(ev.key.keysym.sym)
+ + + + +
+ + + + ]
264 : : {
265 [ + - ]: 1 : case SDLK_F1: return retval(std::pair(-1, resizetype::winy));
266 [ + - ]: 1 : case SDLK_F2: return retval(std::pair(+1, resizetype::winy));
267 [ + - ]: 1 : case SDLK_F3: return retval(std::pair(-1, resizetype::winx));
268 [ + - ]: 1 : case SDLK_F4: return retval(std::pair(+1, resizetype::winx));
269 [ + - ]: 1 : case SDLK_F5: return retval(std::pair(-1, resizetype::celly));
270 [ + - ]: 1 : case SDLK_F6: return retval(std::pair(+1, resizetype::celly));
271 [ + - ]: 1 : case SDLK_F7: return retval(std::pair(-1, resizetype::cellx));
272 [ + - ]: 1 : case SDLK_F8: return retval(std::pair(+1, resizetype::cellx));
273 : 1 : case SDLK_F9: // Decrease Y-scale:
274 [ - + ]: 1 : if(ScaleY >= 2) --ScaleY; else ScaleY /= std::sqrt(2);
275 [ + - ]: 1 : if(ScaleY < 1.5) ScaleY = 1;
276 [ + - ]: 1 : return retval(std::pair(0, resizetype::winy));
277 : 1 : case SDLK_F10:// Increase Y-scale:
278 [ + - ]: 1 : if(ScaleY < 2) ScaleY *= std::sqrt(2); else ++ScaleY;
279 [ - + ]: 1 : if(ScaleY >= 1.9) ScaleY = int(ScaleY+0.1);
280 [ + - ]: 1 : return retval(std::pair(0, resizetype::winy));
281 : 1 : case SDLK_F11:// Decrease X-scale:
282 [ - + ]: 1 : if(ScaleX >= 2) --ScaleX; else ScaleX /= std::sqrt(2);
283 [ + - ]: 1 : if(ScaleX < 1.5) ScaleX = 1;
284 [ + - ]: 1 : return retval(std::pair(0, resizetype::winx));
285 : 1 : case SDLK_F12:// Increase X-scale:
286 [ + - ]: 1 : if(ScaleX < 2) ScaleX *= std::sqrt(2); else ++ScaleX;
287 [ - + ]: 1 : if(ScaleX >= 1.9) ScaleX = int(ScaleX+0.1);
288 [ + - ]: 1 : return retval(std::pair(0, resizetype::winx));
289 : : }
290 : : // Put the input in "pending_input", so that it gets automatically
291 : : // cancelled if a textinput event is generated.
292 [ + - ]: 1072 : pending_input += InterpretInput(shift, alt, ctrl, ev.key.keysym.sym);
293 : : }
294 : : break;
295 : : }
296 : : }
297 : : }
298 [ + - ]: 4839 : return retval(false);
299 : 4858 : }
300 : :
301 : 1 : UI::UI()
302 : : {
303 : 1 : }
304 : :
305 : 1 : UI::~UI()
306 : : {
307 : 1 : SDL_Quit();
308 : 1 : }
309 : :
310 : : UI ui;
311 : :
312 : : #ifdef RUN_TESTS
313 : 3 : TEST(ui, general)
314 : : {
315 : 1 : ui.SetHeadless(true);
316 : 1 : ui.BeepOn();
317 : 1 : ui.ResizeTo(8,8, 10,10);
318 [ + - ]: 1 : std::vector<std::uint32_t> pixbuf(10*10*8*8, 0xFF00FF);
319 [ + - ]: 1 : ui.PresentGraphics(&pixbuf[0]);
320 [ + - ]: 1 : ui.HandleEvents(true);
321 : :
322 [ + - ]: 1 : ui.SetHeadless(false);
323 : :
324 [ + - ]: 1 : ui.ResizeTo(8,8, 10,10);
325 [ + - ]: 1 : ui.SetWindowTitle("gruu");
326 [ + - ]: 1 : ui.SetIconName("gruu");
327 [ + - ]: 1 : ui.BeepOn();
328 [ + - ]: 1 : ui.PresentGraphics(&pixbuf[0]);
329 [ + - ]: 1 : ui.HandleEvents(true);
330 [ + - ]: 1 : ui.ResizeTo(16,16, 10,10);
331 [ + - ]: 1 : pixbuf.resize(10*10*16*16);
332 [ + - ]: 1 : ui.PresentGraphics(&pixbuf[0]);
333 : 1 : }
334 : :
335 : : using namespace std::string_view_literals;
336 : :
337 : : #include <cstring>
338 : 3 : TEST(ui, eventsim)
339 : : {
340 : 1 : std::string result{};
341 : 1 : SDL_Event ev{}, dummy{};
342 : :
343 : 608 : auto DoEvent = [&](auto type)
344 : : {
345 : 1214 : ev.type = type;
346 [ + + ]: 611 : while(SDL_PollEvent(&dummy)) {} // Delete all real events
347 : 607 : SDL_PushEvent(&ev); // Insert the fabricated event
348 : : // Now read events
349 [ + + ]: 5463 : for(unsigned n=0; n<8; ++n)
350 [ + - ]: 9712 : result += ui.HandleEvents(true).first;
351 : 608 : };
352 : 603 : auto DoKeyEvent = [&](auto type, auto sym)
353 : : {
354 : 602 : ev.key.keysym.sym = sym;
355 : 602 : DoEvent(type);
356 : 548 : };
357 : 10 : auto CtrlAltShiftOff = [&]()
358 : : {
359 [ + + ]: 63 : for(auto c: {SDLK_LSHIFT, SDLK_RSHIFT, SDLK_LALT, SDLK_RALT, SDLK_LCTRL, SDLK_RCTRL})
360 : 54 : DoKeyEvent(SDL_KEYUP, c);
361 : 10 : };
362 : :
363 [ + + ]: 4 : for(auto c: {SDL_WINDOWEVENT_EXPOSED, SDL_WINDOWEVENT_RESIZED, SDL_WINDOWEVENT_SIZE_CHANGED})
364 : : {
365 : 3 : ev.window.event = c;
366 [ + - ]: 3 : SDL_PushEvent(&ev);
367 [ + - ]: 3 : DoEvent(SDL_WINDOWEVENT);
368 : : }
369 : 1 : std::strcpy(ev.text.text, "kupo");
370 [ + - ]: 1 : DoEvent(SDL_TEXTINPUT);
371 : :
372 : 1 : static constexpr const std::string_view expected_results[25] =
373 : : {
374 : : "kupo"sv,
375 : : // None:
376 : : ""sv,
377 : : "\33OD\33OC\33OA\33OB\33[H\33[F\33[2~\33[3~\33[5~\33[6~"sv,
378 : : "\033.,-\r\x7F\t \r"sv,
379 : : // Shift:
380 : : "\33O1;2P\33O1;2Q\33O1;2R\33O1;2S\33[15;2~\33[17;2~\33[18;2~\33[19;2~\33[20;2~\33[21;2~\33[23;2~\33[24;2~"sv,
381 : : "\33[1;2D\33[1;2C\33[1;2A\33[1;2B\33[1;2H\33[1;2F\33[2;2~\33[3;2~\33[5;2~\33[6;2~"sv,
382 : : "\033.,-\r\x7F\33[Z \r"sv,
383 : : // Ctrl:
384 : : "\33O1;5P\33O1;5Q\33O1;5R\33O1;5S\33[15;5~\33[17;5~\33[18;5~\33[19;5~\33[20;5~\33[21;5~\33[23;5~\33[24;5~"sv,
385 : : "\33[1;5D\33[1;5C\33[1;5A\33[1;5B\33[1;5H\33[1;5F\33[2;5~\33[3;5~\33[5;5~\33[6;5~"sv,
386 : : "\x1\x2\x3\x4\x5\x6\a\b\t\n\v\f\r\xE\xF\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1A\033" "01\0\033\x1C\x1D\x1E\x1F\x7F" "9\xE\f\r\r\b\t\0\r"sv,
387 : : // Shift+Ctrl:
388 : : "\33O1;6P\33O1;6Q\33O1;6R\33O1;6S\33[15;6~\33[17;6~\33[18;6~\33[19;6~\33[20;6~\33[21;6~\33[23;6~\33[24;6~"sv,
389 : : "\33[1;6D\33[1;6C\33[1;6A\33[1;6B\33[1;6H\33[1;6F\33[2;6~\33[3;6~\33[5;6~\33[6;6~"sv,
390 : : "\x1\x2\x3\x4\x5\x6\a\b\33[Z\n\v\f\r\xE\xF\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1A\033" "01\0\033\x1C\x1D\x1E\x1F\x7F" "9\xE\f\r\r\b\33[Z\0\r"sv,
391 : : // Alt:
392 : : "\33O1;3P\33O1;3Q\33O1;3R\33O1;3S\33[15;3~\33[17;3~\33[18;3~\33[19;3~\33[20;3~\33[21;3~\33[23;3~\33[24;3~"sv,
393 : : "\33[1;3D\33[1;3C\33[1;3A\33[1;3B\33[1;3H\33[1;3F\33[2;3~\33[3;3~\33[5;3~\33[6;3~"sv,
394 : : "\xC3\xA1\xC3\xA2\xC3\xA3\xC3\xA4\xC3\xA5\xC3\xA6\xC3\xA7\xC3\xA8\xC3\xA9\xC3\xAA\xC3\xAB\xC3\xAC\xC3\xAD\xC3\xAE\xC3\xAF\xC3\xB0\xC3\xB1\xC3\xB2\xC3\xB3\xC3\xB4\xC3\xB5\xC3\xB6\xC3\xB7\xC3\xB8\xC3\xB9\xC3\xBA\xC2\x9B\xC2\xB0\xC2\xB1\xC2\xB2\xC2\xB3\xC2\xB4\xC2\xB5\xC2\xB6\xC2\xB7\xC2\xB8\xC2\xB9\xC2\xAE\xC2\xAC\xC2\xAD\xC2\x8D\xC3\xBF\xC2\x89\xC2\xA0\xC2\x8D"sv,
395 : : // Shift+Alt:
396 : : "\33O1;4P\33O1;4Q\33O1;4R\33O1;4S\33[15;4~\33[17;4~\33[18;4~\33[19;4~\33[20;4~\33[21;4~\33[23;4~\33[24;4~"sv,
397 : : "\33[1;4D\33[1;4C\33[1;4A\33[1;4B\33[1;4H\33[1;4F\33[2;4~\33[3;4~\33[5;4~\33[6;4~"sv,
398 : : "\xC3\x81\xC3\x82\xC3\x83\xC3\x84\xC3\x85\xC3\x86\xC3\x87\xC3\x88\xC3\x89\xC3\x8A\xC3\x8B\xC3\x8C\xC3\x8D\xC3\x8E\xC3\x8F\xC3\x90\xC3\x91\xC3\x92\xC3\x93\xC3\x94\xC3\x95\xC3\x96\xC3\x97\xC3\x98\xC3\x99\xC3\x9A\xC2\x9B\xC2\xB0\xC2\xB1\xC2\xB2\xC2\xB3\xC2\xB4\xC2\xB5\xC2\xB6\xC2\xB7\xC2\xB8\xC2\xB9\xC2\xAE\xC2\xAC\xC2\xAD\xC2\x8D\xC3\xBF\xC2\x89\xC2\xA0\xC2\x8D"sv,
399 : : // Ctrl+Alt:
400 : : "\33O1;7P\33O1;7Q\33O1;7R\33O1;7S\33[15;7~\33[17;7~\33[18;7~\33[19;7~\33[20;7~\33[21;7~\33[23;7~\33[24;7~"sv,
401 : : "\33[1;7D\33[1;7C\33[1;7A\33[1;7B\33[1;7H\33[1;7F\33[2;7~\33[3;7~\33[5;7~\33[6;7~"sv,
402 : : "\xC2\x81\xC2\x82\xC2\x83\xC2\x84\xC2\x85\xC2\x86\xC2\x87\xC2\x88\xC2\x89\xC2\x8A\xC2\x8B\xC2\x8C\xC2\x8D\xC2\x8E\xC2\x8F\xC2\x90\xC2\x91\xC2\x92\xC2\x93\xC2\x94\xC2\x95\xC2\x96\xC2\x97\xC2\x98\xC2\x99\xC2\x9A\xC2\x9B\xC2\xB0\xC2\xB1\xC2\x80\xC2\x9B\xC2\x9C\xC2\x9D\xC2\x9E\xC2\x9F\xC3\xBF\xC2\xB9\xC2\x8E\xC2\x8C\xC2\x8D\xC2\x8D\xC2\x88\xC2\x89\xC2\x80\xC2\x8D"sv,
403 : : // Shift+Ctrl+Alt:
404 : : "\33O1;8P\33O1;8Q\33O1;8R\33O1;8S\33[15;8~\33[17;8~\33[18;8~\33[19;8~\33[20;8~\33[21;8~\33[23;8~\33[24;8~"sv,
405 : : "\33[1;8D\33[1;8C\33[1;8A\33[1;8B\33[1;8H\33[1;8F\33[2;8~\33[3;8~\33[5;8~\33[6;8~"sv,
406 : : "\xC2\x81\xC2\x82\xC2\x83\xC2\x84\xC2\x85\xC2\x86\xC2\x87\xC2\x88\xC2\x89\xC2\x8A\xC2\x8B\xC2\x8C\xC2\x8D\xC2\x8E\xC2\x8F\xC2\x90\xC2\x91\xC2\x92\xC2\x93\xC2\x94\xC2\x95\xC2\x96\xC2\x97\xC2\x98\xC2\x99\xC2\x9A\xC2\x9B\xC2\xB0\xC2\xB1\xC2\x80\xC2\x9B\xC2\x9C\xC2\x9D\xC2\x9E\xC2\x9F\xC3\xBF\xC2\xB9\xC2\x8E\xC2\x8C\xC2\x8D\xC2\x8D\xC2\x88\xC2\x89\xC2\x80\xC2\x8D"sv
407 : : };
408 : :
409 : 1 : const std::string_view* result_ptr = expected_results;
410 : 1 : EXPECT_EQ(result, *result_ptr);
411 : 1 : result.clear(); ++result_ptr;
412 : :
413 [ + + ]: 9 : for(unsigned ctrlmask=0; ctrlmask<8; ++ctrlmask)
414 : : {
415 [ + - ]: 8 : CtrlAltShiftOff();
416 [ + + + - ]: 8 : if(ctrlmask&1) DoKeyEvent(SDL_KEYDOWN, SDLK_LSHIFT);
417 [ + + + - ]: 8 : if(ctrlmask&2) DoKeyEvent(SDL_KEYDOWN, SDLK_LCTRL);
418 [ + + + - ]: 8 : if(ctrlmask&4) DoKeyEvent(SDL_KEYDOWN, SDLK_LALT);
419 : 200 : for(auto c: {SDLK_F1, SDLK_F2, SDLK_F3, SDLK_F4, SDLK_F5, SDLK_F6, SDLK_F7, SDLK_F8,
420 [ + + ]: 104 : SDLK_F9, SDLK_F10, SDLK_F11, SDLK_F12})
421 : : {
422 [ + - ]: 192 : DoKeyEvent(SDL_KEYDOWN, c);
423 : : }
424 : :
425 : 8 : EXPECT_EQ(result, result_ptr[0]);
426 : 8 : result.clear();
427 : :
428 : 168 : for(auto c: {SDLK_LEFT, SDLK_RIGHT, SDLK_UP, SDLK_DOWN, SDLK_HOME, SDLK_END,
429 [ + + ]: 88 : SDLK_INSERT, SDLK_DELETE, SDLK_PAGEUP, SDLK_PAGEDOWN})
430 : : {
431 [ + - ]: 160 : DoKeyEvent(SDL_KEYDOWN, c);
432 : : }
433 : :
434 : 8 : EXPECT_EQ(result, result_ptr[1]);
435 : 8 : result.clear();
436 : :
437 : 728 : for(auto c: {SDLK_a,SDLK_b,SDLK_c,SDLK_d,SDLK_e,SDLK_f,SDLK_g,SDLK_h,SDLK_i,
438 : : SDLK_j,SDLK_k,SDLK_l,SDLK_m,SDLK_n,SDLK_o,SDLK_p,SDLK_q,SDLK_r,
439 : : SDLK_s,SDLK_t,SDLK_u,SDLK_v,SDLK_w,SDLK_x,SDLK_y,SDLK_z,
440 : : SDLK_ESCAPE,
441 : : SDLK_0,SDLK_1,SDLK_2,SDLK_3,SDLK_4,
442 : : SDLK_5,SDLK_6,SDLK_7,SDLK_8,SDLK_9,
443 : : SDLK_PERIOD,SDLK_COMMA,SDLK_SLASH,SDLK_RETURN,SDLK_BACKSPACE,
444 [ + + ]: 368 : SDLK_TAB,SDLK_SPACE,SDLK_KP_ENTER})
445 : : {
446 [ + - ]: 720 : DoKeyEvent(SDL_KEYDOWN, c);
447 : : }
448 : :
449 : 8 : EXPECT_EQ(result, result_ptr[2]);
450 : 8 : result.clear();
451 : :
452 : 8 : result_ptr += 3;
453 : : }
454 [ + - ]: 1 : DoEvent(SDL_QUIT);
455 [ + - ]: 1 : CtrlAltShiftOff();
456 : 1 : }
457 : : #endif
|