25330e81fb601a889a6355ea254e605e5235626d
[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 #ifdef WM_TOUCH
39 typedef BOOL (WINAPI *pGetTouchInputInfo)(HTOUCHINPUT,UINT,PTOUCHINPUT,int);
40 typedef BOOL (WINAPI *pCloseTouchInputHandle)(HTOUCHINPUT);
41 static pGetTouchInputInfo fghGetTouchInputInfo = (pGetTouchInputInfo)0xDEADBEEF;
42 static pCloseTouchInputHandle fghCloseTouchInputHandle = (pCloseTouchInputHandle)0xDEADBEEF;
43 #endif
44
45 #ifdef _WIN32_WCE
46 typedef struct GXDisplayProperties GXDisplayProperties;
47 typedef struct GXKeyList GXKeyList;
48 #include <gx.h>
49
50 typedef struct GXKeyList (*GXGETDEFAULTKEYS)(int);
51 typedef int (*GXOPENINPUT)();
52
53 GXGETDEFAULTKEYS GXGetDefaultKeys_ = NULL;
54 GXOPENINPUT GXOpenInput_ = NULL;
55
56 struct GXKeyList gxKeyList;
57 #endif /* _WIN32_WCE */
58
59 /* 
60  * Helper functions for getting client area from the window rect
61  * and the window rect from the client area given the style of the window
62  * (or a valid window pointer from which the style can be queried).
63  */
64 extern void fghComputeWindowRectFromClientArea_QueryWindow( const SFG_Window *window, RECT *clientRect, BOOL posIsOutside );
65 extern RECT fghGetClientArea                              ( const SFG_Window *window,                   BOOL wantPosOutside );
66
67
68 void fgPlatformReshapeWindow ( SFG_Window *window, int width, int height )
69 {
70     RECT windowRect;
71
72     /*
73      * For windowed mode, get the current position of the
74      * window and resize taking the size of the frame
75      * decorations into account.
76      */
77
78     /* "GetWindowRect" returns the pixel coordinates of the outside of the window */
79     GetWindowRect( window->Window.Handle, &windowRect );
80
81     /* Create rect in FreeGLUT format, (X,Y) topleft outside window, WxH of client area */
82     windowRect.right    = windowRect.left+width;
83     windowRect.bottom   = windowRect.top+height;
84
85     if (window->Parent == NULL)
86         /* get the window rect from this to feed to SetWindowPos, correct for window decorations */
87         fghComputeWindowRectFromClientArea_QueryWindow(window,&windowRect,TRUE);
88     else
89     {
90         /* correct rect for position client area of parent window
91          * (SetWindowPos input for child windows is in coordinates
92          * relative to the parent's client area).
93          * Child windows don't have decoration, so no need to correct
94          * for them.
95          */
96         RECT parentRect;
97         parentRect = fghGetClientArea( window->Parent, FALSE );
98         windowRect.left   -= parentRect.left;
99         windowRect.right  -= parentRect.left;
100         windowRect.top    -= parentRect.top;
101         windowRect.bottom -= parentRect.top;
102     }
103     
104     /* Do the actual resizing */
105     SetWindowPos( window->Window.Handle,
106                   HWND_TOP,
107                   windowRect.left, windowRect.top,
108                   windowRect.right - windowRect.left,
109                   windowRect.bottom- windowRect.top,
110                   SWP_NOACTIVATE | SWP_NOOWNERZORDER | SWP_NOSENDCHANGING |
111                   SWP_NOZORDER
112     );
113 }
114
115
116 void fgPlatformDisplayWindow ( SFG_Window *window )
117 {
118     RedrawWindow(
119         window->Window.Handle, NULL, NULL,
120         RDW_NOERASE | RDW_INTERNALPAINT | RDW_INVALIDATE | RDW_UPDATENOW
121     );
122 }
123
124
125 fg_time_t fgPlatformSystemTime ( void )
126 {
127 #if defined(_WIN32_WCE)
128     return GetTickCount();
129 #else
130     /* TODO: do this with QueryPerformanceCounter as timeGetTime has
131      * insufficient resolution (only about 5 ms on system under low load).
132      * See:
133      * http://msdn.microsoft.com/en-us/library/windows/desktop/dd757629(v=vs.85).aspx
134      * Or maybe QueryPerformanceCounter is not a good idea either, see
135      * http://old.nabble.com/Re%3A-glutTimerFunc-does-not-detect-if-system-time-moved-backward-p33479674.html
136      * for some other ideas (at bottom)...
137      */
138     return timeGetTime();
139 #endif
140 }
141
142
143 void fgPlatformSleepForEvents( fg_time_t msec )
144 {
145     MsgWaitForMultipleObjects( 0, NULL, FALSE, (DWORD) msec, QS_ALLINPUT );
146 }
147
148
149 void fgPlatformProcessSingleEvent ( void )
150 {
151     MSG stMsg;
152
153     FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutMainLoopEvent" );
154
155     while( PeekMessage( &stMsg, NULL, 0, 0, PM_NOREMOVE ) )
156     {
157         if( GetMessage( &stMsg, NULL, 0, 0 ) == 0 )
158         {
159             if( fgState.ActionOnWindowClose == GLUT_ACTION_EXIT )
160             {
161                 fgDeinitialize( );
162                 exit( 0 );
163             }
164             else if( fgState.ActionOnWindowClose == GLUT_ACTION_GLUTMAINLOOP_RETURNS )
165                 fgState.ExecState = GLUT_EXEC_STATE_STOP;
166
167             return;
168         }
169
170         TranslateMessage( &stMsg );
171         DispatchMessage( &stMsg );
172     }
173 }
174
175
176
177 void fgPlatformMainLoopPreliminaryWork ( void )
178 {
179     SFG_Window *window = (SFG_Window *)fgStructure.Windows.First ;
180
181     /*
182      * Processing before the main loop:  If there is a window which is open and
183      * which has a visibility callback, call it.  I know this is an ugly hack,
184      * but I'm not sure what else to do about it.  Ideally we should leave
185      * something uninitialized in the create window code and initialize it in
186      * the main loop, and have that initialization create a "WM_ACTIVATE"
187      * message.  Then we would put the visibility callback code in the
188      * "case WM_ACTIVATE" block below.         - John Fay -- 10/24/02
189      */
190     while( window )
191     {
192         if ( FETCH_WCB( *window, Visibility ) )
193         {
194             SFG_Window *current_window = fgStructure.CurrentWindow ;
195
196             INVOKE_WCB( *window, Visibility, ( window->State.Visible ) );
197             fgSetWindow( current_window );
198         }
199
200         window = (SFG_Window *)window->Node.Next ;
201     }
202 }
203
204
205 /*
206  * Determine a GLUT modifer mask based on MS-WINDOWS system info.
207  */
208 static int fgPlatformGetModifiers (void)
209 {
210     return
211         ( ( ( GetKeyState( VK_LSHIFT   ) < 0 ) ||
212             ( GetKeyState( VK_RSHIFT   ) < 0 )) ? GLUT_ACTIVE_SHIFT : 0 ) |
213         ( ( ( GetKeyState( VK_LCONTROL ) < 0 ) ||
214             ( GetKeyState( VK_RCONTROL ) < 0 )) ? GLUT_ACTIVE_CTRL  : 0 ) |
215         ( ( ( GetKeyState( VK_LMENU    ) < 0 ) ||
216             ( GetKeyState( VK_RMENU    ) < 0 )) ? GLUT_ACTIVE_ALT   : 0 );
217 }
218
219 /*
220  * The window procedure for handling Win32 events
221  */
222 LRESULT CALLBACK fgPlatformWindowProc( HWND hWnd, UINT uMsg, WPARAM wParam,
223                                        LPARAM lParam )
224 {
225     static unsigned char lControl = 0, rControl = 0, lShift = 0,
226                          rShift = 0, lAlt = 0, rAlt = 0;
227
228     SFG_Window* window;
229     PAINTSTRUCT ps;
230     LRESULT lRet = 1;
231
232     FREEGLUT_INTERNAL_ERROR_EXIT_IF_NOT_INITIALISED ( "Event Handler" ) ;
233
234     window = fgWindowByHandle( hWnd );
235
236     if ( ( window == NULL ) && ( uMsg != WM_CREATE ) )
237       return DefWindowProc( hWnd, uMsg, wParam, lParam );
238
239     /* printf ( "Window %3d message <%04x> %12d %12d\n", window?window->ID:0,
240              uMsg, wParam, lParam ); */
241
242     /* events only sent to main window. Check if the current window that the mouse
243        is over is a child window and if so, make sure we call the callback on that
244        child instead.
245     */
246     if (window && window->Children.First)
247     {
248         POINT mouse_pos;
249         SFG_WindowHandleType hwnd;
250
251         GetCursorPos( &mouse_pos );
252         ScreenToClient( window->Window.Handle, &mouse_pos );
253         hwnd = ChildWindowFromPoint(window->Window.Handle, mouse_pos);
254         if (hwnd)   /* can be NULL if mouse outside parent by the time we get here */
255             window = fgWindowByHandle(hwnd);
256     }
257
258     if ( window )
259     {
260       fgState.Modifiers = fgPlatformGetModifiers( );
261
262       /* Checking for CTRL, ALT, and SHIFT key positions:  Key Down! */
263       if ( !lControl && GetAsyncKeyState ( VK_LCONTROL ) )
264       {
265           INVOKE_WCB    ( *window, Special,
266                         ( GLUT_KEY_CTRL_L, window->State.MouseX, window->State.MouseY )
267                       );
268
269           lControl = 1;
270       }
271
272       if ( !rControl && GetAsyncKeyState ( VK_RCONTROL ) )
273       {
274           INVOKE_WCB ( *window, Special,
275                        ( GLUT_KEY_CTRL_R, window->State.MouseX, window->State.MouseY )
276                      );
277
278           rControl = 1;
279       }
280
281       if ( !lShift && GetAsyncKeyState ( VK_LSHIFT ) )
282       {
283           INVOKE_WCB ( *window, Special,
284                        ( GLUT_KEY_SHIFT_L, window->State.MouseX, window->State.MouseY )
285                      );
286
287           lShift = 1;
288       }
289
290       if ( !rShift && GetAsyncKeyState ( VK_RSHIFT ) )
291       {
292           INVOKE_WCB ( *window, Special,
293                        ( GLUT_KEY_SHIFT_R, window->State.MouseX, window->State.MouseY )
294                      );
295
296           rShift = 1;
297       }
298
299       if ( !lAlt && GetAsyncKeyState ( VK_LMENU ) )
300       {
301           INVOKE_WCB ( *window, Special,
302                        ( GLUT_KEY_ALT_L, window->State.MouseX, window->State.MouseY )
303                      );
304
305           lAlt = 1;
306       }
307
308       if ( !rAlt && GetAsyncKeyState ( VK_RMENU ) )
309       {
310           INVOKE_WCB ( *window, Special,
311                        ( GLUT_KEY_ALT_R, window->State.MouseX, window->State.MouseY )
312                      );
313
314           rAlt = 1;
315       }
316
317       /* Checking for CTRL, ALT, and SHIFT key positions:  Key Up! */
318       if ( lControl && !GetAsyncKeyState ( VK_LCONTROL ) )
319       {
320           INVOKE_WCB ( *window, SpecialUp,
321                        ( GLUT_KEY_CTRL_L, window->State.MouseX, window->State.MouseY )
322                      );
323
324           lControl = 0;
325       }
326
327       if ( rControl && !GetAsyncKeyState ( VK_RCONTROL ) )
328       {
329           INVOKE_WCB ( *window, SpecialUp,
330                        ( GLUT_KEY_CTRL_R, window->State.MouseX, window->State.MouseY )
331                      );
332
333           rControl = 0;
334       }
335
336       if ( lShift && !GetAsyncKeyState ( VK_LSHIFT ) )
337       {
338           INVOKE_WCB ( *window, SpecialUp,
339                        ( GLUT_KEY_SHIFT_L, window->State.MouseX, window->State.MouseY )
340                      );
341
342           lShift = 0;
343       }
344
345       if ( rShift && !GetAsyncKeyState ( VK_RSHIFT ) )
346       {
347           INVOKE_WCB ( *window, SpecialUp,
348                        ( GLUT_KEY_SHIFT_R, window->State.MouseX, window->State.MouseY )
349                      );
350
351           rShift = 0;
352       }
353
354       if ( lAlt && !GetAsyncKeyState ( VK_LMENU ) )
355       {
356           INVOKE_WCB ( *window, SpecialUp,
357                        ( GLUT_KEY_ALT_L, window->State.MouseX, window->State.MouseY )
358                      );
359
360           lAlt = 0;
361       }
362
363       if ( rAlt && !GetAsyncKeyState ( VK_RMENU ) )
364       {
365           INVOKE_WCB ( *window, SpecialUp,
366                        ( GLUT_KEY_ALT_R, window->State.MouseX, window->State.MouseY )
367                      );
368
369           rAlt = 0;
370       }
371
372       fgState.Modifiers = INVALID_MODIFIERS;
373     }
374
375     switch( uMsg )
376     {
377     case WM_CREATE:
378         /* The window structure is passed as the creation structure parameter... */
379         window = (SFG_Window *) (((LPCREATESTRUCT) lParam)->lpCreateParams);
380         FREEGLUT_INTERNAL_ERROR_EXIT ( ( window != NULL ), "Cannot create window",
381                                        "fgPlatformWindowProc" );
382
383         window->Window.Handle = hWnd;
384         window->Window.pContext.Device = GetDC( hWnd );
385         if( window->IsMenu )
386         {
387             unsigned int current_DisplayMode = fgState.DisplayMode;
388             fgState.DisplayMode = GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH;
389 #if !defined(_WIN32_WCE)
390             fgSetupPixelFormat( window, GL_FALSE, PFD_MAIN_PLANE );
391 #endif
392             fgState.DisplayMode = current_DisplayMode;
393
394             if( fgStructure.MenuContext )
395                 wglMakeCurrent( window->Window.pContext.Device,
396                                 fgStructure.MenuContext->MContext
397                 );
398             else
399             {
400                 fgStructure.MenuContext =
401                     (SFG_MenuContext *)malloc( sizeof(SFG_MenuContext) );
402                 fgStructure.MenuContext->MContext =
403                     wglCreateContext( window->Window.pContext.Device );
404             }
405
406             /* window->Window.Context = wglGetCurrentContext ();   */
407             window->Window.Context = wglCreateContext( window->Window.pContext.Device );
408         }
409         else
410         {
411 #if !defined(_WIN32_WCE)
412             fgSetupPixelFormat( window, GL_FALSE, PFD_MAIN_PLANE );
413 #endif
414
415             if( ! fgState.UseCurrentContext )
416                 window->Window.Context =
417                     wglCreateContext( window->Window.pContext.Device );
418             else
419             {
420                 window->Window.Context = wglGetCurrentContext( );
421                 if( ! window->Window.Context )
422                     window->Window.Context =
423                         wglCreateContext( window->Window.pContext.Device );
424             }
425
426 #if !defined(_WIN32_WCE)
427             fgNewWGLCreateContext( window );
428 #endif
429         }
430
431         window->State.NeedToResize = GL_TRUE;
432         /* if we used CW_USEDEFAULT (thats a negative value) for the size
433          * of the window, query the window now for the size at which it
434          * was created.
435          */
436         if( ( window->State.Width < 0 ) || ( window->State.Height < 0 ) )
437         {
438             SFG_Window *current_window = fgStructure.CurrentWindow;
439
440             fgSetWindow( window );
441             window->State.Width = glutGet( GLUT_WINDOW_WIDTH );
442             window->State.Height = glutGet( GLUT_WINDOW_HEIGHT );
443             fgSetWindow( current_window );
444         }
445
446         ReleaseDC( window->Window.Handle, window->Window.pContext.Device );
447
448 #if defined(_WIN32_WCE)
449         /* Take over button handling */
450         {
451             HINSTANCE dxDllLib=LoadLibrary(_T("gx.dll"));
452             if (dxDllLib)
453             {
454                 GXGetDefaultKeys_=(GXGETDEFAULTKEYS)GetProcAddress(dxDllLib, _T("?GXGetDefaultKeys@@YA?AUGXKeyList@@H@Z"));
455                 GXOpenInput_=(GXOPENINPUT)GetProcAddress(dxDllLib, _T("?GXOpenInput@@YAHXZ"));
456             }
457
458             if(GXOpenInput_)
459                 (*GXOpenInput_)();
460             if(GXGetDefaultKeys_)
461                 gxKeyList = (*GXGetDefaultKeys_)(GX_LANDSCAPEKEYS);
462         }
463
464 #endif /* defined(_WIN32_WCE) */
465         break;
466
467     case WM_SIZE:
468         /*
469          * If the window is visible, then it is the user manually resizing it.
470          * If it is not, then it is the system sending us a dummy resize with
471          * zero dimensions on a "glutIconifyWindow" call.
472          */
473         if( window->State.Visible )
474         {
475             window->State.NeedToResize = GL_TRUE;
476 #if defined(_WIN32_WCE)
477             window->State.Width  = HIWORD(lParam);
478             window->State.Height = LOWORD(lParam);
479 #else
480             window->State.Width  = LOWORD(lParam);
481             window->State.Height = HIWORD(lParam);
482 #endif /* defined(_WIN32_WCE) */
483         }
484
485         break;
486
487     case WM_SETFOCUS:
488 /*        printf("WM_SETFOCUS: %p\n", window ); */
489         lRet = DefWindowProc( hWnd, uMsg, wParam, lParam );
490         INVOKE_WCB( *window, Entry, ( GLUT_ENTERED ) );
491
492                 UpdateWindow ( hWnd );
493         break;
494
495     case WM_KILLFOCUS:
496         {
497             SFG_Menu* menu = NULL;
498 /*            printf("WM_KILLFOCUS: %p\n", window ); */
499             lRet = DefWindowProc( hWnd, uMsg, wParam, lParam );
500             INVOKE_WCB( *window, Entry, ( GLUT_LEFT ) );
501
502             /* If we have an open menu, see if the open menu should be closed
503                when focus was lost because user either switched
504                application or FreeGLUT window (if one is running multiple
505                windows). If so, close menu the active menu.
506              */
507             if ( fgStructure.Menus.First )
508                 menu = fgGetActiveMenu();
509             
510             if ( menu )
511             {
512                 SFG_Window* wnd = NULL;
513                 HWND hwnd = GetFocus();  /* Get window with current focus - NULL for non freeglut windows */
514                 if (hwnd)
515                     /* See which of our windows it is */
516                     wnd = fgWindowByHandle(hwnd);
517
518                 if (!hwnd || !wnd)
519                     /* User switched to another application*/
520                     fgDeactivateMenu(menu->ParentWindow);
521                 else if (!wnd->IsMenu && wnd!=menu->ParentWindow)
522                     /* User switched to another FreeGLUT window */
523                     fgDeactivateMenu(menu->ParentWindow);
524             }
525         }
526         break;
527
528 #if 0
529     case WM_ACTIVATE:
530         if (LOWORD(wParam) != WA_INACTIVE)
531         {
532 /*            printf("WM_ACTIVATE: fgSetCursor( %p, %d)\n", window,
533                    window->State.Cursor ); */
534             fgSetCursor( window, window->State.Cursor );
535         }
536
537         lRet = DefWindowProc( hWnd, uMsg, wParam, lParam );
538         break;
539 #endif
540
541     case WM_SETCURSOR:
542 /*      printf ( "Cursor event %x %x %x %x\n", window, window->State.Cursor, lParam, wParam ) ; */
543         if( LOWORD( lParam ) == HTCLIENT )
544             fgSetCursor ( window, window->State.Cursor ) ;
545         else
546             lRet = DefWindowProc( hWnd, uMsg, wParam, lParam );
547         break;
548
549     case WM_SHOWWINDOW:
550         window->State.Visible = GL_TRUE;
551         window->State.Redisplay = GL_TRUE;
552         break;
553
554     case WM_PAINT:
555         /* Turn on the visibility in case it was turned off somehow */
556         window->State.Visible = GL_TRUE;
557         BeginPaint( hWnd, &ps );
558         fghRedrawWindow( window );
559         EndPaint( hWnd, &ps );
560         break;
561
562     case WM_CLOSE:
563         fgDestroyWindow ( window );
564         if ( fgState.ActionOnWindowClose != GLUT_ACTION_CONTINUE_EXECUTION )
565             PostQuitMessage(0);
566         break;
567
568     case WM_DESTROY:
569         /*
570          * The window already got destroyed, so don't bother with it.
571          */
572         return 0;
573
574     case WM_MOUSEMOVE:
575     {
576 #if defined(_WIN32_WCE)
577         window->State.MouseX = 320-HIWORD( lParam );
578         window->State.MouseY = LOWORD( lParam );
579 #else
580         window->State.MouseX = LOWORD( lParam );
581         window->State.MouseY = HIWORD( lParam );
582 #endif /* defined(_WIN32_WCE) */
583         /* Restrict to [-32768, 32767] to match X11 behaviour       */
584         /* See comment in "freeglut_developer" mailing list 10/4/04 */
585         if ( window->State.MouseX > 32767 ) window->State.MouseX -= 65536;
586         if ( window->State.MouseY > 32767 ) window->State.MouseY -= 65536;
587
588         if ( window->ActiveMenu )
589         {
590             fgUpdateMenuHighlight( window->ActiveMenu );
591             break;
592         }
593
594         fgState.Modifiers = fgPlatformGetModifiers( );
595
596         if( ( wParam & MK_LBUTTON ) ||
597             ( wParam & MK_MBUTTON ) ||
598             ( wParam & MK_RBUTTON ) )
599             INVOKE_WCB( *window, Motion, ( window->State.MouseX,
600                                            window->State.MouseY ) );
601         else
602             INVOKE_WCB( *window, Passive, ( window->State.MouseX,
603                                             window->State.MouseY ) );
604
605         fgState.Modifiers = INVALID_MODIFIERS;
606     }
607     break;
608
609     case WM_LBUTTONDOWN:
610     case WM_MBUTTONDOWN:
611     case WM_RBUTTONDOWN:
612     case WM_LBUTTONUP:
613     case WM_MBUTTONUP:
614     case WM_RBUTTONUP:
615     {
616         GLboolean pressed = GL_TRUE;
617         int button;
618
619 #if defined(_WIN32_WCE)
620         window->State.MouseX = 320-HIWORD( lParam );
621         window->State.MouseY = LOWORD( lParam );
622 #else
623         window->State.MouseX = LOWORD( lParam );
624         window->State.MouseY = HIWORD( lParam );
625 #endif /* defined(_WIN32_WCE) */
626
627         /* Restrict to [-32768, 32767] to match X11 behaviour       */
628         /* See comment in "freeglut_developer" mailing list 10/4/04 */
629         if ( window->State.MouseX > 32767 ) window->State.MouseX -= 65536;
630         if ( window->State.MouseY > 32767 ) window->State.MouseY -= 65536;
631
632         switch( uMsg )
633         {
634         case WM_LBUTTONDOWN:
635             pressed = GL_TRUE;
636             button = GLUT_LEFT_BUTTON;
637             break;
638         case WM_MBUTTONDOWN:
639             pressed = GL_TRUE;
640             button = GLUT_MIDDLE_BUTTON;
641             break;
642         case WM_RBUTTONDOWN:
643             pressed = GL_TRUE;
644             button = GLUT_RIGHT_BUTTON;
645             break;
646         case WM_LBUTTONUP:
647             pressed = GL_FALSE;
648             button = GLUT_LEFT_BUTTON;
649             break;
650         case WM_MBUTTONUP:
651             pressed = GL_FALSE;
652             button = GLUT_MIDDLE_BUTTON;
653             break;
654         case WM_RBUTTONUP:
655             pressed = GL_FALSE;
656             button = GLUT_RIGHT_BUTTON;
657             break;
658         default:
659             pressed = GL_FALSE;
660             button = -1;
661             break;
662         }
663
664 #if !defined(_WIN32_WCE)
665         if( GetSystemMetrics( SM_SWAPBUTTON ) )
666         {
667             if( button == GLUT_LEFT_BUTTON )
668                 button = GLUT_RIGHT_BUTTON;
669             else
670                 if( button == GLUT_RIGHT_BUTTON )
671                     button = GLUT_LEFT_BUTTON;
672         }
673 #endif /* !defined(_WIN32_WCE) */
674
675         if( button == -1 )
676             return DefWindowProc( hWnd, uMsg, lParam, wParam );
677
678         /*
679          * Do not execute the application's mouse callback if a menu
680          * is hooked to this button.  In that case an appropriate
681          * private call should be generated.
682          */
683         if( fgCheckActiveMenu( window, button, pressed,
684                                window->State.MouseX, window->State.MouseY ) )
685             break;
686
687         /* Set capture so that the window captures all the mouse messages */
688         /*
689          * XXX - Multiple button support:  Under X11, the mouse is not released
690          * XXX - from the window until all buttons have been released, even if the
691          * XXX - user presses a button in another window.  This will take more
692          * XXX - code changes than I am up to at the moment (10/5/04).  The present
693          * XXX - is a 90 percent solution.
694          */
695         if ( pressed == GL_TRUE )
696           SetCapture ( window->Window.Handle ) ;
697         else
698           ReleaseCapture () ;
699
700         if( ! FETCH_WCB( *window, Mouse ) )
701             break;
702
703         fgSetWindow( window );
704         fgState.Modifiers = fgPlatformGetModifiers( );
705
706         INVOKE_WCB(
707             *window, Mouse,
708             ( button,
709               pressed ? GLUT_DOWN : GLUT_UP,
710               window->State.MouseX,
711               window->State.MouseY
712             )
713         );
714
715         fgState.Modifiers = INVALID_MODIFIERS;
716     }
717     break;
718
719     case WM_MOUSEWHEEL:
720     {
721         int wheel_number = LOWORD( wParam );
722         short ticks = ( short )HIWORD( wParam );
723                 fgState.MouseWheelTicks += ticks;
724
725         /*
726          * XXX Should use WHEEL_DELTA instead of 120
727          */
728                 if ( abs ( fgState.MouseWheelTicks ) >= 120 )
729                 {
730                         int direction = ( fgState.MouseWheelTicks > 0 ) ? 1 : -1;
731
732             if( ! FETCH_WCB( *window, MouseWheel ) &&
733                 ! FETCH_WCB( *window, Mouse ) )
734                 break;
735
736             fgSetWindow( window );
737             fgState.Modifiers = fgPlatformGetModifiers( );
738
739             /*
740              * XXX Should use WHEEL_DELTA instead of 120
741              */
742             while( abs ( fgState.MouseWheelTicks ) >= 120 )
743                         {
744                 if( FETCH_WCB( *window, MouseWheel ) )
745                     INVOKE_WCB( *window, MouseWheel,
746                                 ( wheel_number,
747                                   direction,
748                                   window->State.MouseX,
749                                   window->State.MouseY
750                                 )
751                     );
752                 else  /* No mouse wheel, call the mouse button callback twice */
753                                 {
754                     /*
755                      * Map wheel zero to button 3 and 4; +1 to 3, -1 to 4
756                      *  "    "   one                     +1 to 5, -1 to 6, ...
757                      *
758                      * XXX The below assumes that you have no more than 3 mouse
759                      * XXX buttons.  Sorry.
760                      */
761                     int button = wheel_number * 2 + 3;
762                     if( direction < 0 )
763                         ++button;
764                     INVOKE_WCB( *window, Mouse,
765                                 ( button, GLUT_DOWN,
766                                   window->State.MouseX, window->State.MouseY )
767                     );
768                     INVOKE_WCB( *window, Mouse,
769                                 ( button, GLUT_UP,
770                                   window->State.MouseX, window->State.MouseY )
771                     );
772                                 }
773
774                 /*
775                  * XXX Should use WHEEL_DELTA instead of 120
776                  */
777                                 fgState.MouseWheelTicks -= 120 * direction;
778                         }
779
780             fgState.Modifiers = INVALID_MODIFIERS;
781                 }
782     }
783     break ;
784
785     case WM_SYSKEYDOWN:
786     case WM_KEYDOWN:
787     {
788         int keypress = -1;
789         POINT mouse_pos ;
790
791
792         if( ( fgState.KeyRepeat==GLUT_KEY_REPEAT_OFF || window->State.IgnoreKeyRepeat==GL_TRUE ) && (HIWORD(lParam) & KF_REPEAT) )
793             break;
794
795         /*
796          * Remember the current modifiers state. This is done here in order
797          * to make sure the VK_DELETE keyboard callback is executed properly.
798          */
799         fgState.Modifiers = fgPlatformGetModifiers( );
800
801         GetCursorPos( &mouse_pos );
802         ScreenToClient( window->Window.Handle, &mouse_pos );
803
804         window->State.MouseX = mouse_pos.x;
805         window->State.MouseY = mouse_pos.y;
806
807         /* Convert the Win32 keystroke codes to GLUTtish way */
808 #       define KEY(a,b) case a: keypress = b; break;
809
810         switch( wParam )
811         {
812             KEY( VK_F1,     GLUT_KEY_F1        );
813             KEY( VK_F2,     GLUT_KEY_F2        );
814             KEY( VK_F3,     GLUT_KEY_F3        );
815             KEY( VK_F4,     GLUT_KEY_F4        );
816             KEY( VK_F5,     GLUT_KEY_F5        );
817             KEY( VK_F6,     GLUT_KEY_F6        );
818             KEY( VK_F7,     GLUT_KEY_F7        );
819             KEY( VK_F8,     GLUT_KEY_F8        );
820             KEY( VK_F9,     GLUT_KEY_F9        );
821             KEY( VK_F10,    GLUT_KEY_F10       );
822             KEY( VK_F11,    GLUT_KEY_F11       );
823             KEY( VK_F12,    GLUT_KEY_F12       );
824             KEY( VK_PRIOR,  GLUT_KEY_PAGE_UP   );
825             KEY( VK_NEXT,   GLUT_KEY_PAGE_DOWN );
826             KEY( VK_HOME,   GLUT_KEY_HOME      );
827             KEY( VK_END,    GLUT_KEY_END       );
828             KEY( VK_LEFT,   GLUT_KEY_LEFT      );
829             KEY( VK_UP,     GLUT_KEY_UP        );
830             KEY( VK_RIGHT,  GLUT_KEY_RIGHT     );
831             KEY( VK_DOWN,   GLUT_KEY_DOWN      );
832             KEY( VK_INSERT, GLUT_KEY_INSERT    );
833
834         case VK_LCONTROL:  case VK_RCONTROL:  case VK_CONTROL:
835         case VK_LSHIFT:    case VK_RSHIFT:    case VK_SHIFT:
836         case VK_LMENU:     case VK_RMENU:     case VK_MENU:
837             /* These keypresses and releases are handled earlier in the function */
838             break;
839
840         case VK_DELETE:
841             /* The delete key should be treated as an ASCII keypress: */
842             INVOKE_WCB( *window, Keyboard,
843                         ( 127, window->State.MouseX, window->State.MouseY )
844             );
845         }
846
847 #if defined(_WIN32_WCE)
848         if(!(lParam & 0x40000000)) /* Prevent auto-repeat */
849         {
850             if(wParam==(unsigned)gxKeyList.vkRight)
851                 keypress = GLUT_KEY_RIGHT;
852             else if(wParam==(unsigned)gxKeyList.vkLeft)
853                 keypress = GLUT_KEY_LEFT;
854             else if(wParam==(unsigned)gxKeyList.vkUp)
855                 keypress = GLUT_KEY_UP;
856             else if(wParam==(unsigned)gxKeyList.vkDown)
857                 keypress = GLUT_KEY_DOWN;
858             else if(wParam==(unsigned)gxKeyList.vkA)
859                 keypress = GLUT_KEY_F1;
860             else if(wParam==(unsigned)gxKeyList.vkB)
861                 keypress = GLUT_KEY_F2;
862             else if(wParam==(unsigned)gxKeyList.vkC)
863                 keypress = GLUT_KEY_F3;
864             else if(wParam==(unsigned)gxKeyList.vkStart)
865                 keypress = GLUT_KEY_F4;
866         }
867 #endif
868
869         if( keypress != -1 )
870             INVOKE_WCB( *window, Special,
871                         ( keypress,
872                           window->State.MouseX, window->State.MouseY )
873             );
874
875         fgState.Modifiers = INVALID_MODIFIERS;
876     }
877     break;
878
879     case WM_SYSKEYUP:
880     case WM_KEYUP:
881     {
882         int keypress = -1;
883         POINT mouse_pos;
884
885         /*
886          * Remember the current modifiers state. This is done here in order
887          * to make sure the VK_DELETE keyboard callback is executed properly.
888          */
889         fgState.Modifiers = fgPlatformGetModifiers( );
890
891         GetCursorPos( &mouse_pos );
892         ScreenToClient( window->Window.Handle, &mouse_pos );
893
894         window->State.MouseX = mouse_pos.x;
895         window->State.MouseY = mouse_pos.y;
896
897         /*
898          * Convert the Win32 keystroke codes to GLUTtish way.
899          * "KEY(a,b)" was defined under "WM_KEYDOWN"
900          */
901
902         switch( wParam )
903         {
904             KEY( VK_F1,     GLUT_KEY_F1        );
905             KEY( VK_F2,     GLUT_KEY_F2        );
906             KEY( VK_F3,     GLUT_KEY_F3        );
907             KEY( VK_F4,     GLUT_KEY_F4        );
908             KEY( VK_F5,     GLUT_KEY_F5        );
909             KEY( VK_F6,     GLUT_KEY_F6        );
910             KEY( VK_F7,     GLUT_KEY_F7        );
911             KEY( VK_F8,     GLUT_KEY_F8        );
912             KEY( VK_F9,     GLUT_KEY_F9        );
913             KEY( VK_F10,    GLUT_KEY_F10       );
914             KEY( VK_F11,    GLUT_KEY_F11       );
915             KEY( VK_F12,    GLUT_KEY_F12       );
916             KEY( VK_PRIOR,  GLUT_KEY_PAGE_UP   );
917             KEY( VK_NEXT,   GLUT_KEY_PAGE_DOWN );
918             KEY( VK_HOME,   GLUT_KEY_HOME      );
919             KEY( VK_END,    GLUT_KEY_END       );
920             KEY( VK_LEFT,   GLUT_KEY_LEFT      );
921             KEY( VK_UP,     GLUT_KEY_UP        );
922             KEY( VK_RIGHT,  GLUT_KEY_RIGHT     );
923             KEY( VK_DOWN,   GLUT_KEY_DOWN      );
924             KEY( VK_INSERT, GLUT_KEY_INSERT    );
925
926           case VK_LCONTROL:  case VK_RCONTROL:  case VK_CONTROL:
927           case VK_LSHIFT:    case VK_RSHIFT:    case VK_SHIFT:
928           case VK_LMENU:     case VK_RMENU:     case VK_MENU:
929               /* These keypresses and releases are handled earlier in the function */
930               break;
931
932           case VK_DELETE:
933               /* The delete key should be treated as an ASCII keypress: */
934               INVOKE_WCB( *window, KeyboardUp,
935                           ( 127, window->State.MouseX, window->State.MouseY )
936               );
937               break;
938
939         default:
940         {
941 #if !defined(_WIN32_WCE)
942             BYTE state[ 256 ];
943             WORD code[ 2 ];
944
945             GetKeyboardState( state );
946
947             if( ToAscii( (UINT)wParam, 0, state, code, 0 ) == 1 )
948                 wParam=code[ 0 ];
949
950             INVOKE_WCB( *window, KeyboardUp,
951                         ( (char)wParam,
952                           window->State.MouseX, window->State.MouseY )
953             );
954 #endif /* !defined(_WIN32_WCE) */
955         }
956         }
957
958         if( keypress != -1 )
959             INVOKE_WCB( *window, SpecialUp,
960                         ( keypress,
961                           window->State.MouseX, window->State.MouseY )
962             );
963
964         fgState.Modifiers = INVALID_MODIFIERS;
965     }
966     break;
967
968     case WM_SYSCHAR:
969     case WM_CHAR:
970     {
971       if( (fgState.KeyRepeat==GLUT_KEY_REPEAT_OFF || window->State.IgnoreKeyRepeat==GL_TRUE) && (HIWORD(lParam) & KF_REPEAT) )
972             break;
973
974         fgState.Modifiers = fgPlatformGetModifiers( );
975         INVOKE_WCB( *window, Keyboard,
976                     ( (char)wParam,
977                       window->State.MouseX, window->State.MouseY )
978         );
979         fgState.Modifiers = INVALID_MODIFIERS;
980     }
981     break;
982
983     case WM_CAPTURECHANGED:
984         /* User has finished resizing the window, force a redraw */
985         INVOKE_WCB( *window, Display, ( ) );
986
987         /*lRet = DefWindowProc( hWnd, uMsg, wParam, lParam ); */
988         break;
989
990         /* Other messages that I have seen and which are not handled already */
991     case WM_SETTEXT:  /* 0x000c */
992         lRet = DefWindowProc( hWnd, uMsg, wParam, lParam );
993         /* Pass it on to "DefWindowProc" to set the window text */
994         break;
995
996     case WM_GETTEXT:  /* 0x000d */
997         /* Ideally we would copy the title of the window into "lParam" */
998         /* strncpy ( (char *)lParam, "Window Title", wParam );
999            lRet = ( wParam > 12 ) ? 12 : wParam;  */
1000         /* the number of characters copied */
1001         lRet = DefWindowProc( hWnd, uMsg, wParam, lParam );
1002         break;
1003
1004     case WM_GETTEXTLENGTH:  /* 0x000e */
1005         /* Ideally we would get the length of the title of the window */
1006         lRet = 12;
1007         /* the number of characters in "Window Title\0" (see above) */
1008         break;
1009
1010     case WM_ERASEBKGND:  /* 0x0014 */
1011         lRet = DefWindowProc( hWnd, uMsg, wParam, lParam );
1012         break;
1013
1014 #if !defined(_WIN32_WCE)
1015     case WM_SYNCPAINT:  /* 0x0088 */
1016         /* Another window has moved, need to update this one */
1017         window->State.Redisplay = GL_TRUE;
1018         lRet = DefWindowProc( hWnd, uMsg, wParam, lParam );
1019         /* Help screen says this message must be passed to "DefWindowProc" */
1020         break;
1021
1022     case WM_NCPAINT:  /* 0x0085 */
1023       /* Need to update the border of this window */
1024         lRet = DefWindowProc( hWnd, uMsg, wParam, lParam );
1025         /* Pass it on to "DefWindowProc" to repaint a standard border */
1026         break;
1027
1028     case WM_SYSCOMMAND :  /* 0x0112 */
1029         {
1030           /*
1031            * We have received a system command message.  Try to act on it.
1032            * The commands are passed in through the "wParam" parameter:
1033            * The least significant digit seems to be which edge of the window
1034            * is being used for a resize event:
1035            *     4  3  5
1036            *     1     2
1037            *     7  6  8
1038            * Congratulations and thanks to Richard Rauch for figuring this out..
1039            */
1040             switch ( wParam & 0xfff0 )
1041             {
1042             case SC_SIZE       :
1043                 break ;
1044
1045             case SC_MOVE       :
1046                 break ;
1047
1048             case SC_MINIMIZE   :
1049                 /* User has clicked on the "-" to minimize the window */
1050                 /* Turn off the visibility */
1051                 window->State.Visible = GL_FALSE ;
1052
1053                 break ;
1054
1055             case SC_MAXIMIZE   :
1056                 break ;
1057
1058             case SC_NEXTWINDOW :
1059                 break ;
1060
1061             case SC_PREVWINDOW :
1062                 break ;
1063
1064             case SC_CLOSE      :
1065                 /* Followed very closely by a WM_CLOSE message */
1066                 break ;
1067
1068             case SC_VSCROLL    :
1069                 break ;
1070
1071             case SC_HSCROLL    :
1072                 break ;
1073
1074             case SC_MOUSEMENU  :
1075                 break ;
1076
1077             case SC_KEYMENU    :
1078                 break ;
1079
1080             case SC_ARRANGE    :
1081                 break ;
1082
1083             case SC_RESTORE    :
1084                 break ;
1085
1086             case SC_TASKLIST   :
1087                 break ;
1088
1089             case SC_SCREENSAVE :
1090                 break ;
1091
1092             case SC_HOTKEY     :
1093                 break ;
1094
1095 #if(WINVER >= 0x0400)
1096             case SC_DEFAULT    :
1097                 break ;
1098
1099             case SC_MONITORPOWER    :
1100                 break ;
1101
1102             case SC_CONTEXTHELP    :
1103                 break ;
1104 #endif /* WINVER >= 0x0400 */
1105
1106             default:
1107 #if _DEBUG
1108                 fgWarning( "Unknown wParam type 0x%x", wParam );
1109 #endif
1110                 break;
1111             }
1112         }
1113 #endif /* !defined(_WIN32_WCE) */
1114
1115         /* We need to pass the message on to the operating system as well */
1116         lRet = DefWindowProc( hWnd, uMsg, wParam, lParam );
1117         break;
1118
1119 #ifdef WM_TOUCH
1120         /* handle multi-touch messages */
1121         case WM_TOUCH:
1122         {
1123                 unsigned int numInputs = (unsigned int)wParam;
1124                 unsigned int i = 0;
1125                 TOUCHINPUT* ti = (TOUCHINPUT*)malloc( sizeof(TOUCHINPUT)*numInputs);
1126
1127                 if (fghGetTouchInputInfo == (pGetTouchInputInfo)0xDEADBEEF) {
1128                     fghGetTouchInputInfo = (pGetTouchInputInfo)GetProcAddress(GetModuleHandle("user32"),"GetTouchInputInfo");
1129                     fghCloseTouchInputHandle = (pCloseTouchInputHandle)GetProcAddress(GetModuleHandle("user32"),"CloseTouchInputHandle");
1130                 }
1131
1132                 if (!fghGetTouchInputInfo) { 
1133                         free( (void*)ti );
1134                         break;
1135                 }
1136
1137                 if (fghGetTouchInputInfo( (HTOUCHINPUT)lParam, numInputs, ti, sizeof(TOUCHINPUT) )) {
1138                         /* Handle each contact point */
1139                         for (i = 0; i < numInputs; ++i ) {
1140
1141                                 POINT tp;
1142                                 tp.x = TOUCH_COORD_TO_PIXEL(ti[i].x);
1143                                 tp.y = TOUCH_COORD_TO_PIXEL(ti[i].y);
1144                                 ScreenToClient( hWnd, &tp );
1145
1146                                 ti[i].dwID = ti[i].dwID * 2;
1147
1148                                 if (ti[i].dwFlags & TOUCHEVENTF_DOWN) {
1149                                         INVOKE_WCB( *window, MultiEntry,  ( ti[i].dwID, GLUT_ENTERED ) );
1150                                         INVOKE_WCB( *window, MultiButton, ( ti[i].dwID, tp.x, tp.y, 0, GLUT_DOWN ) );
1151                                 } else if (ti[i].dwFlags & TOUCHEVENTF_MOVE) {
1152                                         INVOKE_WCB( *window, MultiMotion, ( ti[i].dwID, tp.x, tp.y ) );
1153                                 } else if (ti[i].dwFlags & TOUCHEVENTF_UP)   { 
1154                                         INVOKE_WCB( *window, MultiButton, ( ti[i].dwID, tp.x, tp.y, 0, GLUT_UP ) );
1155                                         INVOKE_WCB( *window, MultiEntry,  ( ti[i].dwID, GLUT_LEFT ) );
1156                                 }
1157                         }
1158                 }
1159                 fghCloseTouchInputHandle((HTOUCHINPUT)lParam);
1160                 free( (void*)ti );
1161                 lRet = 0; /*DefWindowProc( hWnd, uMsg, wParam, lParam );*/
1162                 break;
1163         }
1164 #endif
1165     default:
1166         /* Handle unhandled messages */
1167         lRet = DefWindowProc( hWnd, uMsg, wParam, lParam );
1168         break;
1169     }
1170
1171     return lRet;
1172 }