2 * freeglut_main_mswin.c
4 * The Windows-specific mouse cursor related stuff.
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
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:
17 * The above copyright notice and this permission notice shall be included
18 * in all copies or substantial portions of the Software.
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.
28 #include <GL/freeglut.h>
29 #include "../fg_internal.h"
32 extern void fghRedrawWindow ( SFG_Window *window );
34 extern void fgNewWGLCreateContext( SFG_Window* window );
35 extern GLboolean fgSetupPixelFormat( SFG_Window* window, GLboolean checkOnly,
36 unsigned char layer_type );
38 extern void fgPlatformCheckMenuDeactivate();
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;
48 typedef struct GXDisplayProperties GXDisplayProperties;
49 typedef struct GXKeyList GXKeyList;
52 typedef struct GXKeyList (*GXGETDEFAULTKEYS)(int);
53 typedef int (*GXOPENINPUT)();
55 GXGETDEFAULTKEYS GXGetDefaultKeys_ = NULL;
56 GXOPENINPUT GXOpenInput_ = NULL;
58 struct GXKeyList gxKeyList;
59 #endif /* _WIN32_WCE */
62 /* Get system time, taking special precautions against 32bit timer wrap.
63 We use timeGetTime and not GetTickCount because of its better stability,
64 and because we can increase its granularity (to 1 ms in
65 fgPlatformInitialize). For that reason we can't use GetTickCount64 which
66 wouldn't have the wrap issue.
67 Credit: this is based on code in glibc (https://mail.gnome.org/archives/commits-list/2011-November/msg04588.html)
69 static fg_time_t lastTime32 = 0;
70 static fg_time_t timeEpoch = 0;
71 void fgPlatformInitSystemTime()
73 #if defined(_WIN32_WCE)
74 lastTime32 = GetTickCount();
76 lastTime32 = timeGetTime();
79 fg_time_t fgPlatformSystemTime ( void )
82 #if defined(_WIN32_WCE)
83 currTime32 = GetTickCount();
85 currTime32 = timeGetTime();
87 /* Check if we just wrapped */
88 if (currTime32 < lastTime32)
91 lastTime32 = currTime32;
93 return currTime32 | timeEpoch << 32;
97 void fgPlatformSleepForEvents( fg_time_t msec )
99 MsgWaitForMultipleObjects( 0, NULL, FALSE, (DWORD) msec, QS_ALLINPUT );
103 void fgPlatformProcessSingleEvent ( void )
107 FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutMainLoopEvent" );
109 while( PeekMessage( &stMsg, NULL, 0, 0, PM_NOREMOVE ) )
111 if( GetMessage( &stMsg, NULL, 0, 0 ) == 0 )
113 if( fgState.ActionOnWindowClose == GLUT_ACTION_EXIT )
118 else if( fgState.ActionOnWindowClose == GLUT_ACTION_GLUTMAINLOOP_RETURNS )
119 fgState.ExecState = GLUT_EXEC_STATE_STOP;
124 TranslateMessage( &stMsg );
125 DispatchMessage( &stMsg );
131 void fgPlatformMainLoopPreliminaryWork ( void )
133 SFG_Window *window = (SFG_Window *)fgStructure.Windows.First ;
136 * Processing before the main loop: If there is a window which is open and
137 * which has a visibility callback, call it. I know this is an ugly hack,
138 * but I'm not sure what else to do about it. Ideally we should leave
139 * something uninitialized in the create window code and initialize it in
140 * the main loop, and have that initialization create a "WM_ACTIVATE"
141 * message. Then we would put the visibility callback code in the
142 * "case WM_ACTIVATE" block below. - John Fay -- 10/24/02
146 if ( FETCH_WCB( *window, Visibility ) )
148 SFG_Window *current_window = fgStructure.CurrentWindow ;
150 INVOKE_WCB( *window, Visibility, ( window->State.Visible ) );
151 fgSetWindow( current_window );
154 window = (SFG_Window *)window->Node.Next ;
160 * Determine a GLUT modifier mask based on MS-WINDOWS system info.
162 static int fgPlatformGetModifiers (void)
165 ( ( ( GetKeyState( VK_LSHIFT ) < 0 ) ||
166 ( GetKeyState( VK_RSHIFT ) < 0 )) ? GLUT_ACTIVE_SHIFT : 0 ) |
167 ( ( ( GetKeyState( VK_LCONTROL ) < 0 ) ||
168 ( GetKeyState( VK_RCONTROL ) < 0 )) ? GLUT_ACTIVE_CTRL : 0 ) |
169 ( ( ( GetKeyState( VK_LMENU ) < 0 ) ||
170 ( GetKeyState( VK_RMENU ) < 0 )) ? GLUT_ACTIVE_ALT : 0 );
173 static LRESULT fghWindowProcKeyPress(SFG_Window *window, UINT uMsg, GLboolean keydown, WPARAM wParam, LPARAM lParam)
175 static unsigned char lControl = 0, lShift = 0, lAlt = 0,
176 rControl = 0, rShift = 0, rAlt = 0;
181 /* if keydown, check for repeat */
182 if( keydown && ( fgState.KeyRepeat==GLUT_KEY_REPEAT_OFF || window->State.IgnoreKeyRepeat==GL_TRUE ) && (HIWORD(lParam) & KF_REPEAT) )
185 /* Remember the current modifiers state so user can query it from their callback */
186 fgState.Modifiers = fgPlatformGetModifiers( );
188 /* Get mouse position roughly at time of keypress */
189 GetCursorPos( &mouse_pos );
190 ScreenToClient( window->Window.Handle, &mouse_pos );
191 window->State.MouseX = mouse_pos.x;
192 window->State.MouseY = mouse_pos.y;
194 /* Convert the Win32 keystroke codes to GLUTtish way */
195 # define KEY(a,b) case a: keypress = b; break;
199 KEY( VK_F1, GLUT_KEY_F1 );
200 KEY( VK_F2, GLUT_KEY_F2 );
201 KEY( VK_F3, GLUT_KEY_F3 );
202 KEY( VK_F4, GLUT_KEY_F4 );
203 KEY( VK_F5, GLUT_KEY_F5 );
204 KEY( VK_F6, GLUT_KEY_F6 );
205 KEY( VK_F7, GLUT_KEY_F7 );
206 KEY( VK_F8, GLUT_KEY_F8 );
207 KEY( VK_F9, GLUT_KEY_F9 );
208 KEY( VK_F10, GLUT_KEY_F10 );
209 KEY( VK_F11, GLUT_KEY_F11 );
210 KEY( VK_F12, GLUT_KEY_F12 );
211 KEY( VK_PRIOR, GLUT_KEY_PAGE_UP );
212 KEY( VK_NEXT, GLUT_KEY_PAGE_DOWN );
213 KEY( VK_HOME, GLUT_KEY_HOME );
214 KEY( VK_END, GLUT_KEY_END );
215 KEY( VK_LEFT, GLUT_KEY_LEFT );
216 KEY( VK_UP, GLUT_KEY_UP );
217 KEY( VK_RIGHT, GLUT_KEY_RIGHT );
218 KEY( VK_DOWN, GLUT_KEY_DOWN );
219 KEY( VK_INSERT, GLUT_KEY_INSERT );
221 /* handle control, alt and shift. For GLUT, we want to distinguish between left and right presses.
222 * The VK_L* & VK_R* left and right Alt, Ctrl and Shift virtual keys are however only used as parameters to GetAsyncKeyState() and GetKeyState()
223 * so when we get an alt, shift or control keypress here, we manually check whether it was the left or the right
225 #define ASYNC_KEY_EVENT(winKey,glutKey,keyStateVar)\
226 if (!keyStateVar && GetAsyncKeyState ( winKey ))\
231 else if (keyStateVar && !GetAsyncKeyState ( winKey ))\
237 ASYNC_KEY_EVENT(VK_LCONTROL,GLUT_KEY_CTRL_L,lControl);
238 ASYNC_KEY_EVENT(VK_RCONTROL,GLUT_KEY_CTRL_R,rControl);
241 ASYNC_KEY_EVENT(VK_LSHIFT,GLUT_KEY_SHIFT_L,lShift);
242 ASYNC_KEY_EVENT(VK_RSHIFT,GLUT_KEY_SHIFT_R,rShift);
245 ASYNC_KEY_EVENT(VK_LMENU,GLUT_KEY_ALT_L,lAlt);
246 ASYNC_KEY_EVENT(VK_RMENU,GLUT_KEY_ALT_R,rAlt);
248 #undef ASYNC_KEY_EVENT
251 /* The delete key should be treated as an ASCII keypress: */
253 INVOKE_WCB( *window, Keyboard,
254 ( 127, window->State.MouseX, window->State.MouseY )
257 INVOKE_WCB( *window, KeyboardUp,
258 ( 127, window->State.MouseX, window->State.MouseY )
262 #if !defined(_WIN32_WCE)
264 /* keydown displayable characters are handled with WM_CHAR message, but no corresponding up is generated. So get that here. */
270 GetKeyboardState( state );
272 if( ToAscii( (UINT)wParam, 0, state, code, 0 ) == 1 )
275 INVOKE_WCB( *window, KeyboardUp,
277 window->State.MouseX, window->State.MouseY )
283 #if defined(_WIN32_WCE)
284 if(keydown && !(lParam & 0x40000000)) /* Prevent auto-repeat */
286 if(wParam==(unsigned)gxKeyList.vkRight)
287 keypress = GLUT_KEY_RIGHT;
288 else if(wParam==(unsigned)gxKeyList.vkLeft)
289 keypress = GLUT_KEY_LEFT;
290 else if(wParam==(unsigned)gxKeyList.vkUp)
291 keypress = GLUT_KEY_UP;
292 else if(wParam==(unsigned)gxKeyList.vkDown)
293 keypress = GLUT_KEY_DOWN;
294 else if(wParam==(unsigned)gxKeyList.vkA)
295 keypress = GLUT_KEY_F1;
296 else if(wParam==(unsigned)gxKeyList.vkB)
297 keypress = GLUT_KEY_F2;
298 else if(wParam==(unsigned)gxKeyList.vkC)
299 keypress = GLUT_KEY_F3;
300 else if(wParam==(unsigned)gxKeyList.vkStart)
301 keypress = GLUT_KEY_F4;
307 INVOKE_WCB( *window, Special,
309 window->State.MouseX, window->State.MouseY )
312 INVOKE_WCB( *window, SpecialUp,
314 window->State.MouseX, window->State.MouseY )
317 fgState.Modifiers = INVALID_MODIFIERS;
319 /* SYSKEY events should be sent to default window proc for system to handle them */
320 if (uMsg==WM_SYSKEYDOWN || uMsg==WM_SYSKEYUP)
321 return DefWindowProc( window->Window.Handle, uMsg, wParam, lParam );
326 void fghWindowUnderCursor(SFG_Window *window, SFG_Window **child_window)
328 /* Check if the current window that the mouse is over is a child window
329 * of the window the message was sent to.
331 if (window && window->Children.First)
334 SFG_WindowHandleType hwnd;
335 SFG_Window* temp_window;
337 GetCursorPos( &mouse_pos );
338 ScreenToClient( window->Window.Handle, &mouse_pos );
339 hwnd = ChildWindowFromPoint(window->Window.Handle, mouse_pos);
340 if (hwnd && hwnd!=window->Window.Handle) /* can be NULL if mouse outside parent by the time we get here, or can be same as parent if we didn't find a child */
342 temp_window = fgWindowByHandle(hwnd);
343 if (temp_window) /* Verify we got a FreeGLUT window */
345 *child_window = temp_window;
346 /* ChildWindowFromPoint only searches immediate children, so search again to see if actually in grandchild or further descendant */
347 fghWindowUnderCursor(temp_window,child_window);
354 * The window procedure for handling Win32 events
356 LRESULT CALLBACK fgPlatformWindowProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam )
358 SFG_Window *window, *child_window = NULL;
362 FREEGLUT_INTERNAL_ERROR_EXIT_IF_NOT_INITIALISED ( "Event Handler" ) ;
364 window = fgWindowByHandle( hWnd );
366 if ( ( window == NULL ) && ( uMsg != WM_CREATE ) )
367 return DefWindowProc( hWnd, uMsg, wParam, lParam );
369 /* printf ( "Window %3d message <%04x> %12d %12d\n", window?window->ID:0,
370 uMsg, wParam, lParam ); */
372 /* Some events only sent to main window. Check if the current window that
373 * the mouse is over is a child window. Below when handling some messages,
374 * we make sure that we process callbacks on the child window instead.
375 * This mirrors how GLUT does things.
377 fghWindowUnderCursor(window, &child_window);
382 /* The window structure is passed as the creation structure parameter... */
383 window = (SFG_Window *) (((LPCREATESTRUCT) lParam)->lpCreateParams);
384 FREEGLUT_INTERNAL_ERROR_EXIT ( ( window != NULL ), "Cannot create window",
385 "fgPlatformWindowProc" );
387 window->Window.Handle = hWnd;
388 window->Window.pContext.Device = GetDC( hWnd );
391 unsigned int current_DisplayMode = fgState.DisplayMode;
392 fgState.DisplayMode = GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH;
393 #if !defined(_WIN32_WCE)
394 fgSetupPixelFormat( window, GL_FALSE, PFD_MAIN_PLANE );
396 fgState.DisplayMode = current_DisplayMode;
398 if( fgStructure.MenuContext )
399 wglMakeCurrent( window->Window.pContext.Device,
400 fgStructure.MenuContext->MContext
404 fgStructure.MenuContext =
405 (SFG_MenuContext *)malloc( sizeof(SFG_MenuContext) );
406 fgStructure.MenuContext->MContext =
407 wglCreateContext( window->Window.pContext.Device );
410 /* window->Window.Context = wglGetCurrentContext (); */
411 window->Window.Context = wglCreateContext( window->Window.pContext.Device );
415 #if !defined(_WIN32_WCE)
416 fgSetupPixelFormat( window, GL_FALSE, PFD_MAIN_PLANE );
419 if( ! fgState.UseCurrentContext )
420 window->Window.Context =
421 wglCreateContext( window->Window.pContext.Device );
424 window->Window.Context = wglGetCurrentContext( );
425 if( ! window->Window.Context )
426 window->Window.Context =
427 wglCreateContext( window->Window.pContext.Device );
430 #if !defined(_WIN32_WCE)
431 fgNewWGLCreateContext( window );
435 window->State.NeedToResize = GL_TRUE;
436 /* if we used CW_USEDEFAULT (thats a negative value) for the size
437 * of the window, query the window now for the size at which it
440 if( ( window->State.Width < 0 ) || ( window->State.Height < 0 ) )
442 SFG_Window *current_window = fgStructure.CurrentWindow;
444 fgSetWindow( window );
445 window->State.Width = glutGet( GLUT_WINDOW_WIDTH );
446 window->State.Height = glutGet( GLUT_WINDOW_HEIGHT );
447 fgSetWindow( current_window );
450 ReleaseDC( window->Window.Handle, window->Window.pContext.Device );
452 #if defined(_WIN32_WCE)
453 /* Take over button handling */
455 HINSTANCE dxDllLib=LoadLibrary(_T("gx.dll"));
458 GXGetDefaultKeys_=(GXGETDEFAULTKEYS)GetProcAddress(dxDllLib, _T("?GXGetDefaultKeys@@YA?AUGXKeyList@@H@Z"));
459 GXOpenInput_=(GXOPENINPUT)GetProcAddress(dxDllLib, _T("?GXOpenInput@@YAHXZ"));
464 if(GXGetDefaultKeys_)
465 gxKeyList = (*GXGetDefaultKeys_)(GX_LANDSCAPEKEYS);
468 #endif /* defined(_WIN32_WCE) */
473 * If the window is visible, then it is the user manually resizing it.
474 * If it is not, then it is the system sending us a dummy resize with
475 * zero dimensions on a "glutIconifyWindow" call.
477 if( window->State.Visible )
479 /* get old values first to compare to below */
480 int width = window->State.Width, height=window->State.Height;
481 #if defined(_WIN32_WCE)
482 window->State.Width = HIWORD(lParam);
483 window->State.Height = LOWORD(lParam);
485 window->State.Width = LOWORD(lParam);
486 window->State.Height = HIWORD(lParam);
487 #endif /* defined(_WIN32_WCE) */
489 if (width!=window->State.Width || height!=window->State.Height)
490 /* Something changed, need to resize */
491 window->State.NeedToResize = GL_TRUE;
498 SFG_Window* saved_window = fgStructure.CurrentWindow;
500 GetWindowRect( window->Window.Handle, &windowRect );
504 /* For child window, we should return relative to upper-left
505 * of parent's client area.
507 POINT topleft = {windowRect.left,windowRect.top};
509 ScreenToClient(window->Parent->Window.Handle,&topleft);
510 windowRect.left = topleft.x;
511 windowRect.top = topleft.y;
514 INVOKE_WCB( *window, Position, ( windowRect.left, windowRect.top ) );
515 fgSetWindow(saved_window);
520 /* printf("WM_SETFOCUS: %p\n", window ); */
522 lRet = DefWindowProc( hWnd, uMsg, wParam, lParam );
526 /* If we're dealing with a child window, make sure it has input focus instead, set it here. */
527 SetFocus(child_window->Window.Handle);
528 SetActiveWindow( child_window->Window.Handle );
529 INVOKE_WCB( *child_window, Entry, ( GLUT_ENTERED ) );
530 UpdateWindow ( child_window->Window.Handle );
534 SetActiveWindow( window->Window.Handle );
535 INVOKE_WCB( *window, Entry, ( GLUT_ENTERED ) );
537 /* Always request update on main window to be safe */
538 UpdateWindow ( hWnd );
544 SFG_Window* saved_window = fgStructure.CurrentWindow;
545 /* printf("WM_KILLFOCUS: %p\n", window ); */
546 lRet = DefWindowProc( hWnd, uMsg, wParam, lParam );
547 INVOKE_WCB( *window, Entry, ( GLUT_LEFT ) );
548 fgSetWindow(saved_window);
550 /* Check if there are any open menus that need to be closed */
551 fgPlatformCheckMenuDeactivate();
557 if (LOWORD(wParam) != WA_INACTIVE)
559 /* printf("WM_ACTIVATE: fgSetCursor( %p, %d)\n", window,
560 window->State.Cursor ); */
561 fgSetCursor( window, window->State.Cursor );
564 lRet = DefWindowProc( hWnd, uMsg, wParam, lParam );
569 /* printf ( "Cursor event %x %x %x %x\n", window, window->State.Cursor, lParam, wParam ) ; */
570 if( LOWORD( lParam ) == HTCLIENT )
571 fgSetCursor ( window, window->State.Cursor ) ;
573 lRet = DefWindowProc( hWnd, uMsg, wParam, lParam );
577 window->State.Visible = GL_TRUE;
578 window->State.Redisplay = GL_TRUE;
582 /* Turn on the visibility in case it was turned off somehow */
583 window->State.Visible = GL_TRUE;
584 InvalidateRect( hWnd, NULL, GL_FALSE ); /* Make sure whole window is repainted. Bit of a hack, but a safe one from what google turns up... */
585 BeginPaint( hWnd, &ps );
586 fghRedrawWindow( window );
587 EndPaint( hWnd, &ps );
591 fgDestroyWindow ( window );
592 if ( fgState.ActionOnWindowClose != GLUT_ACTION_CONTINUE_EXECUTION )
598 * The window already got destroyed, so don't bother with it.
604 #if defined(_WIN32_WCE)
605 window->State.MouseX = 320-HIWORD( lParam );
606 window->State.MouseY = LOWORD( lParam );
608 window->State.MouseX = LOWORD( lParam );
609 window->State.MouseY = HIWORD( lParam );
610 #endif /* defined(_WIN32_WCE) */
611 /* Restrict to [-32768, 32767] to match X11 behaviour */
612 /* See comment in "freeglut_developer" mailing list 10/4/04 */
613 if ( window->State.MouseX > 32767 ) window->State.MouseX -= 65536;
614 if ( window->State.MouseY > 32767 ) window->State.MouseY -= 65536;
616 if ( window->ActiveMenu )
618 fgUpdateMenuHighlight( window->ActiveMenu );
622 fgState.Modifiers = fgPlatformGetModifiers( );
624 if( ( wParam & MK_LBUTTON ) ||
625 ( wParam & MK_MBUTTON ) ||
626 ( wParam & MK_RBUTTON ) )
627 INVOKE_WCB( *window, Motion, ( window->State.MouseX,
628 window->State.MouseY ) );
630 INVOKE_WCB( *window, Passive, ( window->State.MouseX,
631 window->State.MouseY ) );
633 fgState.Modifiers = INVALID_MODIFIERS;
644 GLboolean pressed = GL_TRUE;
647 #if defined(_WIN32_WCE)
648 window->State.MouseX = 320-HIWORD( lParam );
649 window->State.MouseY = LOWORD( lParam );
651 window->State.MouseX = LOWORD( lParam );
652 window->State.MouseY = HIWORD( lParam );
653 #endif /* defined(_WIN32_WCE) */
655 /* Restrict to [-32768, 32767] to match X11 behaviour */
656 /* See comment in "freeglut_developer" mailing list 10/4/04 */
657 if ( window->State.MouseX > 32767 ) window->State.MouseX -= 65536;
658 if ( window->State.MouseY > 32767 ) window->State.MouseY -= 65536;
664 button = GLUT_LEFT_BUTTON;
668 button = GLUT_MIDDLE_BUTTON;
672 button = GLUT_RIGHT_BUTTON;
676 button = GLUT_LEFT_BUTTON;
680 button = GLUT_MIDDLE_BUTTON;
684 button = GLUT_RIGHT_BUTTON;
692 #if !defined(_WIN32_WCE)
693 if( GetSystemMetrics( SM_SWAPBUTTON ) )
695 if( button == GLUT_LEFT_BUTTON )
696 button = GLUT_RIGHT_BUTTON;
698 if( button == GLUT_RIGHT_BUTTON )
699 button = GLUT_LEFT_BUTTON;
701 #endif /* !defined(_WIN32_WCE) */
704 return DefWindowProc( hWnd, uMsg, lParam, wParam );
707 * Do not execute the application's mouse callback if a menu
708 * is hooked to this button. In that case an appropriate
709 * private call should be generated.
711 if( fgCheckActiveMenu( window, button, pressed,
712 window->State.MouseX, window->State.MouseY ) )
715 /* Set capture so that the window captures all the mouse messages */
717 * XXX - Multiple button support: Under X11, the mouse is not released
718 * XXX - from the window until all buttons have been released, even if the
719 * XXX - user presses a button in another window. This will take more
720 * XXX - code changes than I am up to at the moment (10/5/04). The present
721 * XXX - is a 90 percent solution.
723 if ( pressed == GL_TRUE )
724 SetCapture ( window->Window.Handle ) ;
728 if( ! FETCH_WCB( *window, Mouse ) )
731 fgSetWindow( window );
732 fgState.Modifiers = fgPlatformGetModifiers( );
737 pressed ? GLUT_DOWN : GLUT_UP,
738 window->State.MouseX,
743 fgState.Modifiers = INVALID_MODIFIERS;
749 int wheel_number = LOWORD( wParam );
750 short ticks = ( short )HIWORD( wParam );
751 fgState.MouseWheelTicks += ticks;
753 if ( abs ( fgState.MouseWheelTicks ) >= WHEEL_DELTA )
755 int direction = ( fgState.MouseWheelTicks > 0 ) ? 1 : -1;
757 if( ! FETCH_WCB( *window, MouseWheel ) &&
758 ! FETCH_WCB( *window, Mouse ) )
761 fgSetWindow( window );
762 fgState.Modifiers = fgPlatformGetModifiers( );
764 while( abs ( fgState.MouseWheelTicks ) >= WHEEL_DELTA )
766 if( FETCH_WCB( *window, MouseWheel ) )
767 INVOKE_WCB( *window, MouseWheel,
770 window->State.MouseX,
774 else /* No mouse wheel, call the mouse button callback twice */
777 * Map wheel zero to button 3 and 4; +1 to 3, -1 to 4
778 * " " one +1 to 5, -1 to 6, ...
780 * XXX The below assumes that you have no more than 3 mouse
781 * XXX buttons. Sorry.
783 int button = wheel_number * 2 + 3;
786 INVOKE_WCB( *window, Mouse,
788 window->State.MouseX, window->State.MouseY )
790 INVOKE_WCB( *window, Mouse,
792 window->State.MouseX, window->State.MouseY )
796 fgState.MouseWheelTicks -= WHEEL_DELTA * direction;
799 fgState.Modifiers = INVALID_MODIFIERS;
807 window = child_window;
808 lRet = fghWindowProcKeyPress(window,uMsg,GL_TRUE,wParam,lParam);
814 window = child_window;
815 lRet = fghWindowProcKeyPress(window,uMsg,GL_FALSE,wParam,lParam);
822 window = child_window;
824 if( (fgState.KeyRepeat==GLUT_KEY_REPEAT_OFF || window->State.IgnoreKeyRepeat==GL_TRUE) && (HIWORD(lParam) & KF_REPEAT) )
827 fgState.Modifiers = fgPlatformGetModifiers( );
828 INVOKE_WCB( *window, Keyboard,
830 window->State.MouseX, window->State.MouseY )
832 fgState.Modifiers = INVALID_MODIFIERS;
836 case WM_CAPTURECHANGED:
837 /* User has finished resizing the window, force a redraw */
838 INVOKE_WCB( *window, Display, ( ) );
840 /*lRet = DefWindowProc( hWnd, uMsg, wParam, lParam ); */
843 /* Other messages that I have seen and which are not handled already */
844 case WM_SETTEXT: /* 0x000c */
845 lRet = DefWindowProc( hWnd, uMsg, wParam, lParam );
846 /* Pass it on to "DefWindowProc" to set the window text */
849 case WM_GETTEXT: /* 0x000d */
850 /* Ideally we would copy the title of the window into "lParam" */
851 /* strncpy ( (char *)lParam, "Window Title", wParam );
852 lRet = ( wParam > 12 ) ? 12 : wParam; */
853 /* the number of characters copied */
854 lRet = DefWindowProc( hWnd, uMsg, wParam, lParam );
857 case WM_GETTEXTLENGTH: /* 0x000e */
858 /* Ideally we would get the length of the title of the window */
860 /* the number of characters in "Window Title\0" (see above) */
863 case WM_ERASEBKGND: /* 0x0014 */
864 lRet = DefWindowProc( hWnd, uMsg, wParam, lParam );
867 #if !defined(_WIN32_WCE)
868 case WM_SYNCPAINT: /* 0x0088 */
869 /* Another window has moved, need to update this one */
870 window->State.Redisplay = GL_TRUE;
871 lRet = DefWindowProc( hWnd, uMsg, wParam, lParam );
872 /* Help screen says this message must be passed to "DefWindowProc" */
875 case WM_NCPAINT: /* 0x0085 */
876 /* Need to update the border of this window */
877 lRet = DefWindowProc( hWnd, uMsg, wParam, lParam );
878 /* Pass it on to "DefWindowProc" to repaint a standard border */
881 case WM_SYSCOMMAND : /* 0x0112 */
884 * We have received a system command message. Try to act on it.
885 * The commands are passed in through the "wParam" parameter:
886 * The least significant digit seems to be which edge of the window
887 * is being used for a resize event:
891 * Congratulations and thanks to Richard Rauch for figuring this out..
893 switch ( wParam & 0xfff0 )
902 /* User has clicked on the "-" to minimize the window */
903 /* Turn off the visibility */
904 window->State.Visible = GL_FALSE ;
918 /* Followed very closely by a WM_CLOSE message */
948 #if(WINVER >= 0x0400)
952 case SC_MONITORPOWER :
955 case SC_CONTEXTHELP :
957 #endif /* WINVER >= 0x0400 */
961 fgWarning( "Unknown wParam type 0x%x", wParam );
966 #endif /* !defined(_WIN32_WCE) */
968 /* We need to pass the message on to the operating system as well */
969 lRet = DefWindowProc( hWnd, uMsg, wParam, lParam );
973 /* handle multi-touch messages */
976 unsigned int numInputs = (unsigned int)wParam;
978 TOUCHINPUT* ti = (TOUCHINPUT*)malloc( sizeof(TOUCHINPUT)*numInputs);
980 if (fghGetTouchInputInfo == (pGetTouchInputInfo)0xDEADBEEF) {
981 fghGetTouchInputInfo = (pGetTouchInputInfo)GetProcAddress(GetModuleHandle("user32"),"GetTouchInputInfo");
982 fghCloseTouchInputHandle = (pCloseTouchInputHandle)GetProcAddress(GetModuleHandle("user32"),"CloseTouchInputHandle");
985 if (!fghGetTouchInputInfo) {
990 if (fghGetTouchInputInfo( (HTOUCHINPUT)lParam, numInputs, ti, sizeof(TOUCHINPUT) )) {
991 /* Handle each contact point */
992 for (i = 0; i < numInputs; ++i ) {
995 tp.x = TOUCH_COORD_TO_PIXEL(ti[i].x);
996 tp.y = TOUCH_COORD_TO_PIXEL(ti[i].y);
997 ScreenToClient( hWnd, &tp );
999 ti[i].dwID = ti[i].dwID * 2;
1001 if (ti[i].dwFlags & TOUCHEVENTF_DOWN) {
1002 INVOKE_WCB( *window, MultiEntry, ( ti[i].dwID, GLUT_ENTERED ) );
1003 INVOKE_WCB( *window, MultiButton, ( ti[i].dwID, tp.x, tp.y, 0, GLUT_DOWN ) );
1004 } else if (ti[i].dwFlags & TOUCHEVENTF_MOVE) {
1005 INVOKE_WCB( *window, MultiMotion, ( ti[i].dwID, tp.x, tp.y ) );
1006 } else if (ti[i].dwFlags & TOUCHEVENTF_UP) {
1007 INVOKE_WCB( *window, MultiButton, ( ti[i].dwID, tp.x, tp.y, 0, GLUT_UP ) );
1008 INVOKE_WCB( *window, MultiEntry, ( ti[i].dwID, GLUT_LEFT ) );
1012 fghCloseTouchInputHandle((HTOUCHINPUT)lParam);
1014 lRet = 0; /*DefWindowProc( hWnd, uMsg, wParam, lParam );*/
1019 /* Handle unhandled messages */
1020 lRet = DefWindowProc( hWnd, uMsg, wParam, lParam );