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