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 repeat is globally switched off, it cannot be switched back on per window.
183 * But if it is globally switched on, it can be switched off per window. This matches
184 * GLUT's behavior on X11, but not Nate Robbins' win32 GLUT, as he didn't implement the
185 * global state switch.
187 if( keydown && ( fgState.KeyRepeat==GLUT_KEY_REPEAT_OFF || window->State.IgnoreKeyRepeat==GL_TRUE ) && (HIWORD(lParam) & KF_REPEAT) )
190 /* Remember the current modifiers state so user can query it from their callback */
191 fgState.Modifiers = fgPlatformGetModifiers( );
193 /* Get mouse position roughly at time of keypress */
194 GetCursorPos( &mouse_pos );
195 ScreenToClient( window->Window.Handle, &mouse_pos );
196 window->State.MouseX = mouse_pos.x;
197 window->State.MouseY = mouse_pos.y;
199 /* Convert the Win32 keystroke codes to GLUTtish way */
200 # define KEY(a,b) case a: keypress = b; break;
204 KEY( VK_F1, GLUT_KEY_F1 );
205 KEY( VK_F2, GLUT_KEY_F2 );
206 KEY( VK_F3, GLUT_KEY_F3 );
207 KEY( VK_F4, GLUT_KEY_F4 );
208 KEY( VK_F5, GLUT_KEY_F5 );
209 KEY( VK_F6, GLUT_KEY_F6 );
210 KEY( VK_F7, GLUT_KEY_F7 );
211 KEY( VK_F8, GLUT_KEY_F8 );
212 KEY( VK_F9, GLUT_KEY_F9 );
213 KEY( VK_F10, GLUT_KEY_F10 );
214 KEY( VK_F11, GLUT_KEY_F11 );
215 KEY( VK_F12, GLUT_KEY_F12 );
216 KEY( VK_PRIOR, GLUT_KEY_PAGE_UP );
217 KEY( VK_NEXT, GLUT_KEY_PAGE_DOWN );
218 KEY( VK_HOME, GLUT_KEY_HOME );
219 KEY( VK_END, GLUT_KEY_END );
220 KEY( VK_LEFT, GLUT_KEY_LEFT );
221 KEY( VK_UP, GLUT_KEY_UP );
222 KEY( VK_RIGHT, GLUT_KEY_RIGHT );
223 KEY( VK_DOWN, GLUT_KEY_DOWN );
224 KEY( VK_INSERT, GLUT_KEY_INSERT );
226 /* handle control, alt and shift. For GLUT, we want to distinguish between left and right presses.
227 * The VK_L* & VK_R* left and right Alt, Ctrl and Shift virtual keys are however only used as parameters to GetAsyncKeyState() and GetKeyState()
228 * so when we get an alt, shift or control keypress here, we manually check whether it was the left or the right
230 #define ASYNC_KEY_EVENT(winKey,glutKey,keyStateVar)\
231 if (!keyStateVar && GetAsyncKeyState ( winKey ))\
236 else if (keyStateVar && !GetAsyncKeyState ( winKey ))\
242 ASYNC_KEY_EVENT(VK_LCONTROL,GLUT_KEY_CTRL_L,lControl);
243 ASYNC_KEY_EVENT(VK_RCONTROL,GLUT_KEY_CTRL_R,rControl);
246 ASYNC_KEY_EVENT(VK_LSHIFT,GLUT_KEY_SHIFT_L,lShift);
247 ASYNC_KEY_EVENT(VK_RSHIFT,GLUT_KEY_SHIFT_R,rShift);
250 ASYNC_KEY_EVENT(VK_LMENU,GLUT_KEY_ALT_L,lAlt);
251 ASYNC_KEY_EVENT(VK_RMENU,GLUT_KEY_ALT_R,rAlt);
253 #undef ASYNC_KEY_EVENT
256 /* The delete key should be treated as an ASCII keypress: */
258 INVOKE_WCB( *window, Keyboard,
259 ( 127, window->State.MouseX, window->State.MouseY )
262 INVOKE_WCB( *window, KeyboardUp,
263 ( 127, window->State.MouseX, window->State.MouseY )
267 #if !defined(_WIN32_WCE)
269 /* keydown displayable characters are handled with WM_CHAR message, but no corresponding up is generated. So get that here. */
275 GetKeyboardState( state );
277 if( ToAscii( (UINT)wParam, 0, state, code, 0 ) == 1 )
280 INVOKE_WCB( *window, KeyboardUp,
282 window->State.MouseX, window->State.MouseY )
288 #if defined(_WIN32_WCE)
289 if(keydown && !(lParam & 0x40000000)) /* Prevent auto-repeat */
291 if(wParam==(unsigned)gxKeyList.vkRight)
292 keypress = GLUT_KEY_RIGHT;
293 else if(wParam==(unsigned)gxKeyList.vkLeft)
294 keypress = GLUT_KEY_LEFT;
295 else if(wParam==(unsigned)gxKeyList.vkUp)
296 keypress = GLUT_KEY_UP;
297 else if(wParam==(unsigned)gxKeyList.vkDown)
298 keypress = GLUT_KEY_DOWN;
299 else if(wParam==(unsigned)gxKeyList.vkA)
300 keypress = GLUT_KEY_F1;
301 else if(wParam==(unsigned)gxKeyList.vkB)
302 keypress = GLUT_KEY_F2;
303 else if(wParam==(unsigned)gxKeyList.vkC)
304 keypress = GLUT_KEY_F3;
305 else if(wParam==(unsigned)gxKeyList.vkStart)
306 keypress = GLUT_KEY_F4;
312 INVOKE_WCB( *window, Special,
314 window->State.MouseX, window->State.MouseY )
317 INVOKE_WCB( *window, SpecialUp,
319 window->State.MouseX, window->State.MouseY )
322 fgState.Modifiers = INVALID_MODIFIERS;
324 /* SYSKEY events should be sent to default window proc for system to handle them */
325 if (uMsg==WM_SYSKEYDOWN || uMsg==WM_SYSKEYUP)
326 return DefWindowProc( window->Window.Handle, uMsg, wParam, lParam );
331 void fghWindowUnderCursor(SFG_Window *window, SFG_Window **child_window)
333 /* Check if the current window that the mouse is over is a child window
334 * of the window the message was sent to.
336 if (window && window->Children.First)
339 SFG_WindowHandleType hwnd;
340 SFG_Window* temp_window;
342 GetCursorPos( &mouse_pos );
343 ScreenToClient( window->Window.Handle, &mouse_pos );
344 hwnd = ChildWindowFromPoint(window->Window.Handle, mouse_pos);
345 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 */
347 temp_window = fgWindowByHandle(hwnd);
348 if (temp_window) /* Verify we got a FreeGLUT window */
350 *child_window = temp_window;
351 /* ChildWindowFromPoint only searches immediate children, so search again to see if actually in grandchild or further descendant */
352 fghWindowUnderCursor(temp_window,child_window);
359 * The window procedure for handling Win32 events
361 LRESULT CALLBACK fgPlatformWindowProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam )
363 SFG_Window *window, *child_window = NULL;
367 FREEGLUT_INTERNAL_ERROR_EXIT_IF_NOT_INITIALISED ( "Event Handler" ) ;
369 window = fgWindowByHandle( hWnd );
371 if ( ( window == NULL ) && ( uMsg != WM_CREATE ) )
372 return DefWindowProc( hWnd, uMsg, wParam, lParam );
374 /* printf ( "Window %3d message <%04x> %12d %12d\n", window?window->ID:0,
375 uMsg, wParam, lParam ); */
377 /* Some events only sent to main window. Check if the current window that
378 * the mouse is over is a child window. Below when handling some messages,
379 * we make sure that we process callbacks on the child window instead.
380 * This mirrors how GLUT does things.
382 fghWindowUnderCursor(window, &child_window);
387 /* The window structure is passed as the creation structure parameter... */
388 window = (SFG_Window *) (((LPCREATESTRUCT) lParam)->lpCreateParams);
389 FREEGLUT_INTERNAL_ERROR_EXIT ( ( window != NULL ), "Cannot create window",
390 "fgPlatformWindowProc" );
392 window->Window.Handle = hWnd;
393 window->Window.pContext.Device = GetDC( hWnd );
396 unsigned int current_DisplayMode = fgState.DisplayMode;
397 fgState.DisplayMode = GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH;
398 #if !defined(_WIN32_WCE)
399 fgSetupPixelFormat( window, GL_FALSE, PFD_MAIN_PLANE );
401 fgState.DisplayMode = current_DisplayMode;
403 if( fgStructure.MenuContext )
404 wglMakeCurrent( window->Window.pContext.Device,
405 fgStructure.MenuContext->MContext
409 fgStructure.MenuContext =
410 (SFG_MenuContext *)malloc( sizeof(SFG_MenuContext) );
411 fgStructure.MenuContext->MContext =
412 wglCreateContext( window->Window.pContext.Device );
415 /* window->Window.Context = wglGetCurrentContext (); */
416 window->Window.Context = wglCreateContext( window->Window.pContext.Device );
420 #if !defined(_WIN32_WCE)
421 fgSetupPixelFormat( window, GL_FALSE, PFD_MAIN_PLANE );
424 if( ! fgState.UseCurrentContext )
425 window->Window.Context =
426 wglCreateContext( window->Window.pContext.Device );
429 window->Window.Context = wglGetCurrentContext( );
430 if( ! window->Window.Context )
431 window->Window.Context =
432 wglCreateContext( window->Window.pContext.Device );
435 #if !defined(_WIN32_WCE)
436 fgNewWGLCreateContext( window );
440 window->State.NeedToResize = GL_TRUE;
441 /* if we used CW_USEDEFAULT (thats a negative value) for the size
442 * of the window, query the window now for the size at which it
445 if( ( window->State.Width < 0 ) || ( window->State.Height < 0 ) )
447 SFG_Window *current_window = fgStructure.CurrentWindow;
449 fgSetWindow( window );
450 window->State.Width = glutGet( GLUT_WINDOW_WIDTH );
451 window->State.Height = glutGet( GLUT_WINDOW_HEIGHT );
452 fgSetWindow( current_window );
455 ReleaseDC( window->Window.Handle, window->Window.pContext.Device );
457 #if defined(_WIN32_WCE)
458 /* Take over button handling */
460 HINSTANCE dxDllLib=LoadLibrary(_T("gx.dll"));
463 GXGetDefaultKeys_=(GXGETDEFAULTKEYS)GetProcAddress(dxDllLib, _T("?GXGetDefaultKeys@@YA?AUGXKeyList@@H@Z"));
464 GXOpenInput_=(GXOPENINPUT)GetProcAddress(dxDllLib, _T("?GXOpenInput@@YAHXZ"));
469 if(GXGetDefaultKeys_)
470 gxKeyList = (*GXGetDefaultKeys_)(GX_LANDSCAPEKEYS);
473 #endif /* defined(_WIN32_WCE) */
478 * If the window is visible, then it is the user manually resizing it.
479 * If it is not, then it is the system sending us a dummy resize with
480 * zero dimensions on a "glutIconifyWindow" call.
482 if( window->State.Visible )
484 /* get old values first to compare to below */
485 int width = window->State.Width, height=window->State.Height;
486 #if defined(_WIN32_WCE)
487 window->State.Width = HIWORD(lParam);
488 window->State.Height = LOWORD(lParam);
490 window->State.Width = LOWORD(lParam);
491 window->State.Height = HIWORD(lParam);
492 #endif /* defined(_WIN32_WCE) */
494 if (width!=window->State.Width || height!=window->State.Height)
495 /* Something changed, need to resize */
496 window->State.NeedToResize = GL_TRUE;
503 SFG_Window* saved_window = fgStructure.CurrentWindow;
505 GetWindowRect( window->Window.Handle, &windowRect );
509 /* For child window, we should return relative to upper-left
510 * of parent's client area.
512 POINT topleft = {windowRect.left,windowRect.top};
514 ScreenToClient(window->Parent->Window.Handle,&topleft);
515 windowRect.left = topleft.x;
516 windowRect.top = topleft.y;
519 INVOKE_WCB( *window, Position, ( windowRect.left, windowRect.top ) );
520 fgSetWindow(saved_window);
525 /* printf("WM_SETFOCUS: %p\n", window ); */
527 lRet = DefWindowProc( hWnd, uMsg, wParam, lParam );
531 /* If we're dealing with a child window, make sure it has input focus instead, set it here. */
532 SetFocus(child_window->Window.Handle);
533 SetActiveWindow( child_window->Window.Handle );
534 INVOKE_WCB( *child_window, Entry, ( GLUT_ENTERED ) );
535 UpdateWindow ( child_window->Window.Handle );
539 SetActiveWindow( window->Window.Handle );
540 INVOKE_WCB( *window, Entry, ( GLUT_ENTERED ) );
542 /* Always request update on main window to be safe */
543 UpdateWindow ( hWnd );
549 SFG_Window* saved_window = fgStructure.CurrentWindow;
550 /* printf("WM_KILLFOCUS: %p\n", window ); */
551 lRet = DefWindowProc( hWnd, uMsg, wParam, lParam );
552 INVOKE_WCB( *window, Entry, ( GLUT_LEFT ) );
553 fgSetWindow(saved_window);
555 /* Check if there are any open menus that need to be closed */
556 fgPlatformCheckMenuDeactivate();
562 if (LOWORD(wParam) != WA_INACTIVE)
564 /* printf("WM_ACTIVATE: fgSetCursor( %p, %d)\n", window,
565 window->State.Cursor ); */
566 fgSetCursor( window, window->State.Cursor );
569 lRet = DefWindowProc( hWnd, uMsg, wParam, lParam );
574 /* printf ( "Cursor event %x %x %x %x\n", window, window->State.Cursor, lParam, wParam ) ; */
575 if( LOWORD( lParam ) == HTCLIENT )
576 fgSetCursor ( window, window->State.Cursor ) ;
578 lRet = DefWindowProc( hWnd, uMsg, wParam, lParam );
582 window->State.Visible = GL_TRUE;
583 window->State.Redisplay = GL_TRUE;
587 /* Turn on the visibility in case it was turned off somehow */
588 window->State.Visible = GL_TRUE;
589 InvalidateRect( hWnd, NULL, GL_FALSE ); /* Make sure whole window is repainted. Bit of a hack, but a safe one from what google turns up... */
590 BeginPaint( hWnd, &ps );
591 fghRedrawWindow( window );
592 EndPaint( hWnd, &ps );
596 fgDestroyWindow ( window );
597 if ( fgState.ActionOnWindowClose != GLUT_ACTION_CONTINUE_EXECUTION )
603 * The window already got destroyed, so don't bother with it.
609 #if defined(_WIN32_WCE)
610 window->State.MouseX = 320-HIWORD( lParam );
611 window->State.MouseY = LOWORD( lParam );
613 window->State.MouseX = LOWORD( lParam );
614 window->State.MouseY = HIWORD( lParam );
615 #endif /* defined(_WIN32_WCE) */
616 /* Restrict to [-32768, 32767] to match X11 behaviour */
617 /* See comment in "freeglut_developer" mailing list 10/4/04 */
618 if ( window->State.MouseX > 32767 ) window->State.MouseX -= 65536;
619 if ( window->State.MouseY > 32767 ) window->State.MouseY -= 65536;
621 if ( window->ActiveMenu )
623 fgUpdateMenuHighlight( window->ActiveMenu );
627 fgState.Modifiers = fgPlatformGetModifiers( );
629 if( ( wParam & MK_LBUTTON ) ||
630 ( wParam & MK_MBUTTON ) ||
631 ( wParam & MK_RBUTTON ) )
632 INVOKE_WCB( *window, Motion, ( window->State.MouseX,
633 window->State.MouseY ) );
635 INVOKE_WCB( *window, Passive, ( window->State.MouseX,
636 window->State.MouseY ) );
638 fgState.Modifiers = INVALID_MODIFIERS;
649 GLboolean pressed = GL_TRUE;
652 #if defined(_WIN32_WCE)
653 window->State.MouseX = 320-HIWORD( lParam );
654 window->State.MouseY = LOWORD( lParam );
656 window->State.MouseX = LOWORD( lParam );
657 window->State.MouseY = HIWORD( lParam );
658 #endif /* defined(_WIN32_WCE) */
660 /* Restrict to [-32768, 32767] to match X11 behaviour */
661 /* See comment in "freeglut_developer" mailing list 10/4/04 */
662 if ( window->State.MouseX > 32767 ) window->State.MouseX -= 65536;
663 if ( window->State.MouseY > 32767 ) window->State.MouseY -= 65536;
669 button = GLUT_LEFT_BUTTON;
673 button = GLUT_MIDDLE_BUTTON;
677 button = GLUT_RIGHT_BUTTON;
681 button = GLUT_LEFT_BUTTON;
685 button = GLUT_MIDDLE_BUTTON;
689 button = GLUT_RIGHT_BUTTON;
697 #if !defined(_WIN32_WCE)
698 if( GetSystemMetrics( SM_SWAPBUTTON ) )
700 if( button == GLUT_LEFT_BUTTON )
701 button = GLUT_RIGHT_BUTTON;
703 if( button == GLUT_RIGHT_BUTTON )
704 button = GLUT_LEFT_BUTTON;
706 #endif /* !defined(_WIN32_WCE) */
709 return DefWindowProc( hWnd, uMsg, lParam, wParam );
712 * Do not execute the application's mouse callback if a menu
713 * is hooked to this button. In that case an appropriate
714 * private call should be generated.
716 if( fgCheckActiveMenu( window, button, pressed,
717 window->State.MouseX, window->State.MouseY ) )
720 /* Set capture so that the window captures all the mouse messages */
722 * XXX - Multiple button support: Under X11, the mouse is not released
723 * XXX - from the window until all buttons have been released, even if the
724 * XXX - user presses a button in another window. This will take more
725 * XXX - code changes than I am up to at the moment (10/5/04). The present
726 * XXX - is a 90 percent solution.
728 if ( pressed == GL_TRUE )
729 SetCapture ( window->Window.Handle ) ;
733 if( ! FETCH_WCB( *window, Mouse ) )
736 fgSetWindow( window );
737 fgState.Modifiers = fgPlatformGetModifiers( );
742 pressed ? GLUT_DOWN : GLUT_UP,
743 window->State.MouseX,
748 fgState.Modifiers = INVALID_MODIFIERS;
754 int wheel_number = LOWORD( wParam );
755 short ticks = ( short )HIWORD( wParam );
756 fgState.MouseWheelTicks += ticks;
758 if ( abs ( fgState.MouseWheelTicks ) >= WHEEL_DELTA )
760 int direction = ( fgState.MouseWheelTicks > 0 ) ? 1 : -1;
762 if( ! FETCH_WCB( *window, MouseWheel ) &&
763 ! FETCH_WCB( *window, Mouse ) )
766 fgSetWindow( window );
767 fgState.Modifiers = fgPlatformGetModifiers( );
769 while( abs ( fgState.MouseWheelTicks ) >= WHEEL_DELTA )
771 if( FETCH_WCB( *window, MouseWheel ) )
772 INVOKE_WCB( *window, MouseWheel,
775 window->State.MouseX,
779 else /* No mouse wheel, call the mouse button callback twice */
782 * Map wheel zero to button 3 and 4; +1 to 3, -1 to 4
783 * " " one +1 to 5, -1 to 6, ...
785 * XXX The below assumes that you have no more than 3 mouse
786 * XXX buttons. Sorry.
788 int button = wheel_number * 2 + 3;
791 INVOKE_WCB( *window, Mouse,
793 window->State.MouseX, window->State.MouseY )
795 INVOKE_WCB( *window, Mouse,
797 window->State.MouseX, window->State.MouseY )
801 fgState.MouseWheelTicks -= WHEEL_DELTA * direction;
804 fgState.Modifiers = INVALID_MODIFIERS;
812 window = child_window;
813 lRet = fghWindowProcKeyPress(window,uMsg,GL_TRUE,wParam,lParam);
819 window = child_window;
820 lRet = fghWindowProcKeyPress(window,uMsg,GL_FALSE,wParam,lParam);
827 window = child_window;
829 if( (fgState.KeyRepeat==GLUT_KEY_REPEAT_OFF || window->State.IgnoreKeyRepeat==GL_TRUE) && (HIWORD(lParam) & KF_REPEAT) )
832 fgState.Modifiers = fgPlatformGetModifiers( );
833 INVOKE_WCB( *window, Keyboard,
835 window->State.MouseX, window->State.MouseY )
837 fgState.Modifiers = INVALID_MODIFIERS;
841 case WM_CAPTURECHANGED:
842 /* User has finished resizing the window, force a redraw */
843 INVOKE_WCB( *window, Display, ( ) );
845 /*lRet = DefWindowProc( hWnd, uMsg, wParam, lParam ); */
848 /* Other messages that I have seen and which are not handled already */
849 case WM_SETTEXT: /* 0x000c */
850 lRet = DefWindowProc( hWnd, uMsg, wParam, lParam );
851 /* Pass it on to "DefWindowProc" to set the window text */
854 case WM_GETTEXT: /* 0x000d */
855 /* Ideally we would copy the title of the window into "lParam" */
856 /* strncpy ( (char *)lParam, "Window Title", wParam );
857 lRet = ( wParam > 12 ) ? 12 : wParam; */
858 /* the number of characters copied */
859 lRet = DefWindowProc( hWnd, uMsg, wParam, lParam );
862 case WM_GETTEXTLENGTH: /* 0x000e */
863 /* Ideally we would get the length of the title of the window */
865 /* the number of characters in "Window Title\0" (see above) */
868 case WM_ERASEBKGND: /* 0x0014 */
869 lRet = DefWindowProc( hWnd, uMsg, wParam, lParam );
872 #if !defined(_WIN32_WCE)
873 case WM_SYNCPAINT: /* 0x0088 */
874 /* Another window has moved, need to update this one */
875 window->State.Redisplay = GL_TRUE;
876 lRet = DefWindowProc( hWnd, uMsg, wParam, lParam );
877 /* Help screen says this message must be passed to "DefWindowProc" */
880 case WM_NCPAINT: /* 0x0085 */
881 /* Need to update the border of this window */
882 lRet = DefWindowProc( hWnd, uMsg, wParam, lParam );
883 /* Pass it on to "DefWindowProc" to repaint a standard border */
886 case WM_SYSCOMMAND : /* 0x0112 */
889 * We have received a system command message. Try to act on it.
890 * The commands are passed in through the "wParam" parameter:
891 * The least significant digit seems to be which edge of the window
892 * is being used for a resize event:
896 * Congratulations and thanks to Richard Rauch for figuring this out..
898 switch ( wParam & 0xfff0 )
907 /* User has clicked on the "-" to minimize the window */
908 /* Turn off the visibility */
909 window->State.Visible = GL_FALSE ;
923 /* Followed very closely by a WM_CLOSE message */
953 #if(WINVER >= 0x0400)
957 case SC_MONITORPOWER :
960 case SC_CONTEXTHELP :
962 #endif /* WINVER >= 0x0400 */
966 fgWarning( "Unknown wParam type 0x%x", wParam );
971 #endif /* !defined(_WIN32_WCE) */
973 /* We need to pass the message on to the operating system as well */
974 lRet = DefWindowProc( hWnd, uMsg, wParam, lParam );
978 /* handle multi-touch messages */
981 unsigned int numInputs = (unsigned int)wParam;
983 TOUCHINPUT* ti = (TOUCHINPUT*)malloc( sizeof(TOUCHINPUT)*numInputs);
985 if (fghGetTouchInputInfo == (pGetTouchInputInfo)0xDEADBEEF) {
986 fghGetTouchInputInfo = (pGetTouchInputInfo)GetProcAddress(GetModuleHandle("user32"),"GetTouchInputInfo");
987 fghCloseTouchInputHandle = (pCloseTouchInputHandle)GetProcAddress(GetModuleHandle("user32"),"CloseTouchInputHandle");
990 if (!fghGetTouchInputInfo) {
995 if (fghGetTouchInputInfo( (HTOUCHINPUT)lParam, numInputs, ti, sizeof(TOUCHINPUT) )) {
996 /* Handle each contact point */
997 for (i = 0; i < numInputs; ++i ) {
1000 tp.x = TOUCH_COORD_TO_PIXEL(ti[i].x);
1001 tp.y = TOUCH_COORD_TO_PIXEL(ti[i].y);
1002 ScreenToClient( hWnd, &tp );
1004 ti[i].dwID = ti[i].dwID * 2;
1006 if (ti[i].dwFlags & TOUCHEVENTF_DOWN) {
1007 INVOKE_WCB( *window, MultiEntry, ( ti[i].dwID, GLUT_ENTERED ) );
1008 INVOKE_WCB( *window, MultiButton, ( ti[i].dwID, tp.x, tp.y, 0, GLUT_DOWN ) );
1009 } else if (ti[i].dwFlags & TOUCHEVENTF_MOVE) {
1010 INVOKE_WCB( *window, MultiMotion, ( ti[i].dwID, tp.x, tp.y ) );
1011 } else if (ti[i].dwFlags & TOUCHEVENTF_UP) {
1012 INVOKE_WCB( *window, MultiButton, ( ti[i].dwID, tp.x, tp.y, 0, GLUT_UP ) );
1013 INVOKE_WCB( *window, MultiEntry, ( ti[i].dwID, GLUT_LEFT ) );
1017 fghCloseTouchInputHandle((HTOUCHINPUT)lParam);
1019 lRet = 0; /*DefWindowProc( hWnd, uMsg, wParam, lParam );*/
1024 /* Handle unhandled messages */
1025 lRet = DefWindowProc( hWnd, uMsg, wParam, lParam );