ecere: Fixes to support MinGW-w64
[sdk] / ecere / src / gui / drivers / Win32ConsoleInterface.ec
1 namespace gui::drivers;
2
3 import "instance"
4
5 #if defined(__WIN32__)
6
7 #define WIN32_LEAN_AND_MEAN
8 #define Method _Method
9 #define String _String
10 #include <windows.h>
11 #include <mmsystem.h>
12
13 #undef Method
14 #undef String
15
16 import "Display"
17
18 default:
19 WINBASEAPI HWND WINAPI GetConsoleWindow (); 
20
21 private:
22
23 static HANDLE hStdin, hStdout, hInactive;
24 static byte keys[256];
25 static Point mousePosition;
26 static Box mouseRange;
27
28 default:
29 extern int __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnKeyHit;
30 extern int __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnKeyDown;
31 extern int __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnKeyUp;
32
33 extern int __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnMouseMove;
34 extern int __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnLeftButtonDown;
35 extern int __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnRightButtonDown;
36 extern int __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnMiddleButtonDown;
37 extern int __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnLeftDoubleClick;
38 extern int __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnRightDoubleClick;
39 extern int __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnMiddleDoubleClick;
40 extern int __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnLeftButtonUp;
41 extern int __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnRightButtonUp;
42 extern int __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnMiddleButtonUp;
43
44 private:
45
46 /****************************************************************************
47    /// DRIVER IMPLEMENTATION /////////////
48 ****************************************************************************/
49
50 class Win32ConsoleInterface : Interface
51 {
52    class_property(name) = "Win32Console";
53
54    // --- User Interface System ---
55    bool Initialize()
56    {
57       CONSOLE_CURSOR_INFO cursor;
58
59       // FreeConsole();
60       AllocConsole();
61       {
62          WINDOWPLACEMENT placement = { 0 };
63
64          placement.length = sizeof(WINDOWPLACEMENT);
65          placement.showCmd = SW_NORMAL;
66          placement.rcNormalPosition.top = 10;
67          placement.rcNormalPosition.left = 10;
68          placement.rcNormalPosition.right = 810;
69          placement.rcNormalPosition.bottom = 610;
70          SetWindowPlacement(GetConsoleWindow(), &placement);
71          ShowWindow(GetConsoleWindow(), SW_SHOW);
72          SetForegroundWindow(GetConsoleWindow());
73       }
74
75       hStdin = GetStdHandle(STD_INPUT_HANDLE);
76       SetConsoleMode(hStdin, ENABLE_WINDOW_INPUT | ENABLE_MOUSE_INPUT);
77       hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
78       //SetConsoleMode(hStdout, 0);
79       FillBytes(keys, 0, sizeof(keys));
80
81       SetConsoleTitle(guiApp.desktop.text ? guiApp.desktop.text : "");
82       cursor.bVisible = FALSE;
83       cursor.dwSize = 100;
84       SetConsoleCursorInfo(hStdout, &cursor);
85       SetTimer(null, 0, (uint)(1000.0 / 18.2), null);
86
87         return true;
88    }
89
90    void Terminate()
91    {
92       CONSOLE_CURSOR_INFO cursor;
93       SetConsoleMode(hStdout, ENABLE_PROCESSED_OUTPUT);
94       cursor.bVisible = TRUE;
95       cursor.dwSize = 100;
96       SetConsoleCursorInfo(hStdout, &cursor);
97       DumpErrors(true);
98
99       // ShowWindow(GetConsoleWindow(), SW_HIDE);
100       /*
101       FreeConsole();
102       if(AllocConsole())
103       */
104       {
105          // SetForegroundWindow(GetActiveWindow());
106          WINDOWPLACEMENT placement = { 0 };
107          placement.length = sizeof(WINDOWPLACEMENT);
108          placement.showCmd = SW_HIDE;
109          SetWindowPlacement(GetConsoleWindow(), &placement);
110       }
111    }
112
113    bool ProcessInput(bool processAll)
114    {
115       int numInput, c;
116       GetNumberOfConsoleInputEvents(hStdin, &numInput);
117       if(numInput)
118       {
119          for(c = 0; c<numInput; c++)
120          {
121             INPUT_RECORD event;
122             int readInputs;
123             ReadConsoleInput(hStdin, &event, 1, &readInputs);
124             switch(event.EventType)
125             {
126                case KEY_EVENT:
127                {
128                   byte key = (byte)event.Event.KeyEvent.wVirtualScanCode;
129                   byte ch = event.Event.KeyEvent.uChar.AsciiChar;
130                   Key keyFlags;
131
132                   if(event.Event.KeyEvent.dwControlKeyState & ENHANCED_KEY)
133                      key = (byte)GetExtendedKey(key);
134
135                   keyFlags = key;
136                   if(event.Event.KeyEvent.dwControlKeyState&SHIFT_PRESSED)
137                      keyFlags.shift = true;
138                   if(event.Event.KeyEvent.dwControlKeyState&LEFT_ALT_PRESSED ||
139                      event.Event.KeyEvent.dwControlKeyState&RIGHT_ALT_PRESSED)
140                      keyFlags.alt = true;
141                   if(event.Event.KeyEvent.dwControlKeyState&LEFT_CTRL_PRESSED ||
142                      event.Event.KeyEvent.dwControlKeyState&RIGHT_CTRL_PRESSED)
143                      keyFlags.ctrl = true;
144
145                   if(event.Event.KeyEvent.bKeyDown)
146                   {
147                      if(keys[key])
148                         guiApp.desktop.KeyMessage(__ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnKeyHit,keyFlags,ch);
149                      else
150                      {
151                         keys[key] = (byte)bool::true;
152                         guiApp.desktop.KeyMessage(__ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnKeyDown,keyFlags,ch);
153                      }
154                   }
155                   else
156                   {
157                      keys[key] = (byte)bool::false;   
158                      guiApp.desktop.KeyMessage(__ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnKeyUp,keyFlags,ch);
159                   }
160                   break;
161                }
162                case MOUSE_EVENT:
163                {
164                   Modifiers keyFlags = 0;
165                   static MouseButtons lastButtonState = 0;
166                   MouseButtons buttonState = event.Event.MouseEvent.dwButtonState;
167
168                   if(event.Event.MouseEvent.dwControlKeyState&SHIFT_PRESSED)
169                      keyFlags.shift = true;
170                   if(event.Event.MouseEvent.dwControlKeyState&LEFT_ALT_PRESSED ||
171                      event.Event.MouseEvent.dwControlKeyState&RIGHT_ALT_PRESSED)
172                      keyFlags.alt = true;
173                   if(event.Event.MouseEvent.dwControlKeyState&LEFT_CTRL_PRESSED ||
174                      event.Event.MouseEvent.dwControlKeyState&RIGHT_CTRL_PRESSED)
175                      keyFlags.ctrl = true;
176
177                   switch(event.Event.MouseEvent.dwEventFlags)
178                   {
179                      case MOUSE_MOVED:
180                      {
181                         int x = event.Event.MouseEvent.dwMousePosition.X * textCellW;
182                         int y = event.Event.MouseEvent.dwMousePosition.Y * textCellH;
183
184                         x = Min(Max(x, mouseRange.left), mouseRange.right);
185                         y = Min(Max(y, mouseRange.top), mouseRange.bottom);
186
187                         if(x != mousePosition.x || y != mousePosition.y)
188                         {
189                            mousePosition.x = x;
190                            mousePosition.y = y;
191                            guiApp.desktop.MouseMessage(__ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnMouseMove, x, y, &keyFlags, false, false);
192                         }
193                         break;
194                      }
195                      case DOUBLE_CLICK:
196                         if(buttonState.left && !(lastButtonState.left))
197                         {
198                            if(!guiApp.desktop.MouseMessage(__ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnLeftDoubleClick,
199                               mousePosition.x, mousePosition.y, &keyFlags, false, true))
200                               break;
201                         }
202                         else if(buttonState.middle && !(lastButtonState.middle))
203                         {
204                            if(!guiApp.desktop.MouseMessage(__ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnMiddleDoubleClick,
205                               mousePosition.x, mousePosition.y, &keyFlags, false, true))
206                               break;
207                         }
208                         else if(buttonState.right && !(lastButtonState.right))
209                         {
210                            if(!guiApp.desktop.MouseMessage(__ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnRightDoubleClick,
211                               mousePosition.x, mousePosition.y, &keyFlags, false, true))
212                               break;
213                         }
214                      default:
215                         if(buttonState.left && !(lastButtonState.left))
216                            guiApp.desktop.MouseMessage(__ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnLeftButtonDown,
217                               mousePosition.x, mousePosition.y, &keyFlags, false, 
218                               (event.Event.MouseEvent.dwEventFlags == DOUBLE_CLICK) ? false : true) ;
219                         else if(buttonState.middle && !(lastButtonState.middle))
220                            guiApp.desktop.MouseMessage(__ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnMiddleButtonDown,
221                               mousePosition.x, mousePosition.y, &keyFlags, false,
222                               (event.Event.MouseEvent.dwEventFlags == DOUBLE_CLICK) ? false : true);
223                         else if(buttonState.right && !(lastButtonState.right))
224                            guiApp.desktop.MouseMessage(__ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnRightButtonDown,
225                               mousePosition.x, mousePosition.y, &keyFlags, false,
226                               (event.Event.MouseEvent.dwEventFlags == DOUBLE_CLICK) ? false : true);
227                         else if(!(buttonState.left) && lastButtonState.left)
228                            guiApp.desktop.MouseMessage(__ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnLeftButtonUp,
229                               mousePosition.x, mousePosition.y, &keyFlags, false, false);
230                         else if(!(buttonState.middle) && lastButtonState.middle)
231                            guiApp.desktop.MouseMessage(__ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnMiddleButtonUp,
232                               mousePosition.x, mousePosition.y, &keyFlags, false, false);
233                         else if(!(buttonState.right) && lastButtonState.right)
234                            guiApp.desktop.MouseMessage(__ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnRightButtonUp,
235                               mousePosition.x, mousePosition.y, &keyFlags, false, false);
236                   }
237                   lastButtonState = buttonState;
238                   break;
239                }
240                case WINDOW_BUFFER_SIZE_EVENT:
241                {
242                   COORD coord = 
243                   { 
244                      event.Event.WindowBufferSizeEvent.dwSize.X,
245                      event.Event.WindowBufferSizeEvent.dwSize.Y
246                   };
247                   SetConsoleScreenBufferSize(hStdout,coord);
248                   guiApp.SetDesktopPosition(0,0, coord.X * textCellW, coord.Y * textCellH, true);
249                   break;
250                }
251             }
252
253             if(!processAll) break;
254          }
255          return true;
256       }
257       return false;
258    }
259
260    void Wait()
261    {
262       void * objects[2] = { hStdin, *((uint **)guiApp.semaphore) };
263       if(MsgWaitForMultipleObjects(2, objects, FALSE, INFINITE, QS_TIMER) == WAIT_OBJECT_0 + 2)
264       {
265          MSG msg;
266          GetMessage(&msg, null,0,0);
267       }
268    }
269
270    void Lock(Window window)
271    {
272
273    }
274
275    void Unlock(Window window)
276    {
277
278    }
279
280    char ** GraphicsDrivers(int * numDrivers)
281    {
282       static char *graphicsDrivers[] = { "Win32Console" };
283       *numDrivers = sizeof(graphicsDrivers) / sizeof(char *);
284       return (char **)graphicsDrivers;
285    }
286
287    void GetCurrentMode(bool * fullScreen, Resolution * resolution, PixelFormat * colorDepth, int * refreshRate)
288    {
289       *fullScreen = true;
290       *colorDepth = pixelFormatText;
291    }
292
293    void EnsureFullScreen(bool *fullScreen)
294    {
295       *fullScreen = true;
296    }
297
298    bool ScreenMode(bool fullScreen, Resolution resolution, PixelFormat colorDepth, int refreshRate, bool * textMode)
299    {
300       if(fullScreen)
301       {
302          CONSOLE_SCREEN_BUFFER_INFO info;
303
304          ChangeDisplaySettings(null, 0);
305
306          if(GetConsoleScreenBufferInfo(hStdout, &info))
307          {
308             COORD coord;
309             coord.X = info.srWindow.Right+1;
310             coord.Y = info.srWindow.Bottom+1;
311             SetConsoleScreenBufferSize(hStdout,coord);
312             guiApp.SetDesktopPosition(0,0, coord.X * textCellW, coord.Y * textCellH, false);
313             *textMode = true;
314             mouseRange.right = MAXINT;
315             mouseRange.bottom = MAXINT;
316               return true;
317          }
318       }
319       return false;
320    }
321
322    // --- Window Creation ---
323    void * CreateRootWindow(Window window)
324    {
325       return (void *) hStdout;
326    }
327
328    void DestroyRootWindow(void * windowHandle)
329    {
330    }
331
332    // -- Window manipulation ---
333
334    void SetRootWindowCaption(void * windowHandle, char * name)
335    {
336       if(windowHandle == guiApp.desktop)
337          SetConsoleTitle(name);
338    }
339
340    void PositionRootWindow(void * windowHandle, int x, int y, int w, int h, bool move, bool resize)
341    {
342    }
343
344    void OrderRootWindow(void * windowHandle, bool topMost)
345    {
346    }
347
348    void SetRootWindowColor(Window window)
349    {
350    }
351
352    void OffsetWindow(void * windowHandle, int * x, int * y)
353    {
354
355    }
356
357    void UpdateRootWindow(void * windowHandle)
358    {
359    }
360
361    void SetRootWindowState(void * windowHandle, int state, bool visible)
362    {
363    }
364
365    void ActivateRootWindow(void * windowHandle)
366    {
367    }
368
369    // --- Mouse-based window movement ---
370
371    void StartMoving(void * windowHandle, int x, int y, bool fromKeyBoard)
372    {
373    }
374
375    void StopMoving(void * windowHandle)
376    {
377    }
378
379    // -- Mouse manipulation ---
380
381    void GetMousePosition(int *x, int *y)
382    {
383       *x = mousePosition.x;
384       *y = mousePosition.y;
385    }
386
387    void SetMousePosition(int x, int y)
388    {
389       mousePosition.x = x;
390       mousePosition.y = y;
391    }
392
393    void SetMouseRange(Window window, Box box)
394    {
395       if(box != null)
396       {
397          mouseRange = box;
398       }
399       else
400       {
401          mouseRange.left = mouseRange.top = 0;
402          mouseRange.right = mouseRange.bottom = MAXINT;
403       }
404    }
405
406    void SetMouseCapture(void * windowHandle)
407    {
408
409    }
410
411    // -- Mouse cursor ---
412
413    void SetMouseCursor(int cursor)
414    {
415
416    }
417
418    // --- Caret ---
419
420    void SetCaret(int x, int y, int size)
421    {
422       COORD coords = { (short)(x / textCellW), (short)(y / textCellH) };
423       CONSOLE_CURSOR_INFO cursor = 
424       { 
425          size ? size : 99, 
426          (size && x >= 0 && y >= 0 && x < guiApp.desktop.clientSize.w && y < guiApp.desktop.clientSize.h) ? TRUE : FALSE
427       };
428       SetConsoleCursorInfo(hStdout, &cursor);
429       SetConsoleCursorPosition(hStdout, coords);
430    }  
431
432    // --- Clipboard manipulation ---
433
434    void ClearClipboard()
435    {
436         if(OpenClipboard(null))
437         {
438          EmptyClipboard();
439            CloseClipboard();
440       }
441    }
442
443    bool AllocateClipboard(ClipBoard clipBoard, uint size)
444    {
445       bool result = false;
446       clipBoard.handle=GlobalAlloc(GHND | GMEM_DDESHARE, size);
447       if(clipBoard.handle)
448       {
449          clipBoard.text=GlobalLock(clipBoard.handle);
450          if(clipBoard.text)
451             result = true;
452          else
453             GlobalFree(clipBoard.handle);
454       }
455       return result;
456    }
457
458    bool SaveClipboard(ClipBoard clipBoard)
459    {
460       bool status = false;
461       if(clipBoard.handle)
462       {
463          GlobalUnlock(clipBoard.handle);
464            if(OpenClipboard(null))
465            {
466             EmptyClipboard();
467               if(SetClipboardData(CF_TEXT,clipBoard.handle))
468             {
469                  CloseClipboard();
470                status = true;
471             }
472          }
473          if(!status)
474             GlobalFree(clipBoard.handle);
475       }
476       return status;
477    }
478
479    bool LoadClipboard(ClipBoard clipBoard)
480    {
481       bool result = false;
482         if(OpenClipboard(null))
483         {
484          if(clipBoard.handle = GetClipboardData(CF_TEXT))
485          {
486             if(clipBoard.text = GlobalLock(clipBoard.handle))
487                result = true;
488          }
489          CloseClipboard();
490       }
491       return result;
492    }
493
494    void UnloadClipboard(ClipBoard clipBoard)
495    {
496       if(clipBoard.handle)
497          GlobalUnlock(clipBoard.handle);
498    }
499
500    // --- State based input ---
501
502    bool AcquireInput(void * windowHandle, bool state)
503    {
504       return false;
505    }
506
507    bool GetMouseState(MouseButtons * buttons, int * x, int * y)
508    {
509       bool result = false;
510
511       return result;
512    }
513
514    bool GetJoystickState(int device, Joystick joystick)
515    {
516       bool result = false;
517
518       return result;
519    }
520
521    bool GetKeyState(Key key)
522    {
523       if(key < 256)
524          return keys[key];
525       else if(key == capsState)
526          return GetKeyState(VK_CAPITAL) & 0x00000001;
527       else if(key == numState)
528          return GetKeyState(VK_NUMLOCK) & 0x00000001;
529       else if(key == scrollState)
530          return GetKeyState(VK_SCROLL) & 0x00000001;
531       return 0;
532    }
533 };
534
535 #endif