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