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 */
514 printf(" hwnd: %p\n",hwnd);
516 /* See which of our windows it is */
517 wnd = fgWindowByHandle(hwnd);
519 //printf(" got menu: %p\n",menu);
521 printf(" wnd: %p, wnd->AM->PW: %p, menu->PW: %p\n",wnd,wnd&&wnd->ActiveMenu?wnd->ActiveMenu->ParentWindow:0,menu->ParentWindow);
523 printf(" wnd menu: %i, wnd->ActiveMenu: %p, wnd->Parent: %p\n",wnd->IsMenu,wnd->ActiveMenu,wnd->Parent);
527 /* User switched to another application*/
528 fgDeactivateMenu(menu->ParentWindow);
529 printf(" -> kill1\n");
531 else if (!wnd->IsMenu && wnd!=menu->ParentWindow)
533 /* User switched to another FreeGLUT window */
534 fgDeactivateMenu(menu->ParentWindow);
535 printf(" -> kill2\n");
540 printf(" -> survive\n");
548 if (LOWORD(wParam) != WA_INACTIVE)
550 /* printf("WM_ACTIVATE: fgSetCursor( %p, %d)\n", window,
551 window->State.Cursor ); */
552 fgSetCursor( window, window->State.Cursor );
555 lRet = DefWindowProc( hWnd, uMsg, wParam, lParam );
560 /* printf ( "Cursor event %x %x %x %x\n", window, window->State.Cursor, lParam, wParam ) ; */
561 if( LOWORD( lParam ) == HTCLIENT )
562 fgSetCursor ( window, window->State.Cursor ) ;
564 lRet = DefWindowProc( hWnd, uMsg, wParam, lParam );
568 window->State.Visible = GL_TRUE;
569 window->State.Redisplay = GL_TRUE;
573 /* Turn on the visibility in case it was turned off somehow */
574 window->State.Visible = GL_TRUE;
575 BeginPaint( hWnd, &ps );
576 fghRedrawWindow( window );
577 EndPaint( hWnd, &ps );
581 fgDestroyWindow ( window );
582 if ( fgState.ActionOnWindowClose != GLUT_ACTION_CONTINUE_EXECUTION )
588 * The window already got destroyed, so don't bother with it.
594 #if defined(_WIN32_WCE)
595 window->State.MouseX = 320-HIWORD( lParam );
596 window->State.MouseY = LOWORD( lParam );
598 window->State.MouseX = LOWORD( lParam );
599 window->State.MouseY = HIWORD( lParam );
600 #endif /* defined(_WIN32_WCE) */
601 /* Restrict to [-32768, 32767] to match X11 behaviour */
602 /* See comment in "freeglut_developer" mailing list 10/4/04 */
603 if ( window->State.MouseX > 32767 ) window->State.MouseX -= 65536;
604 if ( window->State.MouseY > 32767 ) window->State.MouseY -= 65536;
606 if ( window->ActiveMenu )
608 fgUpdateMenuHighlight( window->ActiveMenu );
612 fgState.Modifiers = fgPlatformGetModifiers( );
614 if( ( wParam & MK_LBUTTON ) ||
615 ( wParam & MK_MBUTTON ) ||
616 ( wParam & MK_RBUTTON ) )
617 INVOKE_WCB( *window, Motion, ( window->State.MouseX,
618 window->State.MouseY ) );
620 INVOKE_WCB( *window, Passive, ( window->State.MouseX,
621 window->State.MouseY ) );
623 fgState.Modifiers = INVALID_MODIFIERS;
634 GLboolean pressed = GL_TRUE;
637 #if defined(_WIN32_WCE)
638 window->State.MouseX = 320-HIWORD( lParam );
639 window->State.MouseY = LOWORD( lParam );
641 window->State.MouseX = LOWORD( lParam );
642 window->State.MouseY = HIWORD( lParam );
643 #endif /* defined(_WIN32_WCE) */
645 /* Restrict to [-32768, 32767] to match X11 behaviour */
646 /* See comment in "freeglut_developer" mailing list 10/4/04 */
647 if ( window->State.MouseX > 32767 ) window->State.MouseX -= 65536;
648 if ( window->State.MouseY > 32767 ) window->State.MouseY -= 65536;
654 button = GLUT_LEFT_BUTTON;
658 button = GLUT_MIDDLE_BUTTON;
662 button = GLUT_RIGHT_BUTTON;
666 button = GLUT_LEFT_BUTTON;
670 button = GLUT_MIDDLE_BUTTON;
674 button = GLUT_RIGHT_BUTTON;
682 #if !defined(_WIN32_WCE)
683 if( GetSystemMetrics( SM_SWAPBUTTON ) )
685 if( button == GLUT_LEFT_BUTTON )
686 button = GLUT_RIGHT_BUTTON;
688 if( button == GLUT_RIGHT_BUTTON )
689 button = GLUT_LEFT_BUTTON;
691 #endif /* !defined(_WIN32_WCE) */
694 return DefWindowProc( hWnd, uMsg, lParam, wParam );
697 * Do not execute the application's mouse callback if a menu
698 * is hooked to this button. In that case an appropriate
699 * private call should be generated.
701 if( fgCheckActiveMenu( window, button, pressed,
702 window->State.MouseX, window->State.MouseY ) )
705 /* Set capture so that the window captures all the mouse messages */
707 * XXX - Multiple button support: Under X11, the mouse is not released
708 * XXX - from the window until all buttons have been released, even if the
709 * XXX - user presses a button in another window. This will take more
710 * XXX - code changes than I am up to at the moment (10/5/04). The present
711 * XXX - is a 90 percent solution.
713 if ( pressed == GL_TRUE )
714 SetCapture ( window->Window.Handle ) ;
718 if( ! FETCH_WCB( *window, Mouse ) )
721 fgSetWindow( window );
722 fgState.Modifiers = fgPlatformGetModifiers( );
727 pressed ? GLUT_DOWN : GLUT_UP,
728 window->State.MouseX,
733 fgState.Modifiers = INVALID_MODIFIERS;
739 int wheel_number = LOWORD( wParam );
740 short ticks = ( short )HIWORD( wParam );
741 fgState.MouseWheelTicks += ticks;
744 * XXX Should use WHEEL_DELTA instead of 120
746 if ( abs ( fgState.MouseWheelTicks ) >= 120 )
748 int direction = ( fgState.MouseWheelTicks > 0 ) ? 1 : -1;
750 if( ! FETCH_WCB( *window, MouseWheel ) &&
751 ! FETCH_WCB( *window, Mouse ) )
754 fgSetWindow( window );
755 fgState.Modifiers = fgPlatformGetModifiers( );
758 * XXX Should use WHEEL_DELTA instead of 120
760 while( abs ( fgState.MouseWheelTicks ) >= 120 )
762 if( FETCH_WCB( *window, MouseWheel ) )
763 INVOKE_WCB( *window, MouseWheel,
766 window->State.MouseX,
770 else /* No mouse wheel, call the mouse button callback twice */
773 * Map wheel zero to button 3 and 4; +1 to 3, -1 to 4
774 * " " one +1 to 5, -1 to 6, ...
776 * XXX The below assumes that you have no more than 3 mouse
777 * XXX buttons. Sorry.
779 int button = wheel_number * 2 + 3;
782 INVOKE_WCB( *window, Mouse,
784 window->State.MouseX, window->State.MouseY )
786 INVOKE_WCB( *window, Mouse,
788 window->State.MouseX, window->State.MouseY )
793 * XXX Should use WHEEL_DELTA instead of 120
795 fgState.MouseWheelTicks -= 120 * direction;
798 fgState.Modifiers = INVALID_MODIFIERS;
810 if( ( fgState.KeyRepeat==GLUT_KEY_REPEAT_OFF || window->State.IgnoreKeyRepeat==GL_TRUE ) && (HIWORD(lParam) & KF_REPEAT) )
814 * Remember the current modifiers state. This is done here in order
815 * to make sure the VK_DELETE keyboard callback is executed properly.
817 fgState.Modifiers = fgPlatformGetModifiers( );
819 GetCursorPos( &mouse_pos );
820 ScreenToClient( window->Window.Handle, &mouse_pos );
822 window->State.MouseX = mouse_pos.x;
823 window->State.MouseY = mouse_pos.y;
825 /* Convert the Win32 keystroke codes to GLUTtish way */
826 # define KEY(a,b) case a: keypress = b; break;
830 KEY( VK_F1, GLUT_KEY_F1 );
831 KEY( VK_F2, GLUT_KEY_F2 );
832 KEY( VK_F3, GLUT_KEY_F3 );
833 KEY( VK_F4, GLUT_KEY_F4 );
834 KEY( VK_F5, GLUT_KEY_F5 );
835 KEY( VK_F6, GLUT_KEY_F6 );
836 KEY( VK_F7, GLUT_KEY_F7 );
837 KEY( VK_F8, GLUT_KEY_F8 );
838 KEY( VK_F9, GLUT_KEY_F9 );
839 KEY( VK_F10, GLUT_KEY_F10 );
840 KEY( VK_F11, GLUT_KEY_F11 );
841 KEY( VK_F12, GLUT_KEY_F12 );
842 KEY( VK_PRIOR, GLUT_KEY_PAGE_UP );
843 KEY( VK_NEXT, GLUT_KEY_PAGE_DOWN );
844 KEY( VK_HOME, GLUT_KEY_HOME );
845 KEY( VK_END, GLUT_KEY_END );
846 KEY( VK_LEFT, GLUT_KEY_LEFT );
847 KEY( VK_UP, GLUT_KEY_UP );
848 KEY( VK_RIGHT, GLUT_KEY_RIGHT );
849 KEY( VK_DOWN, GLUT_KEY_DOWN );
850 KEY( VK_INSERT, GLUT_KEY_INSERT );
852 case VK_LCONTROL: case VK_RCONTROL: case VK_CONTROL:
853 case VK_LSHIFT: case VK_RSHIFT: case VK_SHIFT:
854 case VK_LMENU: case VK_RMENU: case VK_MENU:
855 /* These keypresses and releases are handled earlier in the function */
859 /* The delete key should be treated as an ASCII keypress: */
860 INVOKE_WCB( *window, Keyboard,
861 ( 127, window->State.MouseX, window->State.MouseY )
865 #if defined(_WIN32_WCE)
866 if(!(lParam & 0x40000000)) /* Prevent auto-repeat */
868 if(wParam==(unsigned)gxKeyList.vkRight)
869 keypress = GLUT_KEY_RIGHT;
870 else if(wParam==(unsigned)gxKeyList.vkLeft)
871 keypress = GLUT_KEY_LEFT;
872 else if(wParam==(unsigned)gxKeyList.vkUp)
873 keypress = GLUT_KEY_UP;
874 else if(wParam==(unsigned)gxKeyList.vkDown)
875 keypress = GLUT_KEY_DOWN;
876 else if(wParam==(unsigned)gxKeyList.vkA)
877 keypress = GLUT_KEY_F1;
878 else if(wParam==(unsigned)gxKeyList.vkB)
879 keypress = GLUT_KEY_F2;
880 else if(wParam==(unsigned)gxKeyList.vkC)
881 keypress = GLUT_KEY_F3;
882 else if(wParam==(unsigned)gxKeyList.vkStart)
883 keypress = GLUT_KEY_F4;
888 INVOKE_WCB( *window, Special,
890 window->State.MouseX, window->State.MouseY )
893 fgState.Modifiers = INVALID_MODIFIERS;
904 * Remember the current modifiers state. This is done here in order
905 * to make sure the VK_DELETE keyboard callback is executed properly.
907 fgState.Modifiers = fgPlatformGetModifiers( );
909 GetCursorPos( &mouse_pos );
910 ScreenToClient( window->Window.Handle, &mouse_pos );
912 window->State.MouseX = mouse_pos.x;
913 window->State.MouseY = mouse_pos.y;
916 * Convert the Win32 keystroke codes to GLUTtish way.
917 * "KEY(a,b)" was defined under "WM_KEYDOWN"
922 KEY( VK_F1, GLUT_KEY_F1 );
923 KEY( VK_F2, GLUT_KEY_F2 );
924 KEY( VK_F3, GLUT_KEY_F3 );
925 KEY( VK_F4, GLUT_KEY_F4 );
926 KEY( VK_F5, GLUT_KEY_F5 );
927 KEY( VK_F6, GLUT_KEY_F6 );
928 KEY( VK_F7, GLUT_KEY_F7 );
929 KEY( VK_F8, GLUT_KEY_F8 );
930 KEY( VK_F9, GLUT_KEY_F9 );
931 KEY( VK_F10, GLUT_KEY_F10 );
932 KEY( VK_F11, GLUT_KEY_F11 );
933 KEY( VK_F12, GLUT_KEY_F12 );
934 KEY( VK_PRIOR, GLUT_KEY_PAGE_UP );
935 KEY( VK_NEXT, GLUT_KEY_PAGE_DOWN );
936 KEY( VK_HOME, GLUT_KEY_HOME );
937 KEY( VK_END, GLUT_KEY_END );
938 KEY( VK_LEFT, GLUT_KEY_LEFT );
939 KEY( VK_UP, GLUT_KEY_UP );
940 KEY( VK_RIGHT, GLUT_KEY_RIGHT );
941 KEY( VK_DOWN, GLUT_KEY_DOWN );
942 KEY( VK_INSERT, GLUT_KEY_INSERT );
944 case VK_LCONTROL: case VK_RCONTROL: case VK_CONTROL:
945 case VK_LSHIFT: case VK_RSHIFT: case VK_SHIFT:
946 case VK_LMENU: case VK_RMENU: case VK_MENU:
947 /* These keypresses and releases are handled earlier in the function */
951 /* The delete key should be treated as an ASCII keypress: */
952 INVOKE_WCB( *window, KeyboardUp,
953 ( 127, window->State.MouseX, window->State.MouseY )
959 #if !defined(_WIN32_WCE)
963 GetKeyboardState( state );
965 if( ToAscii( (UINT)wParam, 0, state, code, 0 ) == 1 )
968 INVOKE_WCB( *window, KeyboardUp,
970 window->State.MouseX, window->State.MouseY )
972 #endif /* !defined(_WIN32_WCE) */
977 INVOKE_WCB( *window, SpecialUp,
979 window->State.MouseX, window->State.MouseY )
982 fgState.Modifiers = INVALID_MODIFIERS;
989 if( (fgState.KeyRepeat==GLUT_KEY_REPEAT_OFF || window->State.IgnoreKeyRepeat==GL_TRUE) && (HIWORD(lParam) & KF_REPEAT) )
992 fgState.Modifiers = fgPlatformGetModifiers( );
993 INVOKE_WCB( *window, Keyboard,
995 window->State.MouseX, window->State.MouseY )
997 fgState.Modifiers = INVALID_MODIFIERS;
1001 case WM_CAPTURECHANGED:
1002 /* User has finished resizing the window, force a redraw */
1003 INVOKE_WCB( *window, Display, ( ) );
1005 /*lRet = DefWindowProc( hWnd, uMsg, wParam, lParam ); */
1008 /* Other messages that I have seen and which are not handled already */
1009 case WM_SETTEXT: /* 0x000c */
1010 lRet = DefWindowProc( hWnd, uMsg, wParam, lParam );
1011 /* Pass it on to "DefWindowProc" to set the window text */
1014 case WM_GETTEXT: /* 0x000d */
1015 /* Ideally we would copy the title of the window into "lParam" */
1016 /* strncpy ( (char *)lParam, "Window Title", wParam );
1017 lRet = ( wParam > 12 ) ? 12 : wParam; */
1018 /* the number of characters copied */
1019 lRet = DefWindowProc( hWnd, uMsg, wParam, lParam );
1022 case WM_GETTEXTLENGTH: /* 0x000e */
1023 /* Ideally we would get the length of the title of the window */
1025 /* the number of characters in "Window Title\0" (see above) */
1028 case WM_ERASEBKGND: /* 0x0014 */
1029 lRet = DefWindowProc( hWnd, uMsg, wParam, lParam );
1032 #if !defined(_WIN32_WCE)
1033 case WM_SYNCPAINT: /* 0x0088 */
1034 /* Another window has moved, need to update this one */
1035 window->State.Redisplay = GL_TRUE;
1036 lRet = DefWindowProc( hWnd, uMsg, wParam, lParam );
1037 /* Help screen says this message must be passed to "DefWindowProc" */
1040 case WM_NCPAINT: /* 0x0085 */
1041 /* Need to update the border of this window */
1042 lRet = DefWindowProc( hWnd, uMsg, wParam, lParam );
1043 /* Pass it on to "DefWindowProc" to repaint a standard border */
1046 case WM_SYSCOMMAND : /* 0x0112 */
1049 * We have received a system command message. Try to act on it.
1050 * The commands are passed in through the "wParam" parameter:
1051 * The least significant digit seems to be which edge of the window
1052 * is being used for a resize event:
1056 * Congratulations and thanks to Richard Rauch for figuring this out..
1058 switch ( wParam & 0xfff0 )
1067 /* User has clicked on the "-" to minimize the window */
1068 /* Turn off the visibility */
1069 window->State.Visible = GL_FALSE ;
1076 case SC_NEXTWINDOW :
1079 case SC_PREVWINDOW :
1083 /* Followed very closely by a WM_CLOSE message */
1107 case SC_SCREENSAVE :
1113 #if(WINVER >= 0x0400)
1117 case SC_MONITORPOWER :
1120 case SC_CONTEXTHELP :
1122 #endif /* WINVER >= 0x0400 */
1126 fgWarning( "Unknown wParam type 0x%x", wParam );
1131 #endif /* !defined(_WIN32_WCE) */
1133 /* We need to pass the message on to the operating system as well */
1134 lRet = DefWindowProc( hWnd, uMsg, wParam, lParam );
1138 /* handle multi-touch messages */
1141 unsigned int numInputs = (unsigned int)wParam;
1143 TOUCHINPUT* ti = (TOUCHINPUT*)malloc( sizeof(TOUCHINPUT)*numInputs);
1145 if (fghGetTouchInputInfo == (pGetTouchInputInfo)0xDEADBEEF) {
1146 fghGetTouchInputInfo = (pGetTouchInputInfo)GetProcAddress(GetModuleHandle("user32"),"GetTouchInputInfo");
1147 fghCloseTouchInputHandle = (pCloseTouchInputHandle)GetProcAddress(GetModuleHandle("user32"),"CloseTouchInputHandle");
1150 if (!fghGetTouchInputInfo) {
1155 if (fghGetTouchInputInfo( (HTOUCHINPUT)lParam, numInputs, ti, sizeof(TOUCHINPUT) )) {
1156 /* Handle each contact point */
1157 for (i = 0; i < numInputs; ++i ) {
1160 tp.x = TOUCH_COORD_TO_PIXEL(ti[i].x);
1161 tp.y = TOUCH_COORD_TO_PIXEL(ti[i].y);
1162 ScreenToClient( hWnd, &tp );
1164 ti[i].dwID = ti[i].dwID * 2;
1166 if (ti[i].dwFlags & TOUCHEVENTF_DOWN) {
1167 INVOKE_WCB( *window, MultiEntry, ( ti[i].dwID, GLUT_ENTERED ) );
1168 INVOKE_WCB( *window, MultiButton, ( ti[i].dwID, tp.x, tp.y, 0, GLUT_DOWN ) );
1169 } else if (ti[i].dwFlags & TOUCHEVENTF_MOVE) {
1170 INVOKE_WCB( *window, MultiMotion, ( ti[i].dwID, tp.x, tp.y ) );
1171 } else if (ti[i].dwFlags & TOUCHEVENTF_UP) {
1172 INVOKE_WCB( *window, MultiButton, ( ti[i].dwID, tp.x, tp.y, 0, GLUT_UP ) );
1173 INVOKE_WCB( *window, MultiEntry, ( ti[i].dwID, GLUT_LEFT ) );
1177 fghCloseTouchInputHandle((HTOUCHINPUT)lParam);
1179 lRet = 0; /*DefWindowProc( hWnd, uMsg, wParam, lParam );*/
1184 /* Handle unhandled messages */
1185 lRet = DefWindowProc( hWnd, uMsg, wParam, lParam );