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 );
496 /* printf("WM_KILLFOCUS (ismenu: %i): %p\n", window->IsMenu, window ); */
497 lRet = DefWindowProc( hWnd, uMsg, wParam, lParam );
498 INVOKE_WCB( *window, Entry, ( GLUT_LEFT ) );
500 /* If this is a menu that lost focus, see if user either switched
501 application or FreeGLUT window (if one is running multiple
502 windows). If so, close menu that lost focus.
504 if( window->IsMenu &&
505 window->ActiveMenu && window->ActiveMenu->IsActive )
507 SFG_Window* wnd = NULL;
508 HWND hwnd = GetForegroundWindow(); /* Get window with current focus */
510 /* See if its one of our windows */
511 wnd = fgWindowByHandle(hwnd);
514 /* User switched to another application*/
515 fgDeactivateMenu(window->ActiveMenu->ParentWindow);
517 ( wnd->IsMenu && wnd->ActiveMenu->ParentWindow!=window->ActiveMenu->ParentWindow) || /* Make sure we don't kill the menu when trying to enter a submenu */
518 (!wnd->IsMenu && wnd!=window->ActiveMenu->ParentWindow)
520 /* User switched to another FreeGLUT window */
521 fgDeactivateMenu(window->ActiveMenu->ParentWindow);
528 if (LOWORD(wParam) != WA_INACTIVE)
530 /* printf("WM_ACTIVATE: fgSetCursor( %p, %d)\n", window,
531 window->State.Cursor ); */
532 fgSetCursor( window, window->State.Cursor );
535 lRet = DefWindowProc( hWnd, uMsg, wParam, lParam );
540 /* printf ( "Cursor event %x %x %x %x\n", window, window->State.Cursor, lParam, wParam ) ; */
541 if( LOWORD( lParam ) == HTCLIENT )
542 fgSetCursor ( window, window->State.Cursor ) ;
544 lRet = DefWindowProc( hWnd, uMsg, wParam, lParam );
548 window->State.Visible = GL_TRUE;
549 window->State.Redisplay = GL_TRUE;
553 /* Turn on the visibility in case it was turned off somehow */
554 window->State.Visible = GL_TRUE;
555 BeginPaint( hWnd, &ps );
556 fghRedrawWindow( window );
557 EndPaint( hWnd, &ps );
561 fgDestroyWindow ( window );
562 if ( fgState.ActionOnWindowClose != GLUT_ACTION_CONTINUE_EXECUTION )
568 * The window already got destroyed, so don't bother with it.
574 #if defined(_WIN32_WCE)
575 window->State.MouseX = 320-HIWORD( lParam );
576 window->State.MouseY = LOWORD( lParam );
578 window->State.MouseX = LOWORD( lParam );
579 window->State.MouseY = HIWORD( lParam );
580 #endif /* defined(_WIN32_WCE) */
581 /* Restrict to [-32768, 32767] to match X11 behaviour */
582 /* See comment in "freeglut_developer" mailing list 10/4/04 */
583 if ( window->State.MouseX > 32767 ) window->State.MouseX -= 65536;
584 if ( window->State.MouseY > 32767 ) window->State.MouseY -= 65536;
586 if ( window->ActiveMenu )
588 fgUpdateMenuHighlight( window->ActiveMenu );
592 fgState.Modifiers = fgPlatformGetModifiers( );
594 if( ( wParam & MK_LBUTTON ) ||
595 ( wParam & MK_MBUTTON ) ||
596 ( wParam & MK_RBUTTON ) )
597 INVOKE_WCB( *window, Motion, ( window->State.MouseX,
598 window->State.MouseY ) );
600 INVOKE_WCB( *window, Passive, ( window->State.MouseX,
601 window->State.MouseY ) );
603 fgState.Modifiers = INVALID_MODIFIERS;
614 GLboolean pressed = GL_TRUE;
617 #if defined(_WIN32_WCE)
618 window->State.MouseX = 320-HIWORD( lParam );
619 window->State.MouseY = LOWORD( lParam );
621 window->State.MouseX = LOWORD( lParam );
622 window->State.MouseY = HIWORD( lParam );
623 #endif /* defined(_WIN32_WCE) */
625 /* Restrict to [-32768, 32767] to match X11 behaviour */
626 /* See comment in "freeglut_developer" mailing list 10/4/04 */
627 if ( window->State.MouseX > 32767 ) window->State.MouseX -= 65536;
628 if ( window->State.MouseY > 32767 ) window->State.MouseY -= 65536;
634 button = GLUT_LEFT_BUTTON;
638 button = GLUT_MIDDLE_BUTTON;
642 button = GLUT_RIGHT_BUTTON;
646 button = GLUT_LEFT_BUTTON;
650 button = GLUT_MIDDLE_BUTTON;
654 button = GLUT_RIGHT_BUTTON;
662 #if !defined(_WIN32_WCE)
663 if( GetSystemMetrics( SM_SWAPBUTTON ) )
665 if( button == GLUT_LEFT_BUTTON )
666 button = GLUT_RIGHT_BUTTON;
668 if( button == GLUT_RIGHT_BUTTON )
669 button = GLUT_LEFT_BUTTON;
671 #endif /* !defined(_WIN32_WCE) */
674 return DefWindowProc( hWnd, uMsg, lParam, wParam );
677 * Do not execute the application's mouse callback if a menu
678 * is hooked to this button. In that case an appropriate
679 * private call should be generated.
681 if( fgCheckActiveMenu( window, button, pressed,
682 window->State.MouseX, window->State.MouseY ) )
685 /* Set capture so that the window captures all the mouse messages */
687 * XXX - Multiple button support: Under X11, the mouse is not released
688 * XXX - from the window until all buttons have been released, even if the
689 * XXX - user presses a button in another window. This will take more
690 * XXX - code changes than I am up to at the moment (10/5/04). The present
691 * XXX - is a 90 percent solution.
693 if ( pressed == GL_TRUE )
694 SetCapture ( window->Window.Handle ) ;
698 if( ! FETCH_WCB( *window, Mouse ) )
701 fgSetWindow( window );
702 fgState.Modifiers = fgPlatformGetModifiers( );
707 pressed ? GLUT_DOWN : GLUT_UP,
708 window->State.MouseX,
713 fgState.Modifiers = INVALID_MODIFIERS;
719 int wheel_number = LOWORD( wParam );
720 short ticks = ( short )HIWORD( wParam );
721 fgState.MouseWheelTicks += ticks;
724 * XXX Should use WHEEL_DELTA instead of 120
726 if ( abs ( fgState.MouseWheelTicks ) >= 120 )
728 int direction = ( fgState.MouseWheelTicks > 0 ) ? 1 : -1;
730 if( ! FETCH_WCB( *window, MouseWheel ) &&
731 ! FETCH_WCB( *window, Mouse ) )
734 fgSetWindow( window );
735 fgState.Modifiers = fgPlatformGetModifiers( );
738 * XXX Should use WHEEL_DELTA instead of 120
740 while( abs ( fgState.MouseWheelTicks ) >= 120 )
742 if( FETCH_WCB( *window, MouseWheel ) )
743 INVOKE_WCB( *window, MouseWheel,
746 window->State.MouseX,
750 else /* No mouse wheel, call the mouse button callback twice */
753 * Map wheel zero to button 3 and 4; +1 to 3, -1 to 4
754 * " " one +1 to 5, -1 to 6, ...
756 * XXX The below assumes that you have no more than 3 mouse
757 * XXX buttons. Sorry.
759 int button = wheel_number * 2 + 3;
762 INVOKE_WCB( *window, Mouse,
764 window->State.MouseX, window->State.MouseY )
766 INVOKE_WCB( *window, Mouse,
768 window->State.MouseX, window->State.MouseY )
773 * XXX Should use WHEEL_DELTA instead of 120
775 fgState.MouseWheelTicks -= 120 * direction;
778 fgState.Modifiers = INVALID_MODIFIERS;
790 if( ( fgState.KeyRepeat==GLUT_KEY_REPEAT_OFF || window->State.IgnoreKeyRepeat==GL_TRUE ) && (HIWORD(lParam) & KF_REPEAT) )
794 * Remember the current modifiers state. This is done here in order
795 * to make sure the VK_DELETE keyboard callback is executed properly.
797 fgState.Modifiers = fgPlatformGetModifiers( );
799 GetCursorPos( &mouse_pos );
800 ScreenToClient( window->Window.Handle, &mouse_pos );
802 window->State.MouseX = mouse_pos.x;
803 window->State.MouseY = mouse_pos.y;
805 /* Convert the Win32 keystroke codes to GLUTtish way */
806 # define KEY(a,b) case a: keypress = b; break;
810 KEY( VK_F1, GLUT_KEY_F1 );
811 KEY( VK_F2, GLUT_KEY_F2 );
812 KEY( VK_F3, GLUT_KEY_F3 );
813 KEY( VK_F4, GLUT_KEY_F4 );
814 KEY( VK_F5, GLUT_KEY_F5 );
815 KEY( VK_F6, GLUT_KEY_F6 );
816 KEY( VK_F7, GLUT_KEY_F7 );
817 KEY( VK_F8, GLUT_KEY_F8 );
818 KEY( VK_F9, GLUT_KEY_F9 );
819 KEY( VK_F10, GLUT_KEY_F10 );
820 KEY( VK_F11, GLUT_KEY_F11 );
821 KEY( VK_F12, GLUT_KEY_F12 );
822 KEY( VK_PRIOR, GLUT_KEY_PAGE_UP );
823 KEY( VK_NEXT, GLUT_KEY_PAGE_DOWN );
824 KEY( VK_HOME, GLUT_KEY_HOME );
825 KEY( VK_END, GLUT_KEY_END );
826 KEY( VK_LEFT, GLUT_KEY_LEFT );
827 KEY( VK_UP, GLUT_KEY_UP );
828 KEY( VK_RIGHT, GLUT_KEY_RIGHT );
829 KEY( VK_DOWN, GLUT_KEY_DOWN );
830 KEY( VK_INSERT, GLUT_KEY_INSERT );
832 case VK_LCONTROL: case VK_RCONTROL: case VK_CONTROL:
833 case VK_LSHIFT: case VK_RSHIFT: case VK_SHIFT:
834 case VK_LMENU: case VK_RMENU: case VK_MENU:
835 /* These keypresses and releases are handled earlier in the function */
839 /* The delete key should be treated as an ASCII keypress: */
840 INVOKE_WCB( *window, Keyboard,
841 ( 127, window->State.MouseX, window->State.MouseY )
845 #if defined(_WIN32_WCE)
846 if(!(lParam & 0x40000000)) /* Prevent auto-repeat */
848 if(wParam==(unsigned)gxKeyList.vkRight)
849 keypress = GLUT_KEY_RIGHT;
850 else if(wParam==(unsigned)gxKeyList.vkLeft)
851 keypress = GLUT_KEY_LEFT;
852 else if(wParam==(unsigned)gxKeyList.vkUp)
853 keypress = GLUT_KEY_UP;
854 else if(wParam==(unsigned)gxKeyList.vkDown)
855 keypress = GLUT_KEY_DOWN;
856 else if(wParam==(unsigned)gxKeyList.vkA)
857 keypress = GLUT_KEY_F1;
858 else if(wParam==(unsigned)gxKeyList.vkB)
859 keypress = GLUT_KEY_F2;
860 else if(wParam==(unsigned)gxKeyList.vkC)
861 keypress = GLUT_KEY_F3;
862 else if(wParam==(unsigned)gxKeyList.vkStart)
863 keypress = GLUT_KEY_F4;
868 INVOKE_WCB( *window, Special,
870 window->State.MouseX, window->State.MouseY )
873 fgState.Modifiers = INVALID_MODIFIERS;
884 * Remember the current modifiers state. This is done here in order
885 * to make sure the VK_DELETE keyboard callback is executed properly.
887 fgState.Modifiers = fgPlatformGetModifiers( );
889 GetCursorPos( &mouse_pos );
890 ScreenToClient( window->Window.Handle, &mouse_pos );
892 window->State.MouseX = mouse_pos.x;
893 window->State.MouseY = mouse_pos.y;
896 * Convert the Win32 keystroke codes to GLUTtish way.
897 * "KEY(a,b)" was defined under "WM_KEYDOWN"
902 KEY( VK_F1, GLUT_KEY_F1 );
903 KEY( VK_F2, GLUT_KEY_F2 );
904 KEY( VK_F3, GLUT_KEY_F3 );
905 KEY( VK_F4, GLUT_KEY_F4 );
906 KEY( VK_F5, GLUT_KEY_F5 );
907 KEY( VK_F6, GLUT_KEY_F6 );
908 KEY( VK_F7, GLUT_KEY_F7 );
909 KEY( VK_F8, GLUT_KEY_F8 );
910 KEY( VK_F9, GLUT_KEY_F9 );
911 KEY( VK_F10, GLUT_KEY_F10 );
912 KEY( VK_F11, GLUT_KEY_F11 );
913 KEY( VK_F12, GLUT_KEY_F12 );
914 KEY( VK_PRIOR, GLUT_KEY_PAGE_UP );
915 KEY( VK_NEXT, GLUT_KEY_PAGE_DOWN );
916 KEY( VK_HOME, GLUT_KEY_HOME );
917 KEY( VK_END, GLUT_KEY_END );
918 KEY( VK_LEFT, GLUT_KEY_LEFT );
919 KEY( VK_UP, GLUT_KEY_UP );
920 KEY( VK_RIGHT, GLUT_KEY_RIGHT );
921 KEY( VK_DOWN, GLUT_KEY_DOWN );
922 KEY( VK_INSERT, GLUT_KEY_INSERT );
924 case VK_LCONTROL: case VK_RCONTROL: case VK_CONTROL:
925 case VK_LSHIFT: case VK_RSHIFT: case VK_SHIFT:
926 case VK_LMENU: case VK_RMENU: case VK_MENU:
927 /* These keypresses and releases are handled earlier in the function */
931 /* The delete key should be treated as an ASCII keypress: */
932 INVOKE_WCB( *window, KeyboardUp,
933 ( 127, window->State.MouseX, window->State.MouseY )
939 #if !defined(_WIN32_WCE)
943 GetKeyboardState( state );
945 if( ToAscii( (UINT)wParam, 0, state, code, 0 ) == 1 )
948 INVOKE_WCB( *window, KeyboardUp,
950 window->State.MouseX, window->State.MouseY )
952 #endif /* !defined(_WIN32_WCE) */
957 INVOKE_WCB( *window, SpecialUp,
959 window->State.MouseX, window->State.MouseY )
962 fgState.Modifiers = INVALID_MODIFIERS;
969 if( (fgState.KeyRepeat==GLUT_KEY_REPEAT_OFF || window->State.IgnoreKeyRepeat==GL_TRUE) && (HIWORD(lParam) & KF_REPEAT) )
972 fgState.Modifiers = fgPlatformGetModifiers( );
973 INVOKE_WCB( *window, Keyboard,
975 window->State.MouseX, window->State.MouseY )
977 fgState.Modifiers = INVALID_MODIFIERS;
981 case WM_CAPTURECHANGED:
982 /* User has finished resizing the window, force a redraw */
983 INVOKE_WCB( *window, Display, ( ) );
985 /*lRet = DefWindowProc( hWnd, uMsg, wParam, lParam ); */
988 /* Other messages that I have seen and which are not handled already */
989 case WM_SETTEXT: /* 0x000c */
990 lRet = DefWindowProc( hWnd, uMsg, wParam, lParam );
991 /* Pass it on to "DefWindowProc" to set the window text */
994 case WM_GETTEXT: /* 0x000d */
995 /* Ideally we would copy the title of the window into "lParam" */
996 /* strncpy ( (char *)lParam, "Window Title", wParam );
997 lRet = ( wParam > 12 ) ? 12 : wParam; */
998 /* the number of characters copied */
999 lRet = DefWindowProc( hWnd, uMsg, wParam, lParam );
1002 case WM_GETTEXTLENGTH: /* 0x000e */
1003 /* Ideally we would get the length of the title of the window */
1005 /* the number of characters in "Window Title\0" (see above) */
1008 case WM_ERASEBKGND: /* 0x0014 */
1009 lRet = DefWindowProc( hWnd, uMsg, wParam, lParam );
1012 #if !defined(_WIN32_WCE)
1013 case WM_SYNCPAINT: /* 0x0088 */
1014 /* Another window has moved, need to update this one */
1015 window->State.Redisplay = GL_TRUE;
1016 lRet = DefWindowProc( hWnd, uMsg, wParam, lParam );
1017 /* Help screen says this message must be passed to "DefWindowProc" */
1020 case WM_NCPAINT: /* 0x0085 */
1021 /* Need to update the border of this window */
1022 lRet = DefWindowProc( hWnd, uMsg, wParam, lParam );
1023 /* Pass it on to "DefWindowProc" to repaint a standard border */
1026 case WM_SYSCOMMAND : /* 0x0112 */
1029 * We have received a system command message. Try to act on it.
1030 * The commands are passed in through the "wParam" parameter:
1031 * The least significant digit seems to be which edge of the window
1032 * is being used for a resize event:
1036 * Congratulations and thanks to Richard Rauch for figuring this out..
1038 switch ( wParam & 0xfff0 )
1047 /* User has clicked on the "-" to minimize the window */
1048 /* Turn off the visibility */
1049 window->State.Visible = GL_FALSE ;
1056 case SC_NEXTWINDOW :
1059 case SC_PREVWINDOW :
1063 /* Followed very closely by a WM_CLOSE message */
1087 case SC_SCREENSAVE :
1093 #if(WINVER >= 0x0400)
1097 case SC_MONITORPOWER :
1100 case SC_CONTEXTHELP :
1102 #endif /* WINVER >= 0x0400 */
1106 fgWarning( "Unknown wParam type 0x%x", wParam );
1111 #endif /* !defined(_WIN32_WCE) */
1113 /* We need to pass the message on to the operating system as well */
1114 lRet = DefWindowProc( hWnd, uMsg, wParam, lParam );
1118 /* handle multi-touch messages */
1121 unsigned int numInputs = (unsigned int)wParam;
1123 TOUCHINPUT* ti = (TOUCHINPUT*)malloc( sizeof(TOUCHINPUT)*numInputs);
1125 if (fghGetTouchInputInfo == (pGetTouchInputInfo)0xDEADBEEF) {
1126 fghGetTouchInputInfo = (pGetTouchInputInfo)GetProcAddress(GetModuleHandle("user32"),"GetTouchInputInfo");
1127 fghCloseTouchInputHandle = (pCloseTouchInputHandle)GetProcAddress(GetModuleHandle("user32"),"CloseTouchInputHandle");
1130 if (!fghGetTouchInputInfo) {
1135 if (fghGetTouchInputInfo( (HTOUCHINPUT)lParam, numInputs, ti, sizeof(TOUCHINPUT) )) {
1136 /* Handle each contact point */
1137 for (i = 0; i < numInputs; ++i ) {
1140 tp.x = TOUCH_COORD_TO_PIXEL(ti[i].x);
1141 tp.y = TOUCH_COORD_TO_PIXEL(ti[i].y);
1142 ScreenToClient( hWnd, &tp );
1144 ti[i].dwID = ti[i].dwID * 2;
1146 if (ti[i].dwFlags & TOUCHEVENTF_DOWN) {
1147 INVOKE_WCB( *window, MultiEntry, ( ti[i].dwID, GLUT_ENTERED ) );
1148 INVOKE_WCB( *window, MultiButton, ( ti[i].dwID, tp.x, tp.y, 0, GLUT_DOWN ) );
1149 } else if (ti[i].dwFlags & TOUCHEVENTF_MOVE) {
1150 INVOKE_WCB( *window, MultiMotion, ( ti[i].dwID, tp.x, tp.y ) );
1151 } else if (ti[i].dwFlags & TOUCHEVENTF_UP) {
1152 INVOKE_WCB( *window, MultiButton, ( ti[i].dwID, tp.x, tp.y, 0, GLUT_UP ) );
1153 INVOKE_WCB( *window, MultiEntry, ( ti[i].dwID, GLUT_LEFT ) );
1157 fghCloseTouchInputHandle((HTOUCHINPUT)lParam);
1159 lRet = 0; /*DefWindowProc( hWnd, uMsg, wParam, lParam );*/
1164 /* Handle unhandled messages */
1165 lRet = DefWindowProc( hWnd, uMsg, wParam, lParam );