LCOV - code coverage report
Current view: top level - src - ui.cc (source / functions) Hit Total Coverage
Test: main_coverage.info Lines: 230 232 99.1 %
Date: 2022-06-15 20:16:21 Functions: 20 22 90.9 %
Branches: 163 246 66.3 %

           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

Generated by: LCOV version 1.16