6de07a21e194699b8cfbe5a8fe13c9c80e3c6b7f
[freeglut] / src / mswin / fg_main_mswin.c
1 /*
2  * freeglut_main_mswin.c
3  *
4  * The Windows-specific mouse cursor related stuff.
5  *
6  * Copyright (c) 2012 Stephen J. Baker. All Rights Reserved.
7  * Written by John F. Fay, <fayjf@sourceforge.net>
8  * Creation date: Sat Jan 21, 2012
9  *
10  * Permission is hereby granted, free of charge, to any person obtaining a
11  * copy of this software and associated documentation files (the "Software"),
12  * to deal in the Software without restriction, including without limitation
13  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
14  * and/or sell copies of the Software, and to permit persons to whom the
15  * Software is furnished to do so, subject to the following conditions:
16  *
17  * The above copyright notice and this permission notice shall be included
18  * in all copies or substantial portions of the Software.
19  *
20  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
21  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
23  * PAWEL W. OLSZTA BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
24  * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
25  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
26  */
27
28 #include <GL/freeglut.h>
29 #include "../fg_internal.h"
30
31
32 extern void fghRedrawWindow ( SFG_Window *window );
33
34 extern void fgNewWGLCreateContext( SFG_Window* window );
35 extern GLboolean fgSetupPixelFormat( SFG_Window* window, GLboolean checkOnly,
36                                      unsigned char layer_type );
37
38 extern void fgPlatformCheckMenuDeactivate();
39
40 #ifdef WM_TOUCH
41 typedef BOOL (WINAPI *pGetTouchInputInfo)(HTOUCHINPUT,UINT,PTOUCHINPUT,int);
42 typedef BOOL (WINAPI *pCloseTouchInputHandle)(HTOUCHINPUT);
43 static pGetTouchInputInfo fghGetTouchInputInfo = (pGetTouchInputInfo)0xDEADBEEF;
44 static pCloseTouchInputHandle fghCloseTouchInputHandle = (pCloseTouchInputHandle)0xDEADBEEF;
45 #endif
46
47 #ifdef _WIN32_WCE
48 typedef struct GXDisplayProperties GXDisplayProperties;
49 typedef struct GXKeyList GXKeyList;
50 #include <gx.h>
51
52 typedef struct GXKeyList (*GXGETDEFAULTKEYS)(int);
53 typedef int (*GXOPENINPUT)();
54
55 GXGETDEFAULTKEYS GXGetDefaultKeys_ = NULL;
56 GXOPENINPUT GXOpenInput_ = NULL;
57
58 struct GXKeyList gxKeyList;
59 #endif /* _WIN32_WCE */
60
61
62 /* Get system time, taking special precautions against 32bit timer wrap.
63    We use timeGetTime and not GetTickCount because of its better stability,
64    and because we can increase its granularity (to 1 ms in
65    fgPlatformInitialize). For that reason we can't use GetTickCount64 which
66    wouldn't have the wrap issue.
67    Credit: this is based on code in glibc (https://mail.gnome.org/archives/commits-list/2011-November/msg04588.html)
68    */
69 static fg_time_t lastTime32 = 0;
70 static fg_time_t timeEpoch = 0;
71 void fgPlatformInitSystemTime()
72 {
73 #if defined(_WIN32_WCE)
74     lastTime32 = GetTickCount();
75 #else
76     lastTime32 = timeGetTime();
77 #endif
78 }
79 fg_time_t fgPlatformSystemTime ( void )
80 {
81     fg_time_t currTime32;
82 #if defined(_WIN32_WCE)
83     currTime32 = GetTickCount();
84 #else
85     currTime32 = timeGetTime();
86 #endif
87     /* Check if we just wrapped */
88     if (currTime32 < lastTime32)
89         timeEpoch++;
90     
91     lastTime32 = currTime32;
92
93     return currTime32 | timeEpoch << 32;
94 }
95
96
97 void fgPlatformSleepForEvents( fg_time_t msec )
98 {
99     MsgWaitForMultipleObjects( 0, NULL, FALSE, (DWORD) msec, QS_ALLINPUT );
100 }
101
102
103 void fgPlatformProcessSingleEvent ( void )
104 {
105     MSG stMsg;
106
107     FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutMainLoopEvent" );
108
109     while( PeekMessage( &stMsg, NULL, 0, 0, PM_NOREMOVE ) )
110     {
111         if( GetMessage( &stMsg, NULL, 0, 0 ) == 0 )
112         {
113             if( fgState.ActionOnWindowClose == GLUT_ACTION_EXIT )
114             {
115                 fgDeinitialize( );
116                 exit( 0 );
117             }
118             else if( fgState.ActionOnWindowClose == GLUT_ACTION_GLUTMAINLOOP_RETURNS )
119                 fgState.ExecState = GLUT_EXEC_STATE_STOP;
120
121             return;
122         }
123
124         TranslateMessage( &stMsg );
125         DispatchMessage( &stMsg );
126     }
127 }
128
129
130
131 void fgPlatformMainLoopPreliminaryWork ( void )
132 {
133     SFG_Window *window = (SFG_Window *)fgStructure.Windows.First ;
134
135     /*
136      * Processing before the main loop:  If there is a window which is open and
137      * which has a visibility callback, call it.  I know this is an ugly hack,
138      * but I'm not sure what else to do about it.  Ideally we should leave
139      * something uninitialized in the create window code and initialize it in
140      * the main loop, and have that initialization create a "WM_ACTIVATE"
141      * message.  Then we would put the visibility callback code in the
142      * "case WM_ACTIVATE" block below.         - John Fay -- 10/24/02
143      */
144     while( window )
145     {
146         if ( FETCH_WCB( *window, Visibility ) )
147         {
148             SFG_Window *current_window = fgStructure.CurrentWindow ;
149
150             INVOKE_WCB( *window, Visibility, ( window->State.Visible ) );
151             fgSetWindow( current_window );
152         }
153
154         window = (SFG_Window *)window->Node.Next ;
155     }
156 }
157
158
159 /*
160  * Determine a GLUT modifier mask based on MS-WINDOWS system info.
161  */
162 static int fgPlatformGetModifiers (void)
163 {
164     return
165         ( ( ( GetKeyState( VK_LSHIFT   ) < 0 ) ||
166             ( GetKeyState( VK_RSHIFT   ) < 0 )) ? GLUT_ACTIVE_SHIFT : 0 ) |
167         ( ( ( GetKeyState( VK_LCONTROL ) < 0 ) ||
168             ( GetKeyState( VK_RCONTROL ) < 0 )) ? GLUT_ACTIVE_CTRL  : 0 ) |
169         ( ( ( GetKeyState( VK_LMENU    ) < 0 ) ||
170             ( GetKeyState( VK_RMENU    ) < 0 )) ? GLUT_ACTIVE_ALT   : 0 );
171 }
172
173 static LRESULT fghKeyPress(SFG_Window *window, UINT uMsg, GLboolean keydown, WPARAM wParam, LPARAM lParam)
174 {
175     static unsigned char lControl = 0, lShift = 0, lAlt = 0,
176                          rControl = 0, rShift = 0, rAlt = 0;
177
178     int keypress = -1;
179     POINT mouse_pos ;
180     
181     /* if keydown, check for repeat */
182     if( keydown && ( fgState.KeyRepeat==GLUT_KEY_REPEAT_OFF || window->State.IgnoreKeyRepeat==GL_TRUE ) && (HIWORD(lParam) & KF_REPEAT) )
183         return 1;
184     
185     /* Remember the current modifiers state so user can query it from their callback */
186     fgState.Modifiers = fgPlatformGetModifiers( );
187
188     /* Get mouse position roughly at time of keypress */
189     GetCursorPos( &mouse_pos );
190     ScreenToClient( window->Window.Handle, &mouse_pos );
191     window->State.MouseX = mouse_pos.x;
192     window->State.MouseY = mouse_pos.y;
193
194     /* Convert the Win32 keystroke codes to GLUTtish way */
195 #   define KEY(a,b) case a: keypress = b; break;
196
197     switch( wParam )
198     {
199         KEY( VK_F1,     GLUT_KEY_F1        );
200         KEY( VK_F2,     GLUT_KEY_F2        );
201         KEY( VK_F3,     GLUT_KEY_F3        );
202         KEY( VK_F4,     GLUT_KEY_F4        );
203         KEY( VK_F5,     GLUT_KEY_F5        );
204         KEY( VK_F6,     GLUT_KEY_F6        );
205         KEY( VK_F7,     GLUT_KEY_F7        );
206         KEY( VK_F8,     GLUT_KEY_F8        );
207         KEY( VK_F9,     GLUT_KEY_F9        );
208         KEY( VK_F10,    GLUT_KEY_F10       );
209         KEY( VK_F11,    GLUT_KEY_F11       );
210         KEY( VK_F12,    GLUT_KEY_F12       );
211         KEY( VK_PRIOR,  GLUT_KEY_PAGE_UP   );
212         KEY( VK_NEXT,   GLUT_KEY_PAGE_DOWN );
213         KEY( VK_HOME,   GLUT_KEY_HOME      );
214         KEY( VK_END,    GLUT_KEY_END       );
215         KEY( VK_LEFT,   GLUT_KEY_LEFT      );
216         KEY( VK_UP,     GLUT_KEY_UP        );
217         KEY( VK_RIGHT,  GLUT_KEY_RIGHT     );
218         KEY( VK_DOWN,   GLUT_KEY_DOWN      );
219         KEY( VK_INSERT, GLUT_KEY_INSERT    );
220
221     /* handle control, alt and shift. For GLUT, we want to distinguish between left and right presses.
222      * The VK_L* & VK_R* left and right Alt, Ctrl and Shift virtual keys are however only used as parameters to GetAsyncKeyState() and GetKeyState()
223      * so when we get an alt, shift or control keypress here, we manually check whether it was the left or the right
224      */
225 #define ASYNC_KEY_EVENT(winKey,glutKey,keyStateVar)\
226     if (!keyStateVar && GetAsyncKeyState ( winKey ))\
227     {\
228         keypress   = glutKey;\
229         keyStateVar = 1;\
230     }\
231     else if (keyStateVar && !GetAsyncKeyState ( winKey ))\
232     {\
233         keypress   = glutKey;\
234         keyStateVar = 0;\
235     }
236     case VK_CONTROL:
237         ASYNC_KEY_EVENT(VK_LCONTROL,GLUT_KEY_CTRL_L,lControl);
238         ASYNC_KEY_EVENT(VK_RCONTROL,GLUT_KEY_CTRL_R,rControl);
239         break;
240     case VK_SHIFT:
241         ASYNC_KEY_EVENT(VK_LSHIFT,GLUT_KEY_SHIFT_L,lShift);
242         ASYNC_KEY_EVENT(VK_RSHIFT,GLUT_KEY_SHIFT_R,rShift);
243         break;
244     case VK_MENU:
245         ASYNC_KEY_EVENT(VK_LMENU,GLUT_KEY_ALT_L,lAlt);
246         ASYNC_KEY_EVENT(VK_RMENU,GLUT_KEY_ALT_R,rAlt);
247         break;
248 #undef ASYNC_KEY_EVENT
249
250     case VK_DELETE:
251         /* The delete key should be treated as an ASCII keypress: */
252         if (keydown)
253             INVOKE_WCB( *window, Keyboard,
254                         ( 127, window->State.MouseX, window->State.MouseY )
255             );
256         else
257             INVOKE_WCB( *window, KeyboardUp,
258                         ( 127, window->State.MouseX, window->State.MouseY )
259             );
260         break;
261
262 #if !defined(_WIN32_WCE)
263     default:
264         /* keydown displayable characters are handled with WM_CHAR message, but no corresponding up is generated. So get that here. */
265         if (!keydown)
266         {
267             BYTE state[ 256 ];
268             WORD code[ 2 ];
269
270             GetKeyboardState( state );
271
272             if( ToAscii( (UINT)wParam, 0, state, code, 0 ) == 1 )
273                 wParam=code[ 0 ];
274
275             INVOKE_WCB( *window, KeyboardUp,
276                    ( (char)wParam,
277                         window->State.MouseX, window->State.MouseY )
278             );
279         }
280 #endif
281     }
282
283 #if defined(_WIN32_WCE)
284     if(keydown && !(lParam & 0x40000000)) /* Prevent auto-repeat */
285     {
286         if(wParam==(unsigned)gxKeyList.vkRight)
287             keypress = GLUT_KEY_RIGHT;
288         else if(wParam==(unsigned)gxKeyList.vkLeft)
289             keypress = GLUT_KEY_LEFT;
290         else if(wParam==(unsigned)gxKeyList.vkUp)
291             keypress = GLUT_KEY_UP;
292         else if(wParam==(unsigned)gxKeyList.vkDown)
293             keypress = GLUT_KEY_DOWN;
294         else if(wParam==(unsigned)gxKeyList.vkA)
295             keypress = GLUT_KEY_F1;
296         else if(wParam==(unsigned)gxKeyList.vkB)
297             keypress = GLUT_KEY_F2;
298         else if(wParam==(unsigned)gxKeyList.vkC)
299             keypress = GLUT_KEY_F3;
300         else if(wParam==(unsigned)gxKeyList.vkStart)
301             keypress = GLUT_KEY_F4;
302     }
303 #endif
304     
305     if( keypress != -1 )
306         if (keydown)
307             INVOKE_WCB( *window, Special,
308                         ( keypress,
309                             window->State.MouseX, window->State.MouseY )
310             );
311         else
312             INVOKE_WCB( *window, SpecialUp,
313                         ( keypress,
314                             window->State.MouseX, window->State.MouseY )
315             );
316
317     fgState.Modifiers = INVALID_MODIFIERS;
318
319     /* SYSKEY events should be sent to default window proc for system to handle them */
320     if (uMsg==WM_SYSKEYDOWN || uMsg==WM_SYSKEYUP)
321         return DefWindowProc( window->Window.Handle, uMsg, wParam, lParam );
322     else
323         return 1;
324 }
325
326 /*
327  * The window procedure for handling Win32 events
328  */
329 LRESULT CALLBACK fgPlatformWindowProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam )
330 {
331     SFG_Window *window, *child_window = NULL;
332     PAINTSTRUCT ps;
333     LRESULT lRet = 1;
334
335     FREEGLUT_INTERNAL_ERROR_EXIT_IF_NOT_INITIALISED ( "Event Handler" ) ;
336
337     window = fgWindowByHandle( hWnd );
338
339     if ( ( window == NULL ) && ( uMsg != WM_CREATE ) )
340       return DefWindowProc( hWnd, uMsg, wParam, lParam );
341
342     /* printf ( "Window %3d message <%04x> %12d %12d\n", window?window->ID:0,
343              uMsg, wParam, lParam ); */
344
345     /* Some events only sent to main window. Check if the current window that
346      * the mouse is over is a child window. Below when handling some messages,
347      * we make sure that we process callbacks on the child window instead.
348      * This mirrors how GLUT does things.
349      */
350     if (window && window->Children.First)
351     {
352         POINT mouse_pos;
353         SFG_WindowHandleType hwnd;
354         SFG_Window* temp_window;
355
356         GetCursorPos( &mouse_pos );
357         ScreenToClient( window->Window.Handle, &mouse_pos );
358         hwnd = ChildWindowFromPoint(window->Window.Handle, mouse_pos);
359         if (hwnd)   /* can be NULL if mouse outside parent by the time we get here */
360         {
361             temp_window = fgWindowByHandle(hwnd);
362             if (temp_window && temp_window->Parent)    /* Verify we got a child window */
363                 child_window = temp_window;
364         }
365     }
366     
367     switch( uMsg )
368     {
369     case WM_CREATE:
370         /* The window structure is passed as the creation structure parameter... */
371         window = (SFG_Window *) (((LPCREATESTRUCT) lParam)->lpCreateParams);
372         FREEGLUT_INTERNAL_ERROR_EXIT ( ( window != NULL ), "Cannot create window",
373                                        "fgPlatformWindowProc" );
374
375         window->Window.Handle = hWnd;
376         window->Window.pContext.Device = GetDC( hWnd );
377         if( window->IsMenu )
378         {
379             unsigned int current_DisplayMode = fgState.DisplayMode;
380             fgState.DisplayMode = GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH;
381 #if !defined(_WIN32_WCE)
382             fgSetupPixelFormat( window, GL_FALSE, PFD_MAIN_PLANE );
383 #endif
384             fgState.DisplayMode = current_DisplayMode;
385
386             if( fgStructure.MenuContext )
387                 wglMakeCurrent( window->Window.pContext.Device,
388                                 fgStructure.MenuContext->MContext
389                 );
390             else
391             {
392                 fgStructure.MenuContext =
393                     (SFG_MenuContext *)malloc( sizeof(SFG_MenuContext) );
394                 fgStructure.MenuContext->MContext =
395                     wglCreateContext( window->Window.pContext.Device );
396             }
397
398             /* window->Window.Context = wglGetCurrentContext ();   */
399             window->Window.Context = wglCreateContext( window->Window.pContext.Device );
400         }
401         else
402         {
403 #if !defined(_WIN32_WCE)
404             fgSetupPixelFormat( window, GL_FALSE, PFD_MAIN_PLANE );
405 #endif
406
407             if( ! fgState.UseCurrentContext )
408                 window->Window.Context =
409                     wglCreateContext( window->Window.pContext.Device );
410             else
411             {
412                 window->Window.Context = wglGetCurrentContext( );
413                 if( ! window->Window.Context )
414                     window->Window.Context =
415                         wglCreateContext( window->Window.pContext.Device );
416             }
417
418 #if !defined(_WIN32_WCE)
419             fgNewWGLCreateContext( window );
420 #endif
421         }
422
423         window->State.NeedToResize = GL_TRUE;
424         /* if we used CW_USEDEFAULT (thats a negative value) for the size
425          * of the window, query the window now for the size at which it
426          * was created.
427          */
428         if( ( window->State.Width < 0 ) || ( window->State.Height < 0 ) )
429         {
430             SFG_Window *current_window = fgStructure.CurrentWindow;
431
432             fgSetWindow( window );
433             window->State.Width = glutGet( GLUT_WINDOW_WIDTH );
434             window->State.Height = glutGet( GLUT_WINDOW_HEIGHT );
435             fgSetWindow( current_window );
436         }
437
438         ReleaseDC( window->Window.Handle, window->Window.pContext.Device );
439
440 #if defined(_WIN32_WCE)
441         /* Take over button handling */
442         {
443             HINSTANCE dxDllLib=LoadLibrary(_T("gx.dll"));
444             if (dxDllLib)
445             {
446                 GXGetDefaultKeys_=(GXGETDEFAULTKEYS)GetProcAddress(dxDllLib, _T("?GXGetDefaultKeys@@YA?AUGXKeyList@@H@Z"));
447                 GXOpenInput_=(GXOPENINPUT)GetProcAddress(dxDllLib, _T("?GXOpenInput@@YAHXZ"));
448             }
449
450             if(GXOpenInput_)
451                 (*GXOpenInput_)();
452             if(GXGetDefaultKeys_)
453                 gxKeyList = (*GXGetDefaultKeys_)(GX_LANDSCAPEKEYS);
454         }
455
456 #endif /* defined(_WIN32_WCE) */
457         break;
458
459     case WM_SIZE:
460         /*
461          * If the window is visible, then it is the user manually resizing it.
462          * If it is not, then it is the system sending us a dummy resize with
463          * zero dimensions on a "glutIconifyWindow" call.
464          */
465         if( window->State.Visible )
466         {
467             /* get old values first to compare to below */
468             int width = window->State.Width, height=window->State.Height;
469 #if defined(_WIN32_WCE)
470             window->State.Width  = HIWORD(lParam);
471             window->State.Height = LOWORD(lParam);
472 #else
473             window->State.Width  = LOWORD(lParam);
474             window->State.Height = HIWORD(lParam);
475 #endif /* defined(_WIN32_WCE) */
476             
477             if (width!=window->State.Width || height!=window->State.Height)
478                 /* Something changed, need to resize */
479                 window->State.NeedToResize = GL_TRUE;
480         }
481
482         break;
483
484     case WM_MOVE:
485         {
486             SFG_Window* saved_window = fgStructure.CurrentWindow;
487             RECT windowRect;
488             GetWindowRect( window->Window.Handle, &windowRect );
489             
490             if (window->Parent)
491             {
492                 /* For child window, we should return relative to upper-left
493                 * of parent's client area.
494                 */
495                 POINT topleft = {windowRect.left,windowRect.top};
496
497                 ScreenToClient(window->Parent->Window.Handle,&topleft);
498                 windowRect.left = topleft.x;
499                 windowRect.top  = topleft.y;
500             }
501
502             INVOKE_WCB( *window, Position, ( windowRect.left, windowRect.top ) );
503             fgSetWindow(saved_window);
504         }
505         break;
506
507     case WM_SETFOCUS:
508 /*        printf("WM_SETFOCUS: %p\n", window ); */
509
510         lRet = DefWindowProc( hWnd, uMsg, wParam, lParam );
511
512         if (child_window)
513         {
514             /* If we're dealing with a child window, make sure it has input focus instead, set it here. */
515             SetFocus(child_window->Window.Handle);
516             SetActiveWindow( child_window->Window.Handle );
517             INVOKE_WCB( *child_window, Entry, ( GLUT_ENTERED ) );
518             UpdateWindow ( child_window->Window.Handle );
519         }
520         else
521         {
522             SetActiveWindow( window->Window.Handle );
523             INVOKE_WCB( *window, Entry, ( GLUT_ENTERED ) );
524         }
525         /* Always request update on main window to be safe */
526         UpdateWindow ( hWnd );
527
528         break;
529
530     case WM_KILLFOCUS:
531         {
532             SFG_Window* saved_window = fgStructure.CurrentWindow;
533 /*            printf("WM_KILLFOCUS: %p\n", window ); */
534             lRet = DefWindowProc( hWnd, uMsg, wParam, lParam );
535             INVOKE_WCB( *window, Entry, ( GLUT_LEFT ) );
536             fgSetWindow(saved_window);
537
538             /* Check if there are any open menus that need to be closed */
539             fgPlatformCheckMenuDeactivate();
540         }
541         break;
542
543 #if 0
544     case WM_ACTIVATE:
545         if (LOWORD(wParam) != WA_INACTIVE)
546         {
547 /*            printf("WM_ACTIVATE: fgSetCursor( %p, %d)\n", window,
548                    window->State.Cursor ); */
549             fgSetCursor( window, window->State.Cursor );
550         }
551
552         lRet = DefWindowProc( hWnd, uMsg, wParam, lParam );
553         break;
554 #endif
555
556     case WM_SETCURSOR:
557 /*      printf ( "Cursor event %x %x %x %x\n", window, window->State.Cursor, lParam, wParam ) ; */
558         if( LOWORD( lParam ) == HTCLIENT )
559             fgSetCursor ( window, window->State.Cursor ) ;
560         else
561             lRet = DefWindowProc( hWnd, uMsg, wParam, lParam );
562         break;
563
564     case WM_SHOWWINDOW:
565         window->State.Visible = GL_TRUE;
566         window->State.Redisplay = GL_TRUE;
567         break;
568
569     case WM_PAINT:
570         /* Turn on the visibility in case it was turned off somehow */
571         window->State.Visible = GL_TRUE;
572         InvalidateRect( hWnd, NULL, GL_FALSE ); /* Make sure whole window is repainted. Bit of a hack, but a safe one from what google turns up... */
573         BeginPaint( hWnd, &ps );
574         fghRedrawWindow( window );
575         EndPaint( hWnd, &ps );
576         break;
577
578     case WM_CLOSE:
579         fgDestroyWindow ( window );
580         if ( fgState.ActionOnWindowClose != GLUT_ACTION_CONTINUE_EXECUTION )
581             PostQuitMessage(0);
582         break;
583
584     case WM_DESTROY:
585         /*
586          * The window already got destroyed, so don't bother with it.
587          */
588         return 0;
589
590     case WM_MOUSEMOVE:
591     {
592 #if defined(_WIN32_WCE)
593         window->State.MouseX = 320-HIWORD( lParam );
594         window->State.MouseY = LOWORD( lParam );
595 #else
596         window->State.MouseX = LOWORD( lParam );
597         window->State.MouseY = HIWORD( lParam );
598 #endif /* defined(_WIN32_WCE) */
599         /* Restrict to [-32768, 32767] to match X11 behaviour       */
600         /* See comment in "freeglut_developer" mailing list 10/4/04 */
601         if ( window->State.MouseX > 32767 ) window->State.MouseX -= 65536;
602         if ( window->State.MouseY > 32767 ) window->State.MouseY -= 65536;
603
604         if ( window->ActiveMenu )
605         {
606             fgUpdateMenuHighlight( window->ActiveMenu );
607             break;
608         }
609
610         fgState.Modifiers = fgPlatformGetModifiers( );
611
612         if( ( wParam & MK_LBUTTON ) ||
613             ( wParam & MK_MBUTTON ) ||
614             ( wParam & MK_RBUTTON ) )
615             INVOKE_WCB( *window, Motion, ( window->State.MouseX,
616                                            window->State.MouseY ) );
617         else
618             INVOKE_WCB( *window, Passive, ( window->State.MouseX,
619                                             window->State.MouseY ) );
620
621         fgState.Modifiers = INVALID_MODIFIERS;
622     }
623     break;
624
625     case WM_LBUTTONDOWN:
626     case WM_MBUTTONDOWN:
627     case WM_RBUTTONDOWN:
628     case WM_LBUTTONUP:
629     case WM_MBUTTONUP:
630     case WM_RBUTTONUP:
631     {
632         GLboolean pressed = GL_TRUE;
633         int button;
634
635 #if defined(_WIN32_WCE)
636         window->State.MouseX = 320-HIWORD( lParam );
637         window->State.MouseY = LOWORD( lParam );
638 #else
639         window->State.MouseX = LOWORD( lParam );
640         window->State.MouseY = HIWORD( lParam );
641 #endif /* defined(_WIN32_WCE) */
642
643         /* Restrict to [-32768, 32767] to match X11 behaviour       */
644         /* See comment in "freeglut_developer" mailing list 10/4/04 */
645         if ( window->State.MouseX > 32767 ) window->State.MouseX -= 65536;
646         if ( window->State.MouseY > 32767 ) window->State.MouseY -= 65536;
647
648         switch( uMsg )
649         {
650         case WM_LBUTTONDOWN:
651             pressed = GL_TRUE;
652             button = GLUT_LEFT_BUTTON;
653             break;
654         case WM_MBUTTONDOWN:
655             pressed = GL_TRUE;
656             button = GLUT_MIDDLE_BUTTON;
657             break;
658         case WM_RBUTTONDOWN:
659             pressed = GL_TRUE;
660             button = GLUT_RIGHT_BUTTON;
661             break;
662         case WM_LBUTTONUP:
663             pressed = GL_FALSE;
664             button = GLUT_LEFT_BUTTON;
665             break;
666         case WM_MBUTTONUP:
667             pressed = GL_FALSE;
668             button = GLUT_MIDDLE_BUTTON;
669             break;
670         case WM_RBUTTONUP:
671             pressed = GL_FALSE;
672             button = GLUT_RIGHT_BUTTON;
673             break;
674         default:
675             pressed = GL_FALSE;
676             button = -1;
677             break;
678         }
679
680 #if !defined(_WIN32_WCE)
681         if( GetSystemMetrics( SM_SWAPBUTTON ) )
682         {
683             if( button == GLUT_LEFT_BUTTON )
684                 button = GLUT_RIGHT_BUTTON;
685             else
686                 if( button == GLUT_RIGHT_BUTTON )
687                     button = GLUT_LEFT_BUTTON;
688         }
689 #endif /* !defined(_WIN32_WCE) */
690
691         if( button == -1 )
692             return DefWindowProc( hWnd, uMsg, lParam, wParam );
693
694         /*
695          * Do not execute the application's mouse callback if a menu
696          * is hooked to this button.  In that case an appropriate
697          * private call should be generated.
698          */
699         if( fgCheckActiveMenu( window, button, pressed,
700                                window->State.MouseX, window->State.MouseY ) )
701             break;
702
703         /* Set capture so that the window captures all the mouse messages */
704         /*
705          * XXX - Multiple button support:  Under X11, the mouse is not released
706          * XXX - from the window until all buttons have been released, even if the
707          * XXX - user presses a button in another window.  This will take more
708          * XXX - code changes than I am up to at the moment (10/5/04).  The present
709          * XXX - is a 90 percent solution.
710          */
711         if ( pressed == GL_TRUE )
712           SetCapture ( window->Window.Handle ) ;
713         else
714           ReleaseCapture () ;
715
716         if( ! FETCH_WCB( *window, Mouse ) )
717             break;
718
719         fgSetWindow( window );
720         fgState.Modifiers = fgPlatformGetModifiers( );
721
722         INVOKE_WCB(
723             *window, Mouse,
724             ( button,
725               pressed ? GLUT_DOWN : GLUT_UP,
726               window->State.MouseX,
727               window->State.MouseY
728             )
729         );
730
731         fgState.Modifiers = INVALID_MODIFIERS;
732     }
733     break;
734
735     case WM_MOUSEWHEEL:
736     {
737         int wheel_number = LOWORD( wParam );
738         short ticks = ( short )HIWORD( wParam );
739                 fgState.MouseWheelTicks += ticks;
740
741         if ( abs ( fgState.MouseWheelTicks ) >= WHEEL_DELTA )
742                 {
743                         int direction = ( fgState.MouseWheelTicks > 0 ) ? 1 : -1;
744
745             if( ! FETCH_WCB( *window, MouseWheel ) &&
746                 ! FETCH_WCB( *window, Mouse ) )
747                 break;
748
749             fgSetWindow( window );
750             fgState.Modifiers = fgPlatformGetModifiers( );
751
752             while( abs ( fgState.MouseWheelTicks ) >= WHEEL_DELTA )
753                         {
754                 if( FETCH_WCB( *window, MouseWheel ) )
755                     INVOKE_WCB( *window, MouseWheel,
756                                 ( wheel_number,
757                                   direction,
758                                   window->State.MouseX,
759                                   window->State.MouseY
760                                 )
761                     );
762                 else  /* No mouse wheel, call the mouse button callback twice */
763                                 {
764                     /*
765                      * Map wheel zero to button 3 and 4; +1 to 3, -1 to 4
766                      *  "    "   one                     +1 to 5, -1 to 6, ...
767                      *
768                      * XXX The below assumes that you have no more than 3 mouse
769                      * XXX buttons.  Sorry.
770                      */
771                     int button = wheel_number * 2 + 3;
772                     if( direction < 0 )
773                         ++button;
774                     INVOKE_WCB( *window, Mouse,
775                                 ( button, GLUT_DOWN,
776                                   window->State.MouseX, window->State.MouseY )
777                     );
778                     INVOKE_WCB( *window, Mouse,
779                                 ( button, GLUT_UP,
780                                   window->State.MouseX, window->State.MouseY )
781                     );
782                                 }
783
784                                 fgState.MouseWheelTicks -= WHEEL_DELTA * direction;
785                         }
786
787             fgState.Modifiers = INVALID_MODIFIERS;
788                 }
789     }
790     break ;
791
792     case WM_SYSKEYDOWN:
793     case WM_KEYDOWN:
794         if (child_window)
795             window = child_window;
796         lRet = fghKeyPress(window,uMsg,GL_TRUE,wParam,lParam);
797     break;
798
799     case WM_SYSKEYUP:
800     case WM_KEYUP:
801         if (child_window)
802             window = child_window;
803         lRet = fghKeyPress(window,uMsg,GL_FALSE,wParam,lParam);
804     break;
805
806     case WM_SYSCHAR:
807     case WM_CHAR:
808     {
809       if (child_window)
810         window = child_window;
811
812       if( (fgState.KeyRepeat==GLUT_KEY_REPEAT_OFF || window->State.IgnoreKeyRepeat==GL_TRUE) && (HIWORD(lParam) & KF_REPEAT) )
813             break;
814
815         fgState.Modifiers = fgPlatformGetModifiers( );
816         INVOKE_WCB( *window, Keyboard,
817                     ( (char)wParam,
818                       window->State.MouseX, window->State.MouseY )
819         );
820         fgState.Modifiers = INVALID_MODIFIERS;
821     }
822     break;
823
824     case WM_CAPTURECHANGED:
825         /* User has finished resizing the window, force a redraw */
826         INVOKE_WCB( *window, Display, ( ) );
827
828         /*lRet = DefWindowProc( hWnd, uMsg, wParam, lParam ); */
829         break;
830
831         /* Other messages that I have seen and which are not handled already */
832     case WM_SETTEXT:  /* 0x000c */
833         lRet = DefWindowProc( hWnd, uMsg, wParam, lParam );
834         /* Pass it on to "DefWindowProc" to set the window text */
835         break;
836
837     case WM_GETTEXT:  /* 0x000d */
838         /* Ideally we would copy the title of the window into "lParam" */
839         /* strncpy ( (char *)lParam, "Window Title", wParam );
840            lRet = ( wParam > 12 ) ? 12 : wParam;  */
841         /* the number of characters copied */
842         lRet = DefWindowProc( hWnd, uMsg, wParam, lParam );
843         break;
844
845     case WM_GETTEXTLENGTH:  /* 0x000e */
846         /* Ideally we would get the length of the title of the window */
847         lRet = 12;
848         /* the number of characters in "Window Title\0" (see above) */
849         break;
850
851     case WM_ERASEBKGND:  /* 0x0014 */
852         lRet = DefWindowProc( hWnd, uMsg, wParam, lParam );
853         break;
854
855 #if !defined(_WIN32_WCE)
856     case WM_SYNCPAINT:  /* 0x0088 */
857         /* Another window has moved, need to update this one */
858         window->State.Redisplay = GL_TRUE;
859         lRet = DefWindowProc( hWnd, uMsg, wParam, lParam );
860         /* Help screen says this message must be passed to "DefWindowProc" */
861         break;
862
863     case WM_NCPAINT:  /* 0x0085 */
864       /* Need to update the border of this window */
865         lRet = DefWindowProc( hWnd, uMsg, wParam, lParam );
866         /* Pass it on to "DefWindowProc" to repaint a standard border */
867         break;
868
869     case WM_SYSCOMMAND :  /* 0x0112 */
870         {
871           /*
872            * We have received a system command message.  Try to act on it.
873            * The commands are passed in through the "wParam" parameter:
874            * The least significant digit seems to be which edge of the window
875            * is being used for a resize event:
876            *     4  3  5
877            *     1     2
878            *     7  6  8
879            * Congratulations and thanks to Richard Rauch for figuring this out..
880            */
881             switch ( wParam & 0xfff0 )
882             {
883             case SC_SIZE       :
884                 break ;
885
886             case SC_MOVE       :
887                 break ;
888
889             case SC_MINIMIZE   :
890                 /* User has clicked on the "-" to minimize the window */
891                 /* Turn off the visibility */
892                 window->State.Visible = GL_FALSE ;
893
894                 break ;
895
896             case SC_MAXIMIZE   :
897                 break ;
898
899             case SC_NEXTWINDOW :
900                 break ;
901
902             case SC_PREVWINDOW :
903                 break ;
904
905             case SC_CLOSE      :
906                 /* Followed very closely by a WM_CLOSE message */
907                 break ;
908
909             case SC_VSCROLL    :
910                 break ;
911
912             case SC_HSCROLL    :
913                 break ;
914
915             case SC_MOUSEMENU  :
916                 break ;
917
918             case SC_KEYMENU    :
919                 break ;
920
921             case SC_ARRANGE    :
922                 break ;
923
924             case SC_RESTORE    :
925                 break ;
926
927             case SC_TASKLIST   :
928                 break ;
929
930             case SC_SCREENSAVE :
931                 break ;
932
933             case SC_HOTKEY     :
934                 break ;
935
936 #if(WINVER >= 0x0400)
937             case SC_DEFAULT    :
938                 break ;
939
940             case SC_MONITORPOWER    :
941                 break ;
942
943             case SC_CONTEXTHELP    :
944                 break ;
945 #endif /* WINVER >= 0x0400 */
946
947             default:
948 #if _DEBUG
949                 fgWarning( "Unknown wParam type 0x%x", wParam );
950 #endif
951                 break;
952             }
953         }
954 #endif /* !defined(_WIN32_WCE) */
955
956         /* We need to pass the message on to the operating system as well */
957         lRet = DefWindowProc( hWnd, uMsg, wParam, lParam );
958         break;
959
960 #ifdef WM_TOUCH
961         /* handle multi-touch messages */
962         case WM_TOUCH:
963         {
964                 unsigned int numInputs = (unsigned int)wParam;
965                 unsigned int i = 0;
966                 TOUCHINPUT* ti = (TOUCHINPUT*)malloc( sizeof(TOUCHINPUT)*numInputs);
967
968                 if (fghGetTouchInputInfo == (pGetTouchInputInfo)0xDEADBEEF) {
969                     fghGetTouchInputInfo = (pGetTouchInputInfo)GetProcAddress(GetModuleHandle("user32"),"GetTouchInputInfo");
970                     fghCloseTouchInputHandle = (pCloseTouchInputHandle)GetProcAddress(GetModuleHandle("user32"),"CloseTouchInputHandle");
971                 }
972
973                 if (!fghGetTouchInputInfo) { 
974                         free( (void*)ti );
975                         break;
976                 }
977
978                 if (fghGetTouchInputInfo( (HTOUCHINPUT)lParam, numInputs, ti, sizeof(TOUCHINPUT) )) {
979                         /* Handle each contact point */
980                         for (i = 0; i < numInputs; ++i ) {
981
982                                 POINT tp;
983                                 tp.x = TOUCH_COORD_TO_PIXEL(ti[i].x);
984                                 tp.y = TOUCH_COORD_TO_PIXEL(ti[i].y);
985                                 ScreenToClient( hWnd, &tp );
986
987                                 ti[i].dwID = ti[i].dwID * 2;
988
989                                 if (ti[i].dwFlags & TOUCHEVENTF_DOWN) {
990                                         INVOKE_WCB( *window, MultiEntry,  ( ti[i].dwID, GLUT_ENTERED ) );
991                                         INVOKE_WCB( *window, MultiButton, ( ti[i].dwID, tp.x, tp.y, 0, GLUT_DOWN ) );
992                                 } else if (ti[i].dwFlags & TOUCHEVENTF_MOVE) {
993                                         INVOKE_WCB( *window, MultiMotion, ( ti[i].dwID, tp.x, tp.y ) );
994                                 } else if (ti[i].dwFlags & TOUCHEVENTF_UP)   { 
995                                         INVOKE_WCB( *window, MultiButton, ( ti[i].dwID, tp.x, tp.y, 0, GLUT_UP ) );
996                                         INVOKE_WCB( *window, MultiEntry,  ( ti[i].dwID, GLUT_LEFT ) );
997                                 }
998                         }
999                 }
1000                 fghCloseTouchInputHandle((HTOUCHINPUT)lParam);
1001                 free( (void*)ti );
1002                 lRet = 0; /*DefWindowProc( hWnd, uMsg, wParam, lParam );*/
1003                 break;
1004         }
1005 #endif
1006     default:
1007         /* Handle unhandled messages */
1008         lRet = DefWindowProc( hWnd, uMsg, wParam, lParam );
1009         break;
1010     }
1011
1012     return lRet;
1013 }