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 );
39 typedef BOOL (WINAPI *pGetTouchInputInfo)(HTOUCHINPUT,UINT,PTOUCHINPUT,int);
40 typedef BOOL (WINAPI *pCloseTouchInputHandle)(HTOUCHINPUT);
41 static pGetTouchInputInfo fghGetTouchInputInfo = (pGetTouchInputInfo)0xDEADBEEF;
42 static pCloseTouchInputHandle fghCloseTouchInputHandle = (pCloseTouchInputHandle)0xDEADBEEF;
46 typedef struct GXDisplayProperties GXDisplayProperties;
47 typedef struct GXKeyList GXKeyList;
50 typedef struct GXKeyList (*GXGETDEFAULTKEYS)(int);
51 typedef int (*GXOPENINPUT)();
53 GXGETDEFAULTKEYS GXGetDefaultKeys_ = NULL;
54 GXOPENINPUT GXOpenInput_ = NULL;
56 struct GXKeyList gxKeyList;
57 #endif /* _WIN32_WCE */
60 * Helper functions for getting client area from the window rect
61 * and the window rect from the client area given the style of the window
62 * (or a valid window pointer from which the style can be queried).
64 extern void fghComputeWindowRectFromClientArea_QueryWindow( const SFG_Window *window, RECT *clientRect, BOOL posIsOutside );
65 extern RECT fghGetClientArea ( const SFG_Window *window, BOOL wantPosOutside );
68 void fgPlatformReshapeWindow ( SFG_Window *window, int width, int height )
73 * For windowed mode, get the current position of the
74 * window and resize taking the size of the frame
75 * decorations into account.
78 /* "GetWindowRect" returns the pixel coordinates of the outside of the window */
79 GetWindowRect( window->Window.Handle, &windowRect );
81 /* Create rect in FreeGLUT format, (X,Y) topleft outside window, WxH of client area */
82 windowRect.right = windowRect.left+width;
83 windowRect.bottom = windowRect.top+height;
85 if (window->Parent == NULL)
86 /* get the window rect from this to feed to SetWindowPos, correct for window decorations */
87 fghComputeWindowRectFromClientArea_QueryWindow(window,&windowRect,TRUE);
90 /* correct rect for position client area of parent window
91 * (SetWindowPos input for child windows is in coordinates
92 * relative to the parent's client area).
93 * Child windows don't have decoration, so no need to correct
97 parentRect = fghGetClientArea( window->Parent, FALSE );
98 windowRect.left -= parentRect.left;
99 windowRect.right -= parentRect.left;
100 windowRect.top -= parentRect.top;
101 windowRect.bottom -= parentRect.top;
104 /* Do the actual resizing */
105 SetWindowPos( window->Window.Handle,
107 windowRect.left, windowRect.top,
108 windowRect.right - windowRect.left,
109 windowRect.bottom- windowRect.top,
110 SWP_NOACTIVATE | SWP_NOOWNERZORDER | SWP_NOSENDCHANGING |
116 void fgPlatformDisplayWindow ( SFG_Window *window )
119 window->Window.Handle, NULL, NULL,
120 RDW_NOERASE | RDW_INTERNALPAINT | RDW_INVALIDATE | RDW_UPDATENOW
125 fg_time_t fgPlatformSystemTime ( void )
127 #if defined(_WIN32_WCE)
128 return GetTickCount();
130 /* TODO: do this with QueryPerformanceCounter as timeGetTime has
131 * insufficient resolution (only about 5 ms on system under low load).
133 * http://msdn.microsoft.com/en-us/library/windows/desktop/dd757629(v=vs.85).aspx
134 * Or maybe QueryPerformanceCounter is not a good idea either, see
135 * http://old.nabble.com/Re%3A-glutTimerFunc-does-not-detect-if-system-time-moved-backward-p33479674.html
136 * for some other ideas (at bottom)...
138 return timeGetTime();
143 void fgPlatformSleepForEvents( fg_time_t msec )
145 MsgWaitForMultipleObjects( 0, NULL, FALSE, (DWORD) msec, QS_ALLINPUT );
149 void fgPlatformProcessSingleEvent ( void )
153 FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutMainLoopEvent" );
155 while( PeekMessage( &stMsg, NULL, 0, 0, PM_NOREMOVE ) )
157 if( GetMessage( &stMsg, NULL, 0, 0 ) == 0 )
159 if( fgState.ActionOnWindowClose == GLUT_ACTION_EXIT )
164 else if( fgState.ActionOnWindowClose == GLUT_ACTION_GLUTMAINLOOP_RETURNS )
165 fgState.ExecState = GLUT_EXEC_STATE_STOP;
170 TranslateMessage( &stMsg );
171 DispatchMessage( &stMsg );
177 void fgPlatformMainLoopPreliminaryWork ( void )
179 SFG_Window *window = (SFG_Window *)fgStructure.Windows.First ;
182 * Processing before the main loop: If there is a window which is open and
183 * which has a visibility callback, call it. I know this is an ugly hack,
184 * but I'm not sure what else to do about it. Ideally we should leave
185 * something uninitialized in the create window code and initialize it in
186 * the main loop, and have that initialization create a "WM_ACTIVATE"
187 * message. Then we would put the visibility callback code in the
188 * "case WM_ACTIVATE" block below. - John Fay -- 10/24/02
192 if ( FETCH_WCB( *window, Visibility ) )
194 SFG_Window *current_window = fgStructure.CurrentWindow ;
196 INVOKE_WCB( *window, Visibility, ( window->State.Visible ) );
197 fgSetWindow( current_window );
200 window = (SFG_Window *)window->Node.Next ;
206 * Determine a GLUT modifer mask based on MS-WINDOWS system info.
208 static int fgPlatformGetModifiers (void)
211 ( ( ( GetKeyState( VK_LSHIFT ) < 0 ) ||
212 ( GetKeyState( VK_RSHIFT ) < 0 )) ? GLUT_ACTIVE_SHIFT : 0 ) |
213 ( ( ( GetKeyState( VK_LCONTROL ) < 0 ) ||
214 ( GetKeyState( VK_RCONTROL ) < 0 )) ? GLUT_ACTIVE_CTRL : 0 ) |
215 ( ( ( GetKeyState( VK_LMENU ) < 0 ) ||
216 ( GetKeyState( VK_RMENU ) < 0 )) ? GLUT_ACTIVE_ALT : 0 );
220 * The window procedure for handling Win32 events
222 LRESULT CALLBACK fgPlatformWindowProc( HWND hWnd, UINT uMsg, WPARAM wParam,
225 static unsigned char lControl = 0, rControl = 0, lShift = 0,
226 rShift = 0, lAlt = 0, rAlt = 0;
232 FREEGLUT_INTERNAL_ERROR_EXIT_IF_NOT_INITIALISED ( "Event Handler" ) ;
234 window = fgWindowByHandle( hWnd );
236 if ( ( window == NULL ) && ( uMsg != WM_CREATE ) )
237 return DefWindowProc( hWnd, uMsg, wParam, lParam );
239 /* printf ( "Window %3d message <%04x> %12d %12d\n", window?window->ID:0,
240 uMsg, wParam, lParam ); */
242 /* events only sent to main window. Check if the current window that the mouse
243 is over is a child window and if so, make sure we call the callback on that
246 if (window && window->Children.First)
249 SFG_WindowHandleType hwnd;
251 GetCursorPos( &mouse_pos );
252 ScreenToClient( window->Window.Handle, &mouse_pos );
253 hwnd = ChildWindowFromPoint(window->Window.Handle, mouse_pos);
254 if (hwnd) /* can be NULL if mouse outside parent by the time we get here */
255 window = fgWindowByHandle(hwnd);
260 fgState.Modifiers = fgPlatformGetModifiers( );
262 /* Checking for CTRL, ALT, and SHIFT key positions: Key Down! */
263 if ( !lControl && GetAsyncKeyState ( VK_LCONTROL ) )
265 INVOKE_WCB ( *window, Special,
266 ( GLUT_KEY_CTRL_L, window->State.MouseX, window->State.MouseY )
272 if ( !rControl && GetAsyncKeyState ( VK_RCONTROL ) )
274 INVOKE_WCB ( *window, Special,
275 ( GLUT_KEY_CTRL_R, window->State.MouseX, window->State.MouseY )
281 if ( !lShift && GetAsyncKeyState ( VK_LSHIFT ) )
283 INVOKE_WCB ( *window, Special,
284 ( GLUT_KEY_SHIFT_L, window->State.MouseX, window->State.MouseY )
290 if ( !rShift && GetAsyncKeyState ( VK_RSHIFT ) )
292 INVOKE_WCB ( *window, Special,
293 ( GLUT_KEY_SHIFT_R, window->State.MouseX, window->State.MouseY )
299 if ( !lAlt && GetAsyncKeyState ( VK_LMENU ) )
301 INVOKE_WCB ( *window, Special,
302 ( GLUT_KEY_ALT_L, window->State.MouseX, window->State.MouseY )
308 if ( !rAlt && GetAsyncKeyState ( VK_RMENU ) )
310 INVOKE_WCB ( *window, Special,
311 ( GLUT_KEY_ALT_R, window->State.MouseX, window->State.MouseY )
317 /* Checking for CTRL, ALT, and SHIFT key positions: Key Up! */
318 if ( lControl && !GetAsyncKeyState ( VK_LCONTROL ) )
320 INVOKE_WCB ( *window, SpecialUp,
321 ( GLUT_KEY_CTRL_L, window->State.MouseX, window->State.MouseY )
327 if ( rControl && !GetAsyncKeyState ( VK_RCONTROL ) )
329 INVOKE_WCB ( *window, SpecialUp,
330 ( GLUT_KEY_CTRL_R, window->State.MouseX, window->State.MouseY )
336 if ( lShift && !GetAsyncKeyState ( VK_LSHIFT ) )
338 INVOKE_WCB ( *window, SpecialUp,
339 ( GLUT_KEY_SHIFT_L, window->State.MouseX, window->State.MouseY )
345 if ( rShift && !GetAsyncKeyState ( VK_RSHIFT ) )
347 INVOKE_WCB ( *window, SpecialUp,
348 ( GLUT_KEY_SHIFT_R, window->State.MouseX, window->State.MouseY )
354 if ( lAlt && !GetAsyncKeyState ( VK_LMENU ) )
356 INVOKE_WCB ( *window, SpecialUp,
357 ( GLUT_KEY_ALT_L, window->State.MouseX, window->State.MouseY )
363 if ( rAlt && !GetAsyncKeyState ( VK_RMENU ) )
365 INVOKE_WCB ( *window, SpecialUp,
366 ( GLUT_KEY_ALT_R, window->State.MouseX, window->State.MouseY )
372 fgState.Modifiers = INVALID_MODIFIERS;
378 /* The window structure is passed as the creation structure parameter... */
379 window = (SFG_Window *) (((LPCREATESTRUCT) lParam)->lpCreateParams);
380 FREEGLUT_INTERNAL_ERROR_EXIT ( ( window != NULL ), "Cannot create window",
381 "fgPlatformWindowProc" );
383 window->Window.Handle = hWnd;
384 window->Window.pContext.Device = GetDC( hWnd );
387 unsigned int current_DisplayMode = fgState.DisplayMode;
388 fgState.DisplayMode = GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH;
389 #if !defined(_WIN32_WCE)
390 fgSetupPixelFormat( window, GL_FALSE, PFD_MAIN_PLANE );
392 fgState.DisplayMode = current_DisplayMode;
394 if( fgStructure.MenuContext )
395 wglMakeCurrent( window->Window.pContext.Device,
396 fgStructure.MenuContext->MContext
400 fgStructure.MenuContext =
401 (SFG_MenuContext *)malloc( sizeof(SFG_MenuContext) );
402 fgStructure.MenuContext->MContext =
403 wglCreateContext( window->Window.pContext.Device );
406 /* window->Window.Context = wglGetCurrentContext (); */
407 window->Window.Context = wglCreateContext( window->Window.pContext.Device );
411 #if !defined(_WIN32_WCE)
412 fgSetupPixelFormat( window, GL_FALSE, PFD_MAIN_PLANE );
415 if( ! fgState.UseCurrentContext )
416 window->Window.Context =
417 wglCreateContext( window->Window.pContext.Device );
420 window->Window.Context = wglGetCurrentContext( );
421 if( ! window->Window.Context )
422 window->Window.Context =
423 wglCreateContext( window->Window.pContext.Device );
426 #if !defined(_WIN32_WCE)
427 fgNewWGLCreateContext( window );
431 window->State.NeedToResize = GL_TRUE;
432 /* if we used CW_USEDEFAULT (thats a negative value) for the size
433 * of the window, query the window now for the size at which it
436 if( ( window->State.Width < 0 ) || ( window->State.Height < 0 ) )
438 SFG_Window *current_window = fgStructure.CurrentWindow;
440 fgSetWindow( window );
441 window->State.Width = glutGet( GLUT_WINDOW_WIDTH );
442 window->State.Height = glutGet( GLUT_WINDOW_HEIGHT );
443 fgSetWindow( current_window );
446 ReleaseDC( window->Window.Handle, window->Window.pContext.Device );
448 #if defined(_WIN32_WCE)
449 /* Take over button handling */
451 HINSTANCE dxDllLib=LoadLibrary(_T("gx.dll"));
454 GXGetDefaultKeys_=(GXGETDEFAULTKEYS)GetProcAddress(dxDllLib, _T("?GXGetDefaultKeys@@YA?AUGXKeyList@@H@Z"));
455 GXOpenInput_=(GXOPENINPUT)GetProcAddress(dxDllLib, _T("?GXOpenInput@@YAHXZ"));
460 if(GXGetDefaultKeys_)
461 gxKeyList = (*GXGetDefaultKeys_)(GX_LANDSCAPEKEYS);
464 #endif /* defined(_WIN32_WCE) */
469 * If the window is visible, then it is the user manually resizing it.
470 * If it is not, then it is the system sending us a dummy resize with
471 * zero dimensions on a "glutIconifyWindow" call.
473 if( window->State.Visible )
475 window->State.NeedToResize = GL_TRUE;
476 #if defined(_WIN32_WCE)
477 window->State.Width = HIWORD(lParam);
478 window->State.Height = LOWORD(lParam);
480 window->State.Width = LOWORD(lParam);
481 window->State.Height = HIWORD(lParam);
482 #endif /* defined(_WIN32_WCE) */
488 /* printf("WM_SETFOCUS: %p\n", window ); */
489 lRet = DefWindowProc( hWnd, uMsg, wParam, lParam );
490 INVOKE_WCB( *window, Entry, ( GLUT_ENTERED ) );
492 UpdateWindow ( hWnd );
497 SFG_Menu* menu = NULL;
498 /* printf("WM_KILLFOCUS: %p\n", window ); */
499 lRet = DefWindowProc( hWnd, uMsg, wParam, lParam );
500 INVOKE_WCB( *window, Entry, ( GLUT_LEFT ) );
502 /* If we have an open menu, see if the open menu should be closed
503 when focus was lost because user either switched
504 application or FreeGLUT window (if one is running multiple
505 windows). If so, close menu the active menu.
507 if ( fgStructure.Menus.First )
508 menu = fgGetActiveMenu();
512 SFG_Window* wnd = NULL;
513 HWND hwnd = GetFocus(); /* Get window with current focus - NULL for non freeglut windows */
515 /* See which of our windows it is */
516 wnd = fgWindowByHandle(hwnd);
519 /* User switched to another application*/
520 fgDeactivateMenu(menu->ParentWindow);
521 else if (!wnd->IsMenu && wnd!=menu->ParentWindow) /* Make sure we don't kill the menu when trying to enter a submenu */
522 /* User switched to another FreeGLUT window */
523 fgDeactivateMenu(menu->ParentWindow);
530 if (LOWORD(wParam) != WA_INACTIVE)
532 /* printf("WM_ACTIVATE: fgSetCursor( %p, %d)\n", window,
533 window->State.Cursor ); */
534 fgSetCursor( window, window->State.Cursor );
537 lRet = DefWindowProc( hWnd, uMsg, wParam, lParam );
542 /* printf ( "Cursor event %x %x %x %x\n", window, window->State.Cursor, lParam, wParam ) ; */
543 if( LOWORD( lParam ) == HTCLIENT )
544 fgSetCursor ( window, window->State.Cursor ) ;
546 lRet = DefWindowProc( hWnd, uMsg, wParam, lParam );
550 window->State.Visible = GL_TRUE;
551 window->State.Redisplay = GL_TRUE;
555 /* Turn on the visibility in case it was turned off somehow */
556 window->State.Visible = GL_TRUE;
557 BeginPaint( hWnd, &ps );
558 fghRedrawWindow( window );
559 EndPaint( hWnd, &ps );
563 fgDestroyWindow ( window );
564 if ( fgState.ActionOnWindowClose != GLUT_ACTION_CONTINUE_EXECUTION )
570 * The window already got destroyed, so don't bother with it.
576 #if defined(_WIN32_WCE)
577 window->State.MouseX = 320-HIWORD( lParam );
578 window->State.MouseY = LOWORD( lParam );
580 window->State.MouseX = LOWORD( lParam );
581 window->State.MouseY = HIWORD( lParam );
582 #endif /* defined(_WIN32_WCE) */
583 /* Restrict to [-32768, 32767] to match X11 behaviour */
584 /* See comment in "freeglut_developer" mailing list 10/4/04 */
585 if ( window->State.MouseX > 32767 ) window->State.MouseX -= 65536;
586 if ( window->State.MouseY > 32767 ) window->State.MouseY -= 65536;
588 if ( window->ActiveMenu )
590 fgUpdateMenuHighlight( window->ActiveMenu );
594 fgState.Modifiers = fgPlatformGetModifiers( );
596 if( ( wParam & MK_LBUTTON ) ||
597 ( wParam & MK_MBUTTON ) ||
598 ( wParam & MK_RBUTTON ) )
599 INVOKE_WCB( *window, Motion, ( window->State.MouseX,
600 window->State.MouseY ) );
602 INVOKE_WCB( *window, Passive, ( window->State.MouseX,
603 window->State.MouseY ) );
605 fgState.Modifiers = INVALID_MODIFIERS;
616 GLboolean pressed = GL_TRUE;
619 #if defined(_WIN32_WCE)
620 window->State.MouseX = 320-HIWORD( lParam );
621 window->State.MouseY = LOWORD( lParam );
623 window->State.MouseX = LOWORD( lParam );
624 window->State.MouseY = HIWORD( lParam );
625 #endif /* defined(_WIN32_WCE) */
627 /* Restrict to [-32768, 32767] to match X11 behaviour */
628 /* See comment in "freeglut_developer" mailing list 10/4/04 */
629 if ( window->State.MouseX > 32767 ) window->State.MouseX -= 65536;
630 if ( window->State.MouseY > 32767 ) window->State.MouseY -= 65536;
636 button = GLUT_LEFT_BUTTON;
640 button = GLUT_MIDDLE_BUTTON;
644 button = GLUT_RIGHT_BUTTON;
648 button = GLUT_LEFT_BUTTON;
652 button = GLUT_MIDDLE_BUTTON;
656 button = GLUT_RIGHT_BUTTON;
664 #if !defined(_WIN32_WCE)
665 if( GetSystemMetrics( SM_SWAPBUTTON ) )
667 if( button == GLUT_LEFT_BUTTON )
668 button = GLUT_RIGHT_BUTTON;
670 if( button == GLUT_RIGHT_BUTTON )
671 button = GLUT_LEFT_BUTTON;
673 #endif /* !defined(_WIN32_WCE) */
676 return DefWindowProc( hWnd, uMsg, lParam, wParam );
679 * Do not execute the application's mouse callback if a menu
680 * is hooked to this button. In that case an appropriate
681 * private call should be generated.
683 if( fgCheckActiveMenu( window, button, pressed,
684 window->State.MouseX, window->State.MouseY ) )
687 /* Set capture so that the window captures all the mouse messages */
689 * XXX - Multiple button support: Under X11, the mouse is not released
690 * XXX - from the window until all buttons have been released, even if the
691 * XXX - user presses a button in another window. This will take more
692 * XXX - code changes than I am up to at the moment (10/5/04). The present
693 * XXX - is a 90 percent solution.
695 if ( pressed == GL_TRUE )
696 SetCapture ( window->Window.Handle ) ;
700 if( ! FETCH_WCB( *window, Mouse ) )
703 fgSetWindow( window );
704 fgState.Modifiers = fgPlatformGetModifiers( );
709 pressed ? GLUT_DOWN : GLUT_UP,
710 window->State.MouseX,
715 fgState.Modifiers = INVALID_MODIFIERS;
721 int wheel_number = LOWORD( wParam );
722 short ticks = ( short )HIWORD( wParam );
723 fgState.MouseWheelTicks += ticks;
726 * XXX Should use WHEEL_DELTA instead of 120
728 if ( abs ( fgState.MouseWheelTicks ) >= 120 )
730 int direction = ( fgState.MouseWheelTicks > 0 ) ? 1 : -1;
732 if( ! FETCH_WCB( *window, MouseWheel ) &&
733 ! FETCH_WCB( *window, Mouse ) )
736 fgSetWindow( window );
737 fgState.Modifiers = fgPlatformGetModifiers( );
740 * XXX Should use WHEEL_DELTA instead of 120
742 while( abs ( fgState.MouseWheelTicks ) >= 120 )
744 if( FETCH_WCB( *window, MouseWheel ) )
745 INVOKE_WCB( *window, MouseWheel,
748 window->State.MouseX,
752 else /* No mouse wheel, call the mouse button callback twice */
755 * Map wheel zero to button 3 and 4; +1 to 3, -1 to 4
756 * " " one +1 to 5, -1 to 6, ...
758 * XXX The below assumes that you have no more than 3 mouse
759 * XXX buttons. Sorry.
761 int button = wheel_number * 2 + 3;
764 INVOKE_WCB( *window, Mouse,
766 window->State.MouseX, window->State.MouseY )
768 INVOKE_WCB( *window, Mouse,
770 window->State.MouseX, window->State.MouseY )
775 * XXX Should use WHEEL_DELTA instead of 120
777 fgState.MouseWheelTicks -= 120 * direction;
780 fgState.Modifiers = INVALID_MODIFIERS;
792 if( ( fgState.KeyRepeat==GLUT_KEY_REPEAT_OFF || window->State.IgnoreKeyRepeat==GL_TRUE ) && (HIWORD(lParam) & KF_REPEAT) )
796 * Remember the current modifiers state. This is done here in order
797 * to make sure the VK_DELETE keyboard callback is executed properly.
799 fgState.Modifiers = fgPlatformGetModifiers( );
801 GetCursorPos( &mouse_pos );
802 ScreenToClient( window->Window.Handle, &mouse_pos );
804 window->State.MouseX = mouse_pos.x;
805 window->State.MouseY = mouse_pos.y;
807 /* Convert the Win32 keystroke codes to GLUTtish way */
808 # define KEY(a,b) case a: keypress = b; break;
812 KEY( VK_F1, GLUT_KEY_F1 );
813 KEY( VK_F2, GLUT_KEY_F2 );
814 KEY( VK_F3, GLUT_KEY_F3 );
815 KEY( VK_F4, GLUT_KEY_F4 );
816 KEY( VK_F5, GLUT_KEY_F5 );
817 KEY( VK_F6, GLUT_KEY_F6 );
818 KEY( VK_F7, GLUT_KEY_F7 );
819 KEY( VK_F8, GLUT_KEY_F8 );
820 KEY( VK_F9, GLUT_KEY_F9 );
821 KEY( VK_F10, GLUT_KEY_F10 );
822 KEY( VK_F11, GLUT_KEY_F11 );
823 KEY( VK_F12, GLUT_KEY_F12 );
824 KEY( VK_PRIOR, GLUT_KEY_PAGE_UP );
825 KEY( VK_NEXT, GLUT_KEY_PAGE_DOWN );
826 KEY( VK_HOME, GLUT_KEY_HOME );
827 KEY( VK_END, GLUT_KEY_END );
828 KEY( VK_LEFT, GLUT_KEY_LEFT );
829 KEY( VK_UP, GLUT_KEY_UP );
830 KEY( VK_RIGHT, GLUT_KEY_RIGHT );
831 KEY( VK_DOWN, GLUT_KEY_DOWN );
832 KEY( VK_INSERT, GLUT_KEY_INSERT );
834 case VK_LCONTROL: case VK_RCONTROL: case VK_CONTROL:
835 case VK_LSHIFT: case VK_RSHIFT: case VK_SHIFT:
836 case VK_LMENU: case VK_RMENU: case VK_MENU:
837 /* These keypresses and releases are handled earlier in the function */
841 /* The delete key should be treated as an ASCII keypress: */
842 INVOKE_WCB( *window, Keyboard,
843 ( 127, window->State.MouseX, window->State.MouseY )
847 #if defined(_WIN32_WCE)
848 if(!(lParam & 0x40000000)) /* Prevent auto-repeat */
850 if(wParam==(unsigned)gxKeyList.vkRight)
851 keypress = GLUT_KEY_RIGHT;
852 else if(wParam==(unsigned)gxKeyList.vkLeft)
853 keypress = GLUT_KEY_LEFT;
854 else if(wParam==(unsigned)gxKeyList.vkUp)
855 keypress = GLUT_KEY_UP;
856 else if(wParam==(unsigned)gxKeyList.vkDown)
857 keypress = GLUT_KEY_DOWN;
858 else if(wParam==(unsigned)gxKeyList.vkA)
859 keypress = GLUT_KEY_F1;
860 else if(wParam==(unsigned)gxKeyList.vkB)
861 keypress = GLUT_KEY_F2;
862 else if(wParam==(unsigned)gxKeyList.vkC)
863 keypress = GLUT_KEY_F3;
864 else if(wParam==(unsigned)gxKeyList.vkStart)
865 keypress = GLUT_KEY_F4;
870 INVOKE_WCB( *window, Special,
872 window->State.MouseX, window->State.MouseY )
875 fgState.Modifiers = INVALID_MODIFIERS;
886 * Remember the current modifiers state. This is done here in order
887 * to make sure the VK_DELETE keyboard callback is executed properly.
889 fgState.Modifiers = fgPlatformGetModifiers( );
891 GetCursorPos( &mouse_pos );
892 ScreenToClient( window->Window.Handle, &mouse_pos );
894 window->State.MouseX = mouse_pos.x;
895 window->State.MouseY = mouse_pos.y;
898 * Convert the Win32 keystroke codes to GLUTtish way.
899 * "KEY(a,b)" was defined under "WM_KEYDOWN"
904 KEY( VK_F1, GLUT_KEY_F1 );
905 KEY( VK_F2, GLUT_KEY_F2 );
906 KEY( VK_F3, GLUT_KEY_F3 );
907 KEY( VK_F4, GLUT_KEY_F4 );
908 KEY( VK_F5, GLUT_KEY_F5 );
909 KEY( VK_F6, GLUT_KEY_F6 );
910 KEY( VK_F7, GLUT_KEY_F7 );
911 KEY( VK_F8, GLUT_KEY_F8 );
912 KEY( VK_F9, GLUT_KEY_F9 );
913 KEY( VK_F10, GLUT_KEY_F10 );
914 KEY( VK_F11, GLUT_KEY_F11 );
915 KEY( VK_F12, GLUT_KEY_F12 );
916 KEY( VK_PRIOR, GLUT_KEY_PAGE_UP );
917 KEY( VK_NEXT, GLUT_KEY_PAGE_DOWN );
918 KEY( VK_HOME, GLUT_KEY_HOME );
919 KEY( VK_END, GLUT_KEY_END );
920 KEY( VK_LEFT, GLUT_KEY_LEFT );
921 KEY( VK_UP, GLUT_KEY_UP );
922 KEY( VK_RIGHT, GLUT_KEY_RIGHT );
923 KEY( VK_DOWN, GLUT_KEY_DOWN );
924 KEY( VK_INSERT, GLUT_KEY_INSERT );
926 case VK_LCONTROL: case VK_RCONTROL: case VK_CONTROL:
927 case VK_LSHIFT: case VK_RSHIFT: case VK_SHIFT:
928 case VK_LMENU: case VK_RMENU: case VK_MENU:
929 /* These keypresses and releases are handled earlier in the function */
933 /* The delete key should be treated as an ASCII keypress: */
934 INVOKE_WCB( *window, KeyboardUp,
935 ( 127, window->State.MouseX, window->State.MouseY )
941 #if !defined(_WIN32_WCE)
945 GetKeyboardState( state );
947 if( ToAscii( (UINT)wParam, 0, state, code, 0 ) == 1 )
950 INVOKE_WCB( *window, KeyboardUp,
952 window->State.MouseX, window->State.MouseY )
954 #endif /* !defined(_WIN32_WCE) */
959 INVOKE_WCB( *window, SpecialUp,
961 window->State.MouseX, window->State.MouseY )
964 fgState.Modifiers = INVALID_MODIFIERS;
971 if( (fgState.KeyRepeat==GLUT_KEY_REPEAT_OFF || window->State.IgnoreKeyRepeat==GL_TRUE) && (HIWORD(lParam) & KF_REPEAT) )
974 fgState.Modifiers = fgPlatformGetModifiers( );
975 INVOKE_WCB( *window, Keyboard,
977 window->State.MouseX, window->State.MouseY )
979 fgState.Modifiers = INVALID_MODIFIERS;
983 case WM_CAPTURECHANGED:
984 /* User has finished resizing the window, force a redraw */
985 INVOKE_WCB( *window, Display, ( ) );
987 /*lRet = DefWindowProc( hWnd, uMsg, wParam, lParam ); */
990 /* Other messages that I have seen and which are not handled already */
991 case WM_SETTEXT: /* 0x000c */
992 lRet = DefWindowProc( hWnd, uMsg, wParam, lParam );
993 /* Pass it on to "DefWindowProc" to set the window text */
996 case WM_GETTEXT: /* 0x000d */
997 /* Ideally we would copy the title of the window into "lParam" */
998 /* strncpy ( (char *)lParam, "Window Title", wParam );
999 lRet = ( wParam > 12 ) ? 12 : wParam; */
1000 /* the number of characters copied */
1001 lRet = DefWindowProc( hWnd, uMsg, wParam, lParam );
1004 case WM_GETTEXTLENGTH: /* 0x000e */
1005 /* Ideally we would get the length of the title of the window */
1007 /* the number of characters in "Window Title\0" (see above) */
1010 case WM_ERASEBKGND: /* 0x0014 */
1011 lRet = DefWindowProc( hWnd, uMsg, wParam, lParam );
1014 #if !defined(_WIN32_WCE)
1015 case WM_SYNCPAINT: /* 0x0088 */
1016 /* Another window has moved, need to update this one */
1017 window->State.Redisplay = GL_TRUE;
1018 lRet = DefWindowProc( hWnd, uMsg, wParam, lParam );
1019 /* Help screen says this message must be passed to "DefWindowProc" */
1022 case WM_NCPAINT: /* 0x0085 */
1023 /* Need to update the border of this window */
1024 lRet = DefWindowProc( hWnd, uMsg, wParam, lParam );
1025 /* Pass it on to "DefWindowProc" to repaint a standard border */
1028 case WM_SYSCOMMAND : /* 0x0112 */
1031 * We have received a system command message. Try to act on it.
1032 * The commands are passed in through the "wParam" parameter:
1033 * The least significant digit seems to be which edge of the window
1034 * is being used for a resize event:
1038 * Congratulations and thanks to Richard Rauch for figuring this out..
1040 switch ( wParam & 0xfff0 )
1049 /* User has clicked on the "-" to minimize the window */
1050 /* Turn off the visibility */
1051 window->State.Visible = GL_FALSE ;
1058 case SC_NEXTWINDOW :
1061 case SC_PREVWINDOW :
1065 /* Followed very closely by a WM_CLOSE message */
1089 case SC_SCREENSAVE :
1095 #if(WINVER >= 0x0400)
1099 case SC_MONITORPOWER :
1102 case SC_CONTEXTHELP :
1104 #endif /* WINVER >= 0x0400 */
1108 fgWarning( "Unknown wParam type 0x%x", wParam );
1113 #endif /* !defined(_WIN32_WCE) */
1115 /* We need to pass the message on to the operating system as well */
1116 lRet = DefWindowProc( hWnd, uMsg, wParam, lParam );
1120 /* handle multi-touch messages */
1123 unsigned int numInputs = (unsigned int)wParam;
1125 TOUCHINPUT* ti = (TOUCHINPUT*)malloc( sizeof(TOUCHINPUT)*numInputs);
1127 if (fghGetTouchInputInfo == (pGetTouchInputInfo)0xDEADBEEF) {
1128 fghGetTouchInputInfo = (pGetTouchInputInfo)GetProcAddress(GetModuleHandle("user32"),"GetTouchInputInfo");
1129 fghCloseTouchInputHandle = (pCloseTouchInputHandle)GetProcAddress(GetModuleHandle("user32"),"CloseTouchInputHandle");
1132 if (!fghGetTouchInputInfo) {
1137 if (fghGetTouchInputInfo( (HTOUCHINPUT)lParam, numInputs, ti, sizeof(TOUCHINPUT) )) {
1138 /* Handle each contact point */
1139 for (i = 0; i < numInputs; ++i ) {
1142 tp.x = TOUCH_COORD_TO_PIXEL(ti[i].x);
1143 tp.y = TOUCH_COORD_TO_PIXEL(ti[i].y);
1144 ScreenToClient( hWnd, &tp );
1146 ti[i].dwID = ti[i].dwID * 2;
1148 if (ti[i].dwFlags & TOUCHEVENTF_DOWN) {
1149 INVOKE_WCB( *window, MultiEntry, ( ti[i].dwID, GLUT_ENTERED ) );
1150 INVOKE_WCB( *window, MultiButton, ( ti[i].dwID, tp.x, tp.y, 0, GLUT_DOWN ) );
1151 } else if (ti[i].dwFlags & TOUCHEVENTF_MOVE) {
1152 INVOKE_WCB( *window, MultiMotion, ( ti[i].dwID, tp.x, tp.y ) );
1153 } else if (ti[i].dwFlags & TOUCHEVENTF_UP) {
1154 INVOKE_WCB( *window, MultiButton, ( ti[i].dwID, tp.x, tp.y, 0, GLUT_UP ) );
1155 INVOKE_WCB( *window, MultiEntry, ( ti[i].dwID, GLUT_LEFT ) );
1159 fghCloseTouchInputHandle((HTOUCHINPUT)lParam);
1161 lRet = 0; /*DefWindowProc( hWnd, uMsg, wParam, lParam );*/
1166 /* Handle unhandled messages */
1167 lRet = DefWindowProc( hWnd, uMsg, wParam, lParam );