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 );
327 * The window procedure for handling Win32 events
329 LRESULT CALLBACK fgPlatformWindowProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam )
331 SFG_Window *window, *child_window = NULL;
335 FREEGLUT_INTERNAL_ERROR_EXIT_IF_NOT_INITIALISED ( "Event Handler" ) ;
337 window = fgWindowByHandle( hWnd );
339 if ( ( window == NULL ) && ( uMsg != WM_CREATE ) )
340 return DefWindowProc( hWnd, uMsg, wParam, lParam );
342 /* printf ( "Window %3d message <%04x> %12d %12d\n", window?window->ID:0,
343 uMsg, wParam, lParam ); */
345 /* Some events only sent to main window. Check if the current window that
346 * the mouse is over is a child window. Below when handling some messages,
347 * we make sure that we process callbacks on the child window instead.
348 * This mirrors how GLUT does things.
350 if (window && window->Children.First)
353 SFG_WindowHandleType hwnd;
354 SFG_Window* temp_window;
356 GetCursorPos( &mouse_pos );
357 ScreenToClient( window->Window.Handle, &mouse_pos );
358 hwnd = ChildWindowFromPoint(window->Window.Handle, mouse_pos);
359 if (hwnd) /* can be NULL if mouse outside parent by the time we get here */
361 temp_window = fgWindowByHandle(hwnd);
362 if (temp_window && temp_window->Parent) /* Verify we got a child window */
363 child_window = temp_window;
370 /* The window structure is passed as the creation structure parameter... */
371 window = (SFG_Window *) (((LPCREATESTRUCT) lParam)->lpCreateParams);
372 FREEGLUT_INTERNAL_ERROR_EXIT ( ( window != NULL ), "Cannot create window",
373 "fgPlatformWindowProc" );
375 window->Window.Handle = hWnd;
376 window->Window.pContext.Device = GetDC( hWnd );
379 unsigned int current_DisplayMode = fgState.DisplayMode;
380 fgState.DisplayMode = GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH;
381 #if !defined(_WIN32_WCE)
382 fgSetupPixelFormat( window, GL_FALSE, PFD_MAIN_PLANE );
384 fgState.DisplayMode = current_DisplayMode;
386 if( fgStructure.MenuContext )
387 wglMakeCurrent( window->Window.pContext.Device,
388 fgStructure.MenuContext->MContext
392 fgStructure.MenuContext =
393 (SFG_MenuContext *)malloc( sizeof(SFG_MenuContext) );
394 fgStructure.MenuContext->MContext =
395 wglCreateContext( window->Window.pContext.Device );
398 /* window->Window.Context = wglGetCurrentContext (); */
399 window->Window.Context = wglCreateContext( window->Window.pContext.Device );
403 #if !defined(_WIN32_WCE)
404 fgSetupPixelFormat( window, GL_FALSE, PFD_MAIN_PLANE );
407 if( ! fgState.UseCurrentContext )
408 window->Window.Context =
409 wglCreateContext( window->Window.pContext.Device );
412 window->Window.Context = wglGetCurrentContext( );
413 if( ! window->Window.Context )
414 window->Window.Context =
415 wglCreateContext( window->Window.pContext.Device );
418 #if !defined(_WIN32_WCE)
419 fgNewWGLCreateContext( window );
423 window->State.NeedToResize = GL_TRUE;
424 /* if we used CW_USEDEFAULT (thats a negative value) for the size
425 * of the window, query the window now for the size at which it
428 if( ( window->State.Width < 0 ) || ( window->State.Height < 0 ) )
430 SFG_Window *current_window = fgStructure.CurrentWindow;
432 fgSetWindow( window );
433 window->State.Width = glutGet( GLUT_WINDOW_WIDTH );
434 window->State.Height = glutGet( GLUT_WINDOW_HEIGHT );
435 fgSetWindow( current_window );
438 ReleaseDC( window->Window.Handle, window->Window.pContext.Device );
440 #if defined(_WIN32_WCE)
441 /* Take over button handling */
443 HINSTANCE dxDllLib=LoadLibrary(_T("gx.dll"));
446 GXGetDefaultKeys_=(GXGETDEFAULTKEYS)GetProcAddress(dxDllLib, _T("?GXGetDefaultKeys@@YA?AUGXKeyList@@H@Z"));
447 GXOpenInput_=(GXOPENINPUT)GetProcAddress(dxDllLib, _T("?GXOpenInput@@YAHXZ"));
452 if(GXGetDefaultKeys_)
453 gxKeyList = (*GXGetDefaultKeys_)(GX_LANDSCAPEKEYS);
456 #endif /* defined(_WIN32_WCE) */
461 * If the window is visible, then it is the user manually resizing it.
462 * If it is not, then it is the system sending us a dummy resize with
463 * zero dimensions on a "glutIconifyWindow" call.
465 if( window->State.Visible )
467 /* get old values first to compare to below */
468 int width = window->State.Width, height=window->State.Height;
469 #if defined(_WIN32_WCE)
470 window->State.Width = HIWORD(lParam);
471 window->State.Height = LOWORD(lParam);
473 window->State.Width = LOWORD(lParam);
474 window->State.Height = HIWORD(lParam);
475 #endif /* defined(_WIN32_WCE) */
477 if (width!=window->State.Width || height!=window->State.Height)
478 /* Something changed, need to resize */
479 window->State.NeedToResize = GL_TRUE;
486 SFG_Window* saved_window = fgStructure.CurrentWindow;
488 GetWindowRect( window->Window.Handle, &windowRect );
492 /* For child window, we should return relative to upper-left
493 * of parent's client area.
495 POINT topleft = {windowRect.left,windowRect.top};
497 ScreenToClient(window->Parent->Window.Handle,&topleft);
498 windowRect.left = topleft.x;
499 windowRect.top = topleft.y;
502 INVOKE_WCB( *window, Position, ( windowRect.left, windowRect.top ) );
503 fgSetWindow(saved_window);
508 /* printf("WM_SETFOCUS: %p\n", window ); */
510 lRet = DefWindowProc( hWnd, uMsg, wParam, lParam );
514 /* If we're dealing with a child window, make sure it has input focus instead, set it here. */
515 SetFocus(child_window->Window.Handle);
516 SetActiveWindow( child_window->Window.Handle );
517 INVOKE_WCB( *child_window, Entry, ( GLUT_ENTERED ) );
518 UpdateWindow ( child_window->Window.Handle );
522 SetActiveWindow( window->Window.Handle );
523 INVOKE_WCB( *window, Entry, ( GLUT_ENTERED ) );
525 /* Always request update on main window to be safe */
526 UpdateWindow ( hWnd );
532 SFG_Window* saved_window = fgStructure.CurrentWindow;
533 /* printf("WM_KILLFOCUS: %p\n", window ); */
534 lRet = DefWindowProc( hWnd, uMsg, wParam, lParam );
535 INVOKE_WCB( *window, Entry, ( GLUT_LEFT ) );
536 fgSetWindow(saved_window);
538 /* Check if there are any open menus that need to be closed */
539 fgPlatformCheckMenuDeactivate();
545 if (LOWORD(wParam) != WA_INACTIVE)
547 /* printf("WM_ACTIVATE: fgSetCursor( %p, %d)\n", window,
548 window->State.Cursor ); */
549 fgSetCursor( window, window->State.Cursor );
552 lRet = DefWindowProc( hWnd, uMsg, wParam, lParam );
557 /* printf ( "Cursor event %x %x %x %x\n", window, window->State.Cursor, lParam, wParam ) ; */
558 if( LOWORD( lParam ) == HTCLIENT )
559 fgSetCursor ( window, window->State.Cursor ) ;
561 lRet = DefWindowProc( hWnd, uMsg, wParam, lParam );
565 window->State.Visible = GL_TRUE;
566 window->State.Redisplay = GL_TRUE;
570 /* Turn on the visibility in case it was turned off somehow */
571 window->State.Visible = GL_TRUE;
572 InvalidateRect( hWnd, NULL, GL_FALSE ); /* Make sure whole window is repainted. Bit of a hack, but a safe one from what google turns up... */
573 BeginPaint( hWnd, &ps );
574 fghRedrawWindow( window );
575 EndPaint( hWnd, &ps );
579 fgDestroyWindow ( window );
580 if ( fgState.ActionOnWindowClose != GLUT_ACTION_CONTINUE_EXECUTION )
586 * The window already got destroyed, so don't bother with it.
592 #if defined(_WIN32_WCE)
593 window->State.MouseX = 320-HIWORD( lParam );
594 window->State.MouseY = LOWORD( lParam );
596 window->State.MouseX = LOWORD( lParam );
597 window->State.MouseY = HIWORD( lParam );
598 #endif /* defined(_WIN32_WCE) */
599 /* Restrict to [-32768, 32767] to match X11 behaviour */
600 /* See comment in "freeglut_developer" mailing list 10/4/04 */
601 if ( window->State.MouseX > 32767 ) window->State.MouseX -= 65536;
602 if ( window->State.MouseY > 32767 ) window->State.MouseY -= 65536;
604 if ( window->ActiveMenu )
606 fgUpdateMenuHighlight( window->ActiveMenu );
610 fgState.Modifiers = fgPlatformGetModifiers( );
612 if( ( wParam & MK_LBUTTON ) ||
613 ( wParam & MK_MBUTTON ) ||
614 ( wParam & MK_RBUTTON ) )
615 INVOKE_WCB( *window, Motion, ( window->State.MouseX,
616 window->State.MouseY ) );
618 INVOKE_WCB( *window, Passive, ( window->State.MouseX,
619 window->State.MouseY ) );
621 fgState.Modifiers = INVALID_MODIFIERS;
632 GLboolean pressed = GL_TRUE;
635 #if defined(_WIN32_WCE)
636 window->State.MouseX = 320-HIWORD( lParam );
637 window->State.MouseY = LOWORD( lParam );
639 window->State.MouseX = LOWORD( lParam );
640 window->State.MouseY = HIWORD( lParam );
641 #endif /* defined(_WIN32_WCE) */
643 /* Restrict to [-32768, 32767] to match X11 behaviour */
644 /* See comment in "freeglut_developer" mailing list 10/4/04 */
645 if ( window->State.MouseX > 32767 ) window->State.MouseX -= 65536;
646 if ( window->State.MouseY > 32767 ) window->State.MouseY -= 65536;
652 button = GLUT_LEFT_BUTTON;
656 button = GLUT_MIDDLE_BUTTON;
660 button = GLUT_RIGHT_BUTTON;
664 button = GLUT_LEFT_BUTTON;
668 button = GLUT_MIDDLE_BUTTON;
672 button = GLUT_RIGHT_BUTTON;
680 #if !defined(_WIN32_WCE)
681 if( GetSystemMetrics( SM_SWAPBUTTON ) )
683 if( button == GLUT_LEFT_BUTTON )
684 button = GLUT_RIGHT_BUTTON;
686 if( button == GLUT_RIGHT_BUTTON )
687 button = GLUT_LEFT_BUTTON;
689 #endif /* !defined(_WIN32_WCE) */
692 return DefWindowProc( hWnd, uMsg, lParam, wParam );
695 * Do not execute the application's mouse callback if a menu
696 * is hooked to this button. In that case an appropriate
697 * private call should be generated.
699 if( fgCheckActiveMenu( window, button, pressed,
700 window->State.MouseX, window->State.MouseY ) )
703 /* Set capture so that the window captures all the mouse messages */
705 * XXX - Multiple button support: Under X11, the mouse is not released
706 * XXX - from the window until all buttons have been released, even if the
707 * XXX - user presses a button in another window. This will take more
708 * XXX - code changes than I am up to at the moment (10/5/04). The present
709 * XXX - is a 90 percent solution.
711 if ( pressed == GL_TRUE )
712 SetCapture ( window->Window.Handle ) ;
716 if( ! FETCH_WCB( *window, Mouse ) )
719 fgSetWindow( window );
720 fgState.Modifiers = fgPlatformGetModifiers( );
725 pressed ? GLUT_DOWN : GLUT_UP,
726 window->State.MouseX,
731 fgState.Modifiers = INVALID_MODIFIERS;
737 int wheel_number = LOWORD( wParam );
738 short ticks = ( short )HIWORD( wParam );
739 fgState.MouseWheelTicks += ticks;
741 if ( abs ( fgState.MouseWheelTicks ) >= WHEEL_DELTA )
743 int direction = ( fgState.MouseWheelTicks > 0 ) ? 1 : -1;
745 if( ! FETCH_WCB( *window, MouseWheel ) &&
746 ! FETCH_WCB( *window, Mouse ) )
749 fgSetWindow( window );
750 fgState.Modifiers = fgPlatformGetModifiers( );
752 while( abs ( fgState.MouseWheelTicks ) >= WHEEL_DELTA )
754 if( FETCH_WCB( *window, MouseWheel ) )
755 INVOKE_WCB( *window, MouseWheel,
758 window->State.MouseX,
762 else /* No mouse wheel, call the mouse button callback twice */
765 * Map wheel zero to button 3 and 4; +1 to 3, -1 to 4
766 * " " one +1 to 5, -1 to 6, ...
768 * XXX The below assumes that you have no more than 3 mouse
769 * XXX buttons. Sorry.
771 int button = wheel_number * 2 + 3;
774 INVOKE_WCB( *window, Mouse,
776 window->State.MouseX, window->State.MouseY )
778 INVOKE_WCB( *window, Mouse,
780 window->State.MouseX, window->State.MouseY )
784 fgState.MouseWheelTicks -= WHEEL_DELTA * direction;
787 fgState.Modifiers = INVALID_MODIFIERS;
795 window = child_window;
796 lRet = fghWindowProcKeyPress(window,uMsg,GL_TRUE,wParam,lParam);
802 window = child_window;
803 lRet = fghWindowProcKeyPress(window,uMsg,GL_FALSE,wParam,lParam);
810 window = child_window;
812 if( (fgState.KeyRepeat==GLUT_KEY_REPEAT_OFF || window->State.IgnoreKeyRepeat==GL_TRUE) && (HIWORD(lParam) & KF_REPEAT) )
815 fgState.Modifiers = fgPlatformGetModifiers( );
816 INVOKE_WCB( *window, Keyboard,
818 window->State.MouseX, window->State.MouseY )
820 fgState.Modifiers = INVALID_MODIFIERS;
824 case WM_CAPTURECHANGED:
825 /* User has finished resizing the window, force a redraw */
826 INVOKE_WCB( *window, Display, ( ) );
828 /*lRet = DefWindowProc( hWnd, uMsg, wParam, lParam ); */
831 /* Other messages that I have seen and which are not handled already */
832 case WM_SETTEXT: /* 0x000c */
833 lRet = DefWindowProc( hWnd, uMsg, wParam, lParam );
834 /* Pass it on to "DefWindowProc" to set the window text */
837 case WM_GETTEXT: /* 0x000d */
838 /* Ideally we would copy the title of the window into "lParam" */
839 /* strncpy ( (char *)lParam, "Window Title", wParam );
840 lRet = ( wParam > 12 ) ? 12 : wParam; */
841 /* the number of characters copied */
842 lRet = DefWindowProc( hWnd, uMsg, wParam, lParam );
845 case WM_GETTEXTLENGTH: /* 0x000e */
846 /* Ideally we would get the length of the title of the window */
848 /* the number of characters in "Window Title\0" (see above) */
851 case WM_ERASEBKGND: /* 0x0014 */
852 lRet = DefWindowProc( hWnd, uMsg, wParam, lParam );
855 #if !defined(_WIN32_WCE)
856 case WM_SYNCPAINT: /* 0x0088 */
857 /* Another window has moved, need to update this one */
858 window->State.Redisplay = GL_TRUE;
859 lRet = DefWindowProc( hWnd, uMsg, wParam, lParam );
860 /* Help screen says this message must be passed to "DefWindowProc" */
863 case WM_NCPAINT: /* 0x0085 */
864 /* Need to update the border of this window */
865 lRet = DefWindowProc( hWnd, uMsg, wParam, lParam );
866 /* Pass it on to "DefWindowProc" to repaint a standard border */
869 case WM_SYSCOMMAND : /* 0x0112 */
872 * We have received a system command message. Try to act on it.
873 * The commands are passed in through the "wParam" parameter:
874 * The least significant digit seems to be which edge of the window
875 * is being used for a resize event:
879 * Congratulations and thanks to Richard Rauch for figuring this out..
881 switch ( wParam & 0xfff0 )
890 /* User has clicked on the "-" to minimize the window */
891 /* Turn off the visibility */
892 window->State.Visible = GL_FALSE ;
906 /* Followed very closely by a WM_CLOSE message */
936 #if(WINVER >= 0x0400)
940 case SC_MONITORPOWER :
943 case SC_CONTEXTHELP :
945 #endif /* WINVER >= 0x0400 */
949 fgWarning( "Unknown wParam type 0x%x", wParam );
954 #endif /* !defined(_WIN32_WCE) */
956 /* We need to pass the message on to the operating system as well */
957 lRet = DefWindowProc( hWnd, uMsg, wParam, lParam );
961 /* handle multi-touch messages */
964 unsigned int numInputs = (unsigned int)wParam;
966 TOUCHINPUT* ti = (TOUCHINPUT*)malloc( sizeof(TOUCHINPUT)*numInputs);
968 if (fghGetTouchInputInfo == (pGetTouchInputInfo)0xDEADBEEF) {
969 fghGetTouchInputInfo = (pGetTouchInputInfo)GetProcAddress(GetModuleHandle("user32"),"GetTouchInputInfo");
970 fghCloseTouchInputHandle = (pCloseTouchInputHandle)GetProcAddress(GetModuleHandle("user32"),"CloseTouchInputHandle");
973 if (!fghGetTouchInputInfo) {
978 if (fghGetTouchInputInfo( (HTOUCHINPUT)lParam, numInputs, ti, sizeof(TOUCHINPUT) )) {
979 /* Handle each contact point */
980 for (i = 0; i < numInputs; ++i ) {
983 tp.x = TOUCH_COORD_TO_PIXEL(ti[i].x);
984 tp.y = TOUCH_COORD_TO_PIXEL(ti[i].y);
985 ScreenToClient( hWnd, &tp );
987 ti[i].dwID = ti[i].dwID * 2;
989 if (ti[i].dwFlags & TOUCHEVENTF_DOWN) {
990 INVOKE_WCB( *window, MultiEntry, ( ti[i].dwID, GLUT_ENTERED ) );
991 INVOKE_WCB( *window, MultiButton, ( ti[i].dwID, tp.x, tp.y, 0, GLUT_DOWN ) );
992 } else if (ti[i].dwFlags & TOUCHEVENTF_MOVE) {
993 INVOKE_WCB( *window, MultiMotion, ( ti[i].dwID, tp.x, tp.y ) );
994 } else if (ti[i].dwFlags & TOUCHEVENTF_UP) {
995 INVOKE_WCB( *window, MultiButton, ( ti[i].dwID, tp.x, tp.y, 0, GLUT_UP ) );
996 INVOKE_WCB( *window, MultiEntry, ( ti[i].dwID, GLUT_LEFT ) );
1000 fghCloseTouchInputHandle((HTOUCHINPUT)lParam);
1002 lRet = 0; /*DefWindowProc( hWnd, uMsg, wParam, lParam );*/
1007 /* Handle unhandled messages */
1008 lRet = DefWindowProc( hWnd, uMsg, wParam, lParam );