1 /*
2  *
3  *  Iter Vehemens ad Necem (IVAN)
4  *  Copyright (C) Timo Kiviluoto
5  *  Released under the GNU General
6  *  Public License
7  *
8  *  See LICENSING which should be included
9  *  along with this file for more details
10  *
11  */
12 
13 #include <cstdio>
14 #include <ctime>
15 #include <ratio>
16 #include <chrono>
17 
18 #include "bitmap.h"
19 #include "error.h"
20 #include "graphics.h"
21 #include "festring.h"
22 #include "rawbit.h"
23 #include "whandler.h"
24 
25 #include "dbgmsgproj.h"
26 
27 #if SDL_MAJOR_VERSION == 1
28 /* redefine SDL2 to SDL1 */
29 #define SDL_WINDOWEVENT SDL_VIDEOEXPOSE
30 #define SDLK_PRINTSCREEN SDLK_PRINT
31 #define SDLK_KP_0 SDLK_KP0
32 #define SDLK_KP_1 SDLK_KP1
33 #define SDLK_KP_2 SDLK_KP2
34 #define SDLK_KP_3 SDLK_KP3
35 #define SDLK_KP_4 SDLK_KP4
36 #define SDLK_KP_5 SDLK_KP5
37 #define SDLK_KP_6 SDLK_KP6
38 #define SDLK_KP_7 SDLK_KP7
39 #define SDLK_KP_8 SDLK_KP8
40 #define SDLK_KP_9 SDLK_KP9
41 #endif
42 
43 truth (*globalwindowhandler::ControlLoop[MAX_CONTROLS])();
44 int globalwindowhandler::Controls = 0;
45 ulong globalwindowhandler::Tick;
46 truth globalwindowhandler::ControlLoopsEnabled = true;
47 truth globalwindowhandler::playInBackground=false;
48 festring globalwindowhandler::ScrshotDirectoryName = "";
49 truth bLastSDLkeyEventIsKeyUp=false;
50 
InstallControlLoop(truth (* What)())51 void globalwindowhandler::InstallControlLoop(truth (*What)())
52 {
53   if(Controls == MAX_CONTROLS)
54     ABORT("Animation control frenzy!");
55 
56   ControlLoop[Controls++] = What;
57 }
58 
DeInstallControlLoop(truth (* What)())59 void globalwindowhandler::DeInstallControlLoop(truth (*What)())
60 {
61   int c;
62 
63   for(c = 0; c < Controls; ++c)
64     if(ControlLoop[c] == What)
65       break;
66 
67   if(c != Controls)
68   {
69     --Controls;
70 
71     for(; c < Controls; ++c)
72       ControlLoop[c] = ControlLoop[c + 1];
73   }
74 }
75 
IsKeyPressed(int iSDLScanCode)76 bool globalwindowhandler::IsKeyPressed(int iSDLScanCode)
77 {
78   return SDL_GetKeyboardState(NULL)[iSDLScanCode];
79 }
80 
81 
82 #ifdef __DJGPP__
83 
84 #include <pc.h>
85 #include <keys.h>
86 
GetKey(truth EmptyBuffer)87 int globalwindowhandler::GetKey(truth EmptyBuffer)
88 {
89   if(EmptyBuffer)
90     while(kbhit())
91       getkey();
92 
93   int Key = 0;
94 
95   while(!Key)
96   {
97     while(!kbhit())
98       if(Controls && ControlLoopsEnabled)
99       {
100         static ulong LastTick = 0;
101         UpdateTick();
102 
103         if(LastTick != Tick)
104         {
105           LastTick = Tick;
106           truth Draw = false;
107 
108           for(int c = 0; c < Controls; ++c)
109             if(ControlLoop[c]())
110               Draw = true;
111 
112           if(Draw)
113             graphics::BlitDBToScreen();
114         }
115       }
116 
117     Key = getkey();
118 
119     if(Key == K_Control_Print && !ScrshotDirectoryName.IsEmpty())
120     {
121       mkdir(ScrshotDirectoryName.CStr(), S_IRUSR|S_IWUSR);
122       DOUBLE_BUFFER->Save(ScrshotNameHandler());
123       Key = 0;
124     }
125   }
126 
127   return Key;
128 }
129 
ReadKey()130 int globalwindowhandler::ReadKey()
131 {
132   return kbhit() ? getkey() : 0;
133 }
134 
135 #endif
136 
137 #ifdef USE_SDL
138 
139 #include <algorithm>
140 
141 std::vector<int> globalwindowhandler::KeyBuffer;
142 truth (*globalwindowhandler::QuitMessageHandler)() = 0;
143 bool (*globalwindowhandler::FunctionKeyHandler)(SDL_Keycode) = 0;
144 bool (*globalwindowhandler::ControlKeyHandler)(SDL_Keycode) = 0;
145 
Init()146 void globalwindowhandler::Init()
147 {
148 #if SDL_MAJOR_VERSION == 1
149   SDL_EnableUNICODE(1);
150   SDL_EnableKeyRepeat(500, 30);
151 #else
152   //FIXSDL2 SDL_EnableKeyRepeat(500, 30);
153   SDL_ShowWindow(graphics::GetWindow());
154 #endif
155 }
156 
157 int iCountFPS=0;
158 int iLastSecondFPS=0;
159 std::chrono::high_resolution_clock::time_point tpLastSecondFPS;
MeasureLastSecondRealFPS()160 int MeasureLastSecondRealFPS(){ //call this every new frame request
161   iCountFPS++;
162 
163   using namespace std::chrono;
164   high_resolution_clock::time_point tpNow = high_resolution_clock::now();
165   duration<double, std::milli> delay = tpNow - tpLastSecondFPS;
166   if(delay.count() > 1000){ //1s
167     iLastSecondFPS=iCountFPS;
168     iCountFPS=0; //reset
169     tpLastSecondFPS = tpNow; //reset
170   }
171 
172   return iLastSecondFPS;
173 }
174 
175 std::chrono::high_resolution_clock::time_point tpPreviousFrameTime;
InstaCalcFPS()176 double InstaCalcFPS(){ //call this every new frame request
177   using namespace std::chrono;
178   high_resolution_clock::time_point tpNow = high_resolution_clock::now();
179   duration<double, std::milli> delay = tpNow - tpPreviousFrameTime;
180   tpPreviousFrameTime = tpNow;
181   double d = delay.count();
182   if(d==0)d=1; //TODO this may never happen?
183   return 1000/d;
184 }
185 
186 bool bAllowFrameSkip=true;
187 int iFrameSkip=0;
188 std::chrono::high_resolution_clock::time_point tpBefore;
189 std::chrono::duration<double, std::milli> delay;
190 int iLastSecCountFPS;
191 float fInstaFPS;
192 double dLastFrameTimeMS;
193 int iDefaultDelayMS=10;
194 int iAddFrameSkip=0;
195 
SetAddFrameSkip(int i)196 void globalwindowhandler::SetAddFrameSkip(int i){
197   iAddFrameSkip=i;
198   bAllowFrameSkip = iAddFrameSkip!=0;
199 }
200 
201 /**
202  *  to let user input be more responsive as full dungeon xBRZ may be too heavy
203  *  return SDL delay in ms
204  */
FrameSkipOrDraw()205 int FrameSkipOrDraw(){ //TODO could this be simplified?
206   bool bWaitAKeyPress=false;
207   bool bDoAutoFrameSkip=false;
208   bool bDrawFrame=false;
209   bool bDelay1MS=false;
210 
211   if(iFrameSkip<0)ABORT("iFrameSkip is %d < 0",iFrameSkip);
212 
213   if(iAddFrameSkip==-2){
214     if(dLastFrameTimeMS>142){ //if it is too slow <= 7 fps
215       bWaitAKeyPress=true;
216     }else{
217       bDoAutoFrameSkip=true;
218     }
219   }else
220   if(iAddFrameSkip==-1){
221     bDoAutoFrameSkip=true;
222   }
223 
224   if(!bWaitAKeyPress){ // if waiting a key press, there will have no stand-by animation at all...
225     if(iFrameSkip==0){
226       bDrawFrame=true;
227 
228       // setup next
229       if(bDoAutoFrameSkip){ //TODO improve this automatic mode?
230         if(dLastFrameTimeMS>250){ //4fps
231           iFrameSkip=10;
232         }else
233         if(dLastFrameTimeMS>200){ //5fps
234           iFrameSkip=5;
235         }else
236         if(dLastFrameTimeMS>150){
237           iFrameSkip=3;
238         }else
239         if(dLastFrameTimeMS>100){ //10fps
240           iFrameSkip=1;
241         }
242 
243         bDelay1MS=true;
244       }else{
245         if(iAddFrameSkip==0){ //vanilla  (wont be reached tho cuz of bAllowFrameSkip=false), kept for completeness (in case it changes before calling this method)
246           bDrawFrame=true;
247         }else
248         if(iAddFrameSkip>0){ //fixed
249           iFrameSkip=iAddFrameSkip;
250 
251           bDelay1MS=true;
252         }
253       }
254     }
255   }
256 
257   if(bDrawFrame){
258     tpBefore = std::chrono::high_resolution_clock::now();
259     graphics::BlitDBToScreen();
260     delay = std::chrono::high_resolution_clock::now() - tpBefore;
261     dLastFrameTimeMS = delay.count();
262 
263     //call these ONLY when the frame is actually DRAWN!!! (despite not being actually used yet)
264     iLastSecCountFPS = MeasureLastSecondRealFPS();
265     fInstaFPS = InstaCalcFPS();
266     //DBG5(DBGF(fInstaFPS),DBGI(iLastSecCountFPS),DBGF(dLastFrameTimeMS),DBGI(iAddFrameSkip),DBGI(iFrameSkip));
267   }else{
268     if(iFrameSkip>0)iFrameSkip--;
269     //DBGSI(iFrameSkip);
270   }
271 
272   if(bDelay1MS){
273     return 1;
274   }else{
275     return iDefaultDelayMS;
276   }
277 }
278 
279 const int globalwindowhandler::iRestWaitKey = '.';
280 
281 int iTimeoutDelay=0; // must init with 0
282 int iTimeoutDefaultKey = globalwindowhandler::iRestWaitKey;
283 long keyTimeoutRequestedAt;
284 /**
285  * This is intended to remain active ONLY until the user hits any key.
286  * iTimeoutMillis can be 0 or >=10
287  */
SetKeyTimeout(int iTimeoutMillis,int iDefaultReturnedKey)288 void globalwindowhandler::SetKeyTimeout(int iTimeoutMillis,int iDefaultReturnedKey)//,int iIgnoreKeyWhenDisabling)
289 {
290   if(iTimeoutMillis<0)ABORT("invalid negative timeout %d",iTimeoutMillis);
291 
292   iTimeoutDelay = (iTimeoutMillis/1000.0) * CLOCKS_PER_SEC;
293   if(iTimeoutDelay>0 && iTimeoutDelay<10)iTimeoutDelay=10; // we are unable to issue commands if it is too low TODO could be less than 10ms?
294 
295   iTimeoutDefaultKey=iDefaultReturnedKey;
296 }
IsKeyTimeoutEnabled()297 truth globalwindowhandler::IsKeyTimeoutEnabled()
298 {
299   return iTimeoutDelay>0;
300 }
CheckKeyTimeout()301 void globalwindowhandler::CheckKeyTimeout()
302 {
303   if(iTimeoutDelay>0){ // timeout mode is enalbed
304     if(!KeyBuffer.empty()){ DBG2(KeyBuffer.size(),KeyBuffer[0]); // user pressed some key
305       keyTimeoutRequestedAt=clock(); // resets reference time to wait from
306     }else{ DBG2(keyTimeoutRequestedAt,iTimeoutDelay);
307       if( clock() > (keyTimeoutRequestedAt+iTimeoutDelay) ) //wait for the timeout to...
308         KeyBuffer.push_back(iTimeoutDefaultKey); //...simulate the keypress
309     }
310   }
311 }
312 int iTimeoutDelayBkp=0;
SuspendKeyTimeout()313 void globalwindowhandler::SuspendKeyTimeout()
314 {
315   iTimeoutDelayBkp=iTimeoutDelay;
316   iTimeoutDelay=0;
317 }
ResumeKeyTimeout()318 void globalwindowhandler::ResumeKeyTimeout()
319 {
320   iTimeoutDelay=iTimeoutDelayBkp;
321 }
322 
GetFPS(bool bInsta)323 float globalwindowhandler::GetFPS(bool bInsta){
324   if(bInsta)return fInstaFPS;
325   return iLastSecCountFPS;
326 }
327 
HasKeysOnBuffer()328 truth globalwindowhandler::HasKeysOnBuffer(){
329   return KeyBuffer.size()>0;
330 }
331 
ShowFPS()332 void ShowFPS(){ //TODO still flickers sometimes cuz of silhouette?
333   static long lTimePrevious=clock();
334   static bool bShowFPS = [](){const char* c=std::getenv("IVAN_SHOWFPS");return c!=NULL && strcmp(c,"true")==0;}();
335   if(bShowFPS){
336 //    if(clock()%(CLOCKS_PER_SEC*3)<CLOCKS_PER_SEC){
337     long lTime=clock();
338     if(clock()-lTimePrevious > CLOCKS_PER_SEC*1){
339       static int iMargin=2;
340       static v2 v2Margin(iMargin,iMargin);
341       static char c[100];
342 
343       sprintf(c,"FPS:ls=%.1f,insta=%.1f",globalwindowhandler::GetFPS(false),globalwindowhandler::GetFPS(true));
344       int iDistX = strlen(c)*8 + 10 + 100; // +10 to look good, + 100 cuz of silhouette area
345       v2 v2Pos = RES-v2(iDistX,RES.Y)+v2Margin;
346       v2 v2Size(iDistX, 8+iMargin*2);
347 
348       DOUBLE_BUFFER->Fill(v2Pos,v2Size,BLACK);
349       FONT->Printf(DOUBLE_BUFFER,v2Pos+v2Margin,WHITE,"%s",c);
350       lTimePrevious=lTime;
351     }
352   }
353 }
354 
GetKey(truth EmptyBuffer)355 int globalwindowhandler::GetKey(truth EmptyBuffer)
356 {
357   SDL_Event Event;
358 
359   if(EmptyBuffer)
360   {
361     PollEvents(&Event);
362     KeyBuffer.clear();
363   }
364 
365   keyTimeoutRequestedAt=clock();
366   int iDelayMS=iDefaultDelayMS;
367   for(;;){
368     CheckKeyTimeout();
369 
370     if(!KeyBuffer.empty())
371     {
372       int Key = KeyBuffer[0];
373       KeyBuffer.erase(KeyBuffer.begin());
374 
375       if(Key > 0xE000)
376         return Key - 0xE000;
377 
378       if(Key && Key < 0x81)
379         return Key;
380     }
381     else
382     {
383       bool bHasFocus=false;
384 #if SDL_MAJOR_VERSION == 1
385       bHasFocus = SDL_GetAppState() & SDL_APPACTIVE;
386 #else
387       bHasFocus = SDL_GetWindowFlags(graphics::GetWindow()) & (SDL_WINDOW_MOUSE_FOCUS | SDL_WINDOW_INPUT_FOCUS);
388 #endif
389 
390       bool bPlay=true;
391 
392       if(bPlay && !bHasFocus && !playInBackground)
393         bPlay=false;
394 
395       if(bPlay && Controls==0)
396         bPlay=false;
397 
398       if(bPlay && !ControlLoopsEnabled)
399         bPlay=false;
400 
401       bool bHasEvents=PollEvents(&Event)>0;
402 
403       if(!bHasEvents)
404       {
405         if(bPlay)
406         {
407           static ulong LastTick = 0;
408           UpdateTick();
409 
410           if(LastTick != Tick)
411           {
412             LastTick = Tick;
413             truth Draw = false;
414 
415             for(int c = 0; c < Controls; ++c)
416               if(ControlLoop[c]())
417                 Draw = true;
418 
419             /******************
420              * the stand-by animation
421              */
422             ShowFPS();
423             if(!bAllowFrameSkip){
424               if(Draw)
425                 graphics::BlitDBToScreen();
426 
427               iDelayMS=iDefaultDelayMS;
428             }else{
429               iDelayMS = FrameSkipOrDraw();
430             }
431 
432           }
433 
434           SDL_Delay(iDelayMS);
435         }
436         else
437         {
438           if(bHasFocus){
439             iDelayMS=1000/30; //30 FPS on main menu just to not use too much CPU there. If one day it is animated, lower this properly.
440             SDL_Delay(iDelayMS);
441           }else{
442             SDL_WaitEvent(&Event);DBGLN;
443             ProcessMessage(&Event);DBGLN;
444           }
445         }
446       }
447     }
448 
449   }
450 }
451 
PollEvents(SDL_Event * pEvent)452 uint globalwindowhandler::PollEvents(SDL_Event* pEvent)
453 {
454   if(pEvent==NULL)
455     pEvent=new SDL_Event();
456 
457   uint i=0;
458   while(SDL_PollEvent(pEvent)){
459     ProcessMessage(pEvent);
460     i++;
461   }
462 
463   return i;
464 }
465 
466 v2 v2MousePos;
UpdateMouse()467 uint globalwindowhandler::UpdateMouse()
468 {
469   /**
470    * global didnt fix the wrong mouse position relatively to the visible cursor...
471   if(SDL_GetWindowFlags(graphics::GetWindow()) & SDL_WINDOW_FULLSCREEN_DESKTOP)
472     return SDL_GetGlobalMouseState(&v2MousePos.X,&v2MousePos.Y);
473   else
474    */
475     return SDL_GetMouseState(&v2MousePos.X,&v2MousePos.Y);
476 }
477 
ReadKey()478 int globalwindowhandler::ReadKey()
479 {
480   SDL_Event Event;
481 
482 #if SDL_MAJOR_VERSION == 1
483   if(SDL_GetAppState() & SDL_APPACTIVE)
484 #else
485   if( playInBackground || (SDL_GetWindowFlags(graphics::GetWindow()) & (SDL_WINDOW_MOUSE_FOCUS | SDL_WINDOW_INPUT_FOCUS)) )
486 #endif
487   {
488     PollEvents(&Event);
489   }
490   else
491   {
492     SDL_WaitEvent(&Event);
493     ProcessMessage(&Event);
494   }
495 
496   return KeyBuffer.size() ? GetKey(false) : 0;
497 }
498 
WaitForKeyEvent(uint Key)499 truth globalwindowhandler::WaitForKeyEvent(uint Key)
500 {
501   SDL_Event Event;
502 
503 #if SDL_MAJOR_VERSION == 1
504   if(SDL_GetAppState() & SDL_APPACTIVE)
505 #else
506   if( playInBackground || (SDL_GetWindowFlags(graphics::GetWindow()) & (SDL_WINDOW_MOUSE_FOCUS | SDL_WINDOW_INPUT_FOCUS)) )
507 #endif
508   {
509 #if SDL_MAJOR_VERSION == 2
510     while(SDL_PollEvent(&Event))
511       if(Event.type == Key)
512         return true;
513 #else
514     while(SDL_PollEvent(&Event))
515       if(Event.active.type == Key)
516         return true;
517 #endif
518   }
519   else
520     SDL_WaitEvent(&Event);
521 
522   return false;
523 }
524 
IsLastSDLkeyEventWasKeyUp()525 truth globalwindowhandler::IsLastSDLkeyEventWasKeyUp()
526 {
527   return bLastSDLkeyEventIsKeyUp;
528 }
529 
GetMouseLocation()530 v2 globalwindowhandler::GetMouseLocation()
531 {
532   UpdateMouse();
533   return v2MousePos;
534 }
535 
IsMouseAtRect(v2 v2TopLeft,v2 v2BorderOrBottomRigh,bool b2ndParmIsBorder,v2 v2MousePosOverride)536 bool globalwindowhandler::IsMouseAtRect(v2 v2TopLeft, v2 v2BorderOrBottomRigh, bool b2ndParmIsBorder, v2 v2MousePosOverride)
537 {
538   v2 v2MP = v2MousePosOverride;
539   if(v2MousePosOverride.Is0()){
540     UpdateMouse();
541     v2MP=v2MousePos;
542   }
543 
544   v2 v2BottomRight = v2BorderOrBottomRigh;
545   if(b2ndParmIsBorder)
546     v2BottomRight += v2TopLeft;
547 
548   return
549     v2MP.X > v2TopLeft.X     &&
550     v2MP.Y > v2TopLeft.Y     &&
551     v2MP.X < v2BottomRight.X &&
552     v2MP.Y < v2BottomRight.Y    ;
553 }
554 
555 mouseclick mc;
ConsumeMouseEvent()556 mouseclick globalwindowhandler::ConsumeMouseEvent() //TODO buffer it?
557 {
558   mouseclick mcR;
559   if(mc.btn!=-1 || mc.wheelY!=0)
560     mcR=mc;
561 
562   mc.btn=-1;
563   mc.pos=v2();
564   mc.wheelY=0;
565 
566   return mcR;
567 }
568 
ChkCtrlKey(SDL_Event * Event)569 int globalwindowhandler::ChkCtrlKey(SDL_Event* Event)
570 {
571   if(Event->key.keysym.mod & KMOD_CTRL){ //if CTRL is pressed, user expects something else than the normal key, therefore not permissive
572     if(ControlKeyHandler!=NULL)
573       ControlKeyHandler(Event->key.keysym.sym);
574     return iRestWaitKey; //gum TODO 0 should suffice one day...
575   }DBGLN;
576 
577   return Event->key.keysym.sym;
578 }
579 
ProcessKeyDownMessage(SDL_Event * Event)580 void globalwindowhandler::ProcessKeyDownMessage(SDL_Event* Event)
581 {DBG4(Event->key.keysym.sym,Event->text.text[0],Event->key.keysym.mod & KMOD_ALT,Event->key.keysym.mod & KMOD_CTRL);
582 
583   bLastSDLkeyEventIsKeyUp=false;
584 
585   /**
586    * Events are splitted between SDL_KEYDOWN and SDL_TEXTINPUT.
587    *
588    * All managed events must be explicited,
589    * so, all keyDown events that will be modified must be handled here,
590    * all other non modified keyDown events will be handled by SDL_TEXTINPUT event type outside here.
591    *
592    * More modifiers also means higher priority.
593    *
594    * if one or more modifiers are pressed,
595    * user expects something else than the normal key,
596    * therefore wont fill the key buffer
597    *
598    * Non handled ctrl+alt+... or ctrl+... or alt+... will be ignored.
599    * Tho, they may be overriden by the OS and never reach here...
600    */
601 
602   if((Event->key.keysym.mod & KMOD_CTRL) && (Event->key.keysym.mod & KMOD_ALT)){
603     switch(Event->key.keysym.sym)
604     {
605     case SDLK_e:
606       /**
607        * TODO
608        * exemplify where this is or can be ever used as tests provided no results on Linux,
609        * is it the windows Explorer key? if so #ifdef WIN32 should be used...
610        */
611       AddKeyToBuffer('\177');
612       break;
613     }
614     return;
615   }
616 
617   if(Event->key.keysym.mod & KMOD_CTRL){ //TODO right control key is being ignored on lists for ctrl+f filter on the first try
618     if(ControlKeyHandler!=NULL) //this one was completely externalized
619       ControlKeyHandler(Event->key.keysym.sym);
620     return;
621   }else
622   if(Event->key.keysym.mod & KMOD_ALT){
623     switch(Event->key.keysym.sym)
624     {
625     case SDLK_RETURN:
626     case SDLK_KP_ENTER:
627       graphics::SwitchMode();
628       break;
629     }
630     return;
631   }else
632   if(Event->key.keysym.mod & KMOD_SHIFT){
633     return;
634   }
635 
636   // other special non buffered keys
637   switch(Event->key.keysym.sym)
638   {
639     case SDLK_F1:    case SDLK_F2:    case SDLK_F3:    case SDLK_F4:    case SDLK_F5:
640     case SDLK_F6:    case SDLK_F7:    case SDLK_F8:    case SDLK_F9:    case SDLK_F10:
641     case SDLK_F11:   case SDLK_F12:   case SDLK_F13:   case SDLK_F14:   case SDLK_F15:
642     case SDLK_F16:   case SDLK_F17:   case SDLK_F18:   case SDLK_F19:   case SDLK_F20:
643     case SDLK_F21:   case SDLK_F22:   case SDLK_F23:   case SDLK_F24:
644       if(FunctionKeyHandler!=NULL)
645         FunctionKeyHandler(Event->key.keysym.sym);
646       return; //no buffer
647 
648     case SDLK_SYSREQ:
649     case SDLK_PRINTSCREEN:
650       if(!ScrshotDirectoryName.IsEmpty())
651         DOUBLE_BUFFER->Save(ScrshotNameHandler());
652       return; //no buffer
653   }
654 
655   /////////////////////////////////////////////////////////////////////////////////////////
656   ///////////////////////// MODIFIED KEY BUFFER ///////////////////////////////////////////
657   /////////////////////////////////////////////////////////////////////////////////////////
658   int KeyPressed = 0;
659   switch(Event->key.keysym.sym)
660   {
661     case SDLK_RETURN:
662     case SDLK_KP_ENTER:
663       // ex.: both SDL keys are mixed into KEY_ENTER
664       KeyPressed = KEY_ENTER; //TODO SDL1? old comment tip or deadCode: Event->key.keysym.unicode;
665       break;
666 
667     case SDLK_DOWN:
668     case SDLK_KP_2:
669       KeyPressed = KEY_DOWN + 0xE000;
670       break;
671 
672     case SDLK_UP:
673     case SDLK_KP_8:
674       KeyPressed = KEY_UP + 0xE000;
675       break;
676 
677     case SDLK_RIGHT:
678     case SDLK_KP_6:
679       KeyPressed = KEY_RIGHT + 0xE000;
680       break;
681 
682     case SDLK_LEFT:
683     case SDLK_KP_4:
684       KeyPressed = KEY_LEFT + 0xE000;
685       break;
686 
687     case SDLK_HOME:
688     case SDLK_KP_7:
689       KeyPressed = KEY_HOME + 0xE000;
690       break;
691 
692     case SDLK_END:
693     case SDLK_KP_1:
694       KeyPressed = KEY_END + 0xE000;
695       break;
696     case SDLK_PAGEUP:
697     case SDLK_KP_9:
698       KeyPressed = KEY_PAGE_UP + 0xE000;
699       break;
700 
701     case SDLK_KP_3:
702     case SDLK_PAGEDOWN:
703       KeyPressed = KEY_PAGE_DOWN + 0xE000;
704       break;
705 
706     case SDLK_DELETE:
707       KeyPressed = KEY_DELETE + 0xE000;
708       break;
709 
710     case SDLK_INSERT:
711       KeyPressed = KEY_INSERT + 0xE000;
712       break;
713 
714     case SDLK_KP_5:
715     case SDLK_KP_PERIOD:
716       KeyPressed = iRestWaitKey;
717       break;
718 
719 #if SDL_MAJOR_VERSION == 2
720     default:
721       KeyPressed = Event->key.keysym.sym;
722       if(!KeyPressed)
723         return;
724 #endif
725 
726 //TODO SDL1 still compiles? anyone uses it yet??? the same question about DJGPP...
727 #if SDL_MAJOR_VERSION == 1
728    default:
729     KeyPressed = Event->key.keysym.unicode;
730 
731     if(!KeyPressed)
732       return;
733 #endif
734   }
735   AddKeyToBuffer(KeyPressed);
736 }
737 
738 /**
739  * buffer of yet non processed commands/textInput
740  */
AddKeyToBuffer(int KeyPressed)741 void globalwindowhandler::AddKeyToBuffer(int KeyPressed)
742 { DBG1(KeyPressed);
743   if(KeyPressed==0)return;
744 
745   if( std::find(KeyBuffer.begin(), KeyBuffer.end(), KeyPressed) == KeyBuffer.end() ) //prevent dups TODO because of fast key-repeat OS feature? should be the last key on buffer only then
746     KeyBuffer.push_back(KeyPressed);
747 }
748 
ProcessMessage(SDL_Event * Event)749 void globalwindowhandler::ProcessMessage(SDL_Event* Event)
750 {
751   Uint32 type;
752 #if SDL_MAJOR_VERSION == 1
753   type=(Event->active.type);
754 #else
755   type=(Event->type);
756 #endif
757 
758   switch(type)
759   {
760 
761 #if SDL_MAJOR_VERSION == 1
762    case SDL_VIDEOEXPOSE:
763     graphics::BlitDBToScreen();
764 #else
765    case SDL_WINDOWEVENT:
766     switch(Event->window.event)
767     {
768      case SDL_WINDOWEVENT_SHOWN:
769      case SDL_WINDOWEVENT_RESIZED:
770      case SDL_WINDOWEVENT_RESTORED:
771       graphics::BlitDBToScreen();
772       break;
773     }
774 #endif
775     break;
776 
777    case SDL_QUIT:
778     if(!QuitMessageHandler || QuitMessageHandler())
779       exit(0);
780     return;
781 
782    case SDL_MOUSEBUTTONUP:
783      if(Event->button.button==1 && Event->button.clicks>0){
784        mc.btn = 1;
785        mc.pos.X=Event->button.x;
786        mc.pos.Y=Event->button.y;
787      }
788      break;
789 
790    case SDL_MOUSEWHEEL:
791      mc.wheelY = Event->wheel.y;
792      break;
793 
794 #if SDL_MAJOR_VERSION == 2 //BEFORE key up or down
795    case SDL_TEXTINPUT: DBG2(Event->key.keysym.sym,Event->text.text[0]);
796      AddKeyToBuffer(Event->text.text[0]);
797      break;
798 #endif
799 
800    case SDL_KEYUP: DBGLN;
801      bLastSDLkeyEventIsKeyUp=true;
802      break;
803 
804    case SDL_KEYDOWN: DBGLN;
805      ProcessKeyDownMessage(Event);
806      break;
807   }
808 
809 }
810 
811 // returns true if shift is being pressed
812 // else false
ShiftIsDown()813 truth globalwindowhandler::ShiftIsDown()
814 {
815   return false;
816 }
817 
818 // returns filename to be used for screenshot
ScrshotNameHandler()819 festring globalwindowhandler::ScrshotNameHandler()
820 {
821   static int ScrshotCount = 0;
822 
823   festring ScrshotNum;
824   if (ScrshotCount < 10) // prepend 0s so that files are properly sorted in browser (up to 999 at least).
825     ScrshotNum << "00" << ScrshotCount;
826   else if (ScrshotCount < 100)
827     ScrshotNum << "0" << ScrshotCount;
828   else
829     ScrshotNum << ScrshotCount;
830 
831   festring ScrshotName;
832   ScrshotName << ScrshotDirectoryName << "Scrshot" << ScrshotNum << ".bmp";
833 
834   FILE* Scrshot = fopen(ScrshotName.CStr(), "r");
835 
836   if (Scrshot)
837   {
838     // file exists; close file and increment ScrshotCount
839     fclose(Scrshot);
840     ++ScrshotCount;
841     return ScrshotNameHandler();
842   }
843 
844   // if file doesn't exist; we can use this filename
845   return ScrshotName;
846 }
847 
848 #endif /* USE_SDL */
849