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 * Helper functions for getting client area from the window rect
63 * and the window rect from the client area given the style of the window
64 * (or a valid window pointer from which the style can be queried).
66 extern void fghComputeWindowRectFromClientArea_QueryWindow( RECT *clientRect, const SFG_Window *window, BOOL posIsOutside );
67 extern void fghGetClientArea ( RECT *clientRect, const SFG_Window *window, BOOL wantPosOutside );
70 void fgPlatformReshapeWindow ( SFG_Window *window, int width, int height )
75 * For windowed mode, get the current position of the
76 * window and resize taking the size of the frame
77 * decorations into account.
79 * Note on maximizing behavior of Windows: the resize borders are off
80 * the screen such that the client area extends all the way from the
81 * leftmost corner to the rightmost corner to maximize screen real
82 * estate. A caption is still shown however to allow interaction with
83 * the window controls. This is default behavior of Windows that
84 * FreeGLUT sticks with. To alter, one would have to check if
85 * WS_MAXIMIZE style is set when a resize event is triggered, and
86 * then manually correct the windowRect to put the borders back on
90 /* "GetWindowRect" returns the pixel coordinates of the outside of the window */
91 GetWindowRect( window->Window.Handle, &windowRect );
93 /* Create rect in FreeGLUT format, (X,Y) topleft outside window, WxH of client area */
94 windowRect.right = windowRect.left+width;
95 windowRect.bottom = windowRect.top+height;
97 if (window->Parent == NULL)
98 /* get the window rect from this to feed to SetWindowPos, correct for window decorations */
99 fghComputeWindowRectFromClientArea_QueryWindow(&windowRect,window,TRUE);
102 /* correct rect for position client area of parent window
103 * (SetWindowPos input for child windows is in coordinates
104 * relative to the parent's client area).
105 * Child windows don't have decoration, so no need to correct
109 fghGetClientArea( &parentRect, window->Parent, FALSE );
110 OffsetRect(&windowRect,-parentRect.left,-parentRect.top);
113 /* Do the actual resizing */
114 SetWindowPos( window->Window.Handle,
116 windowRect.left, windowRect.top,
117 windowRect.right - windowRect.left,
118 windowRect.bottom- windowRect.top,
119 SWP_NOACTIVATE | SWP_NOOWNERZORDER | SWP_NOSENDCHANGING |
123 /* Set new width and height so we can test for that in WM_SIZE message handler and don't do anything if not needed */
124 window->State.Width = width;
125 window->State.Height = height;
129 void fgPlatformDisplayWindow ( SFG_Window *window )
132 window->Window.Handle, NULL, NULL,
133 RDW_NOERASE | RDW_INTERNALPAINT | RDW_INVALIDATE | RDW_UPDATENOW
138 /* Get system time, taking special precautions against 32bit timer wrap.
139 We use timeGetTime and not GetTickCount because of its better stability,
140 and because we can increase its granularity (to 1 ms in
141 fgPlatformInitialize). For that reason we can't use GetTickCount64 which
142 wouldn't have the wrap issue.
143 Credit: this is based on code in glibc (https://mail.gnome.org/archives/commits-list/2011-November/msg04588.html)
145 static fg_time_t lastTime32 = 0;
146 static fg_time_t timeEpoch = 0;
147 void fgPlatformInitSystemTime()
149 #if defined(_WIN32_WCE)
150 lastTime32 = GetTickCount();
152 lastTime32 = timeGetTime();
155 fg_time_t fgPlatformSystemTime ( void )
157 fg_time_t currTime32;
158 #if defined(_WIN32_WCE)
159 currTime32 = GetTickCount();
161 currTime32 = timeGetTime();
163 /* Check if we just wrapped */
164 if (currTime32 < lastTime32)
167 lastTime32 = currTime32;
169 return currTime32 | timeEpoch << 32;
173 void fgPlatformSleepForEvents( fg_time_t msec )
175 MsgWaitForMultipleObjects( 0, NULL, FALSE, (DWORD) msec, QS_ALLINPUT );
179 void fgPlatformProcessSingleEvent ( void )
183 FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutMainLoopEvent" );
185 while( PeekMessage( &stMsg, NULL, 0, 0, PM_NOREMOVE ) )
187 if( GetMessage( &stMsg, NULL, 0, 0 ) == 0 )
189 if( fgState.ActionOnWindowClose == GLUT_ACTION_EXIT )
194 else if( fgState.ActionOnWindowClose == GLUT_ACTION_GLUTMAINLOOP_RETURNS )
195 fgState.ExecState = GLUT_EXEC_STATE_STOP;
200 TranslateMessage( &stMsg );
201 DispatchMessage( &stMsg );
207 void fgPlatformMainLoopPreliminaryWork ( void )
209 SFG_Window *window = (SFG_Window *)fgStructure.Windows.First ;
212 * Processing before the main loop: If there is a window which is open and
213 * which has a visibility callback, call it. I know this is an ugly hack,
214 * but I'm not sure what else to do about it. Ideally we should leave
215 * something uninitialized in the create window code and initialize it in
216 * the main loop, and have that initialization create a "WM_ACTIVATE"
217 * message. Then we would put the visibility callback code in the
218 * "case WM_ACTIVATE" block below. - John Fay -- 10/24/02
222 if ( FETCH_WCB( *window, Visibility ) )
224 SFG_Window *current_window = fgStructure.CurrentWindow ;
226 INVOKE_WCB( *window, Visibility, ( window->State.Visible ) );
227 fgSetWindow( current_window );
230 window = (SFG_Window *)window->Node.Next ;
236 * Determine a GLUT modifier mask based on MS-WINDOWS system info.
238 static int fgPlatformGetModifiers (void)
241 ( ( ( GetKeyState( VK_LSHIFT ) < 0 ) ||
242 ( GetKeyState( VK_RSHIFT ) < 0 )) ? GLUT_ACTIVE_SHIFT : 0 ) |
243 ( ( ( GetKeyState( VK_LCONTROL ) < 0 ) ||
244 ( GetKeyState( VK_RCONTROL ) < 0 )) ? GLUT_ACTIVE_CTRL : 0 ) |
245 ( ( ( GetKeyState( VK_LMENU ) < 0 ) ||
246 ( GetKeyState( VK_RMENU ) < 0 )) ? GLUT_ACTIVE_ALT : 0 );
250 * The window procedure for handling Win32 events
252 LRESULT CALLBACK fgPlatformWindowProc( HWND hWnd, UINT uMsg, WPARAM wParam,
255 static unsigned char lControl = 0, rControl = 0, lShift = 0,
256 rShift = 0, lAlt = 0, rAlt = 0;
258 SFG_Window *window, *child_window = NULL;
262 FREEGLUT_INTERNAL_ERROR_EXIT_IF_NOT_INITIALISED ( "Event Handler" ) ;
264 window = fgWindowByHandle( hWnd );
266 if ( ( window == NULL ) && ( uMsg != WM_CREATE ) )
267 return DefWindowProc( hWnd, uMsg, wParam, lParam );
269 /* printf ( "Window %3d message <%04x> %12d %12d\n", window?window->ID:0,
270 uMsg, wParam, lParam ); */
272 /* Some events only sent to main window. Check if the current window that
273 * the mouse is over is a child window. Below when handling some messages,
274 * we make sure that we process callbacks on the child window instead.
275 * This mirrors how GLUT does things.
277 if (window && window->Children.First)
280 SFG_WindowHandleType hwnd;
281 SFG_Window* temp_window;
283 GetCursorPos( &mouse_pos );
284 ScreenToClient( window->Window.Handle, &mouse_pos );
285 hwnd = ChildWindowFromPoint(window->Window.Handle, mouse_pos);
286 if (hwnd) /* can be NULL if mouse outside parent by the time we get here */
288 temp_window = fgWindowByHandle(hwnd);
289 if (temp_window && temp_window->Parent) /* Verify we got a child window */
290 child_window = temp_window;
296 SFG_Window* temp_window = child_window?child_window:window;
298 fgState.Modifiers = fgPlatformGetModifiers( );
300 /* Checking for CTRL, ALT, and SHIFT key positions: Key Down! */
301 #define SPECIAL_KEY_DOWN(winKey,glutKey,winProcVar)\
302 if ( !winProcVar && GetAsyncKeyState ( winKey ) )\
304 INVOKE_WCB ( *temp_window, Special,\
305 ( glutKey, temp_window->State.MouseX, temp_window->State.MouseY )\
310 SPECIAL_KEY_DOWN(VK_LCONTROL,GLUT_KEY_CTRL_L ,lControl);
311 SPECIAL_KEY_DOWN(VK_RCONTROL,GLUT_KEY_CTRL_R ,rControl);
312 SPECIAL_KEY_DOWN(VK_LSHIFT ,GLUT_KEY_SHIFT_L,lShift);
313 SPECIAL_KEY_DOWN(VK_RSHIFT ,GLUT_KEY_SHIFT_R,rShift);
314 SPECIAL_KEY_DOWN(VK_LMENU ,GLUT_KEY_ALT_L ,lAlt);
315 SPECIAL_KEY_DOWN(VK_RMENU ,GLUT_KEY_ALT_R ,rAlt);
316 #undef SPECIAL_KEY_DOWN
318 /* Checking for CTRL, ALT, and SHIFT key positions: Key Up! */
319 #define SPECIAL_KEY_UP(winKey,glutKey,winProcVar)\
320 if ( winProcVar && !GetAsyncKeyState ( winKey ) )\
322 INVOKE_WCB ( *temp_window, SpecialUp,\
323 ( glutKey, temp_window->State.MouseX, temp_window->State.MouseY )\
328 SPECIAL_KEY_UP(VK_LCONTROL,GLUT_KEY_CTRL_L ,lControl);
329 SPECIAL_KEY_UP(VK_RCONTROL,GLUT_KEY_CTRL_R ,rControl);
330 SPECIAL_KEY_UP(VK_LSHIFT ,GLUT_KEY_SHIFT_L,lShift);
331 SPECIAL_KEY_UP(VK_RSHIFT ,GLUT_KEY_SHIFT_R,rShift);
332 SPECIAL_KEY_UP(VK_LMENU ,GLUT_KEY_ALT_L ,lAlt);
333 SPECIAL_KEY_UP(VK_RMENU ,GLUT_KEY_ALT_R ,rAlt);
334 #undef SPECIAL_KEY_UP
336 fgState.Modifiers = INVALID_MODIFIERS;
342 /* The window structure is passed as the creation structure parameter... */
343 window = (SFG_Window *) (((LPCREATESTRUCT) lParam)->lpCreateParams);
344 FREEGLUT_INTERNAL_ERROR_EXIT ( ( window != NULL ), "Cannot create window",
345 "fgPlatformWindowProc" );
347 window->Window.Handle = hWnd;
348 window->Window.pContext.Device = GetDC( hWnd );
351 unsigned int current_DisplayMode = fgState.DisplayMode;
352 fgState.DisplayMode = GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH;
353 #if !defined(_WIN32_WCE)
354 fgSetupPixelFormat( window, GL_FALSE, PFD_MAIN_PLANE );
356 fgState.DisplayMode = current_DisplayMode;
358 if( fgStructure.MenuContext )
359 wglMakeCurrent( window->Window.pContext.Device,
360 fgStructure.MenuContext->MContext
364 fgStructure.MenuContext =
365 (SFG_MenuContext *)malloc( sizeof(SFG_MenuContext) );
366 fgStructure.MenuContext->MContext =
367 wglCreateContext( window->Window.pContext.Device );
370 /* window->Window.Context = wglGetCurrentContext (); */
371 window->Window.Context = wglCreateContext( window->Window.pContext.Device );
375 #if !defined(_WIN32_WCE)
376 fgSetupPixelFormat( window, GL_FALSE, PFD_MAIN_PLANE );
379 if( ! fgState.UseCurrentContext )
380 window->Window.Context =
381 wglCreateContext( window->Window.pContext.Device );
384 window->Window.Context = wglGetCurrentContext( );
385 if( ! window->Window.Context )
386 window->Window.Context =
387 wglCreateContext( window->Window.pContext.Device );
390 #if !defined(_WIN32_WCE)
391 fgNewWGLCreateContext( window );
395 window->State.NeedToResize = GL_TRUE;
396 /* if we used CW_USEDEFAULT (thats a negative value) for the size
397 * of the window, query the window now for the size at which it
400 if( ( window->State.Width < 0 ) || ( window->State.Height < 0 ) )
402 SFG_Window *current_window = fgStructure.CurrentWindow;
404 fgSetWindow( window );
405 window->State.Width = glutGet( GLUT_WINDOW_WIDTH );
406 window->State.Height = glutGet( GLUT_WINDOW_HEIGHT );
407 fgSetWindow( current_window );
410 ReleaseDC( window->Window.Handle, window->Window.pContext.Device );
412 #if defined(_WIN32_WCE)
413 /* Take over button handling */
415 HINSTANCE dxDllLib=LoadLibrary(_T("gx.dll"));
418 GXGetDefaultKeys_=(GXGETDEFAULTKEYS)GetProcAddress(dxDllLib, _T("?GXGetDefaultKeys@@YA?AUGXKeyList@@H@Z"));
419 GXOpenInput_=(GXOPENINPUT)GetProcAddress(dxDllLib, _T("?GXOpenInput@@YAHXZ"));
424 if(GXGetDefaultKeys_)
425 gxKeyList = (*GXGetDefaultKeys_)(GX_LANDSCAPEKEYS);
428 #endif /* defined(_WIN32_WCE) */
433 * If the window is visible, then it is the user manually resizing it.
434 * If it is not, then it is the system sending us a dummy resize with
435 * zero dimensions on a "glutIconifyWindow" call.
437 if( window->State.Visible )
439 /* get old values first to compare to below */
440 int width = window->State.Width, height=window->State.Height;
441 #if defined(_WIN32_WCE)
442 window->State.Width = HIWORD(lParam);
443 window->State.Height = LOWORD(lParam);
445 window->State.Width = LOWORD(lParam);
446 window->State.Height = HIWORD(lParam);
447 #endif /* defined(_WIN32_WCE) */
449 if (width!=window->State.Width || height!=window->State.Height)
450 /* Something changed, need to resize */
451 window->State.NeedToResize = GL_TRUE;
458 SFG_Window* saved_window = fgStructure.CurrentWindow;
460 GetWindowRect( window->Window.Handle, &windowRect );
464 /* For child window, we should return relative to upper-left
465 * of parent's client area.
467 POINT topleft = {windowRect.left,windowRect.top};
469 ScreenToClient(window->Parent->Window.Handle,&topleft);
470 windowRect.left = topleft.x;
471 windowRect.top = topleft.y;
474 INVOKE_WCB( *window, Position, ( windowRect.left, windowRect.top ) );
475 fgSetWindow(saved_window);
480 /* printf("WM_SETFOCUS: %p\n", window ); */
482 lRet = DefWindowProc( hWnd, uMsg, wParam, lParam );
486 /* If we're dealing with a child window, make sure it has input focus instead, set it here. */
487 SetFocus(child_window->Window.Handle);
488 SetActiveWindow( child_window->Window.Handle );
489 INVOKE_WCB( *child_window, Entry, ( GLUT_ENTERED ) );
490 UpdateWindow ( child_window->Window.Handle );
494 SetActiveWindow( window->Window.Handle );
495 INVOKE_WCB( *window, Entry, ( GLUT_ENTERED ) );
497 /* Always request update on main window to be safe */
498 UpdateWindow ( hWnd );
504 SFG_Window* saved_window = fgStructure.CurrentWindow;
505 /* printf("WM_KILLFOCUS: %p\n", window ); */
506 lRet = DefWindowProc( hWnd, uMsg, wParam, lParam );
507 INVOKE_WCB( *window, Entry, ( GLUT_LEFT ) );
508 fgSetWindow(saved_window);
510 /* Check if there are any open menus that need to be closed */
511 fgPlatformCheckMenuDeactivate();
517 if (LOWORD(wParam) != WA_INACTIVE)
519 /* printf("WM_ACTIVATE: fgSetCursor( %p, %d)\n", window,
520 window->State.Cursor ); */
521 fgSetCursor( window, window->State.Cursor );
524 lRet = DefWindowProc( hWnd, uMsg, wParam, lParam );
529 /* printf ( "Cursor event %x %x %x %x\n", window, window->State.Cursor, lParam, wParam ) ; */
530 if( LOWORD( lParam ) == HTCLIENT )
531 fgSetCursor ( window, window->State.Cursor ) ;
533 lRet = DefWindowProc( hWnd, uMsg, wParam, lParam );
537 window->State.Visible = GL_TRUE;
538 window->State.Redisplay = GL_TRUE;
542 /* Turn on the visibility in case it was turned off somehow */
543 window->State.Visible = GL_TRUE;
544 InvalidateRect( hWnd, NULL, GL_FALSE ); /* Make sure whole window is repainted. Bit of a hack, but a safe one from what google turns up... */
545 BeginPaint( hWnd, &ps );
546 fghRedrawWindow( window );
547 EndPaint( hWnd, &ps );
551 fgDestroyWindow ( window );
552 if ( fgState.ActionOnWindowClose != GLUT_ACTION_CONTINUE_EXECUTION )
558 * The window already got destroyed, so don't bother with it.
564 #if defined(_WIN32_WCE)
565 window->State.MouseX = 320-HIWORD( lParam );
566 window->State.MouseY = LOWORD( lParam );
568 window->State.MouseX = LOWORD( lParam );
569 window->State.MouseY = HIWORD( lParam );
570 #endif /* defined(_WIN32_WCE) */
571 /* Restrict to [-32768, 32767] to match X11 behaviour */
572 /* See comment in "freeglut_developer" mailing list 10/4/04 */
573 if ( window->State.MouseX > 32767 ) window->State.MouseX -= 65536;
574 if ( window->State.MouseY > 32767 ) window->State.MouseY -= 65536;
576 if ( window->ActiveMenu )
578 fgUpdateMenuHighlight( window->ActiveMenu );
582 fgState.Modifiers = fgPlatformGetModifiers( );
584 if( ( wParam & MK_LBUTTON ) ||
585 ( wParam & MK_MBUTTON ) ||
586 ( wParam & MK_RBUTTON ) )
587 INVOKE_WCB( *window, Motion, ( window->State.MouseX,
588 window->State.MouseY ) );
590 INVOKE_WCB( *window, Passive, ( window->State.MouseX,
591 window->State.MouseY ) );
593 fgState.Modifiers = INVALID_MODIFIERS;
604 GLboolean pressed = GL_TRUE;
607 #if defined(_WIN32_WCE)
608 window->State.MouseX = 320-HIWORD( lParam );
609 window->State.MouseY = LOWORD( lParam );
611 window->State.MouseX = LOWORD( lParam );
612 window->State.MouseY = HIWORD( lParam );
613 #endif /* defined(_WIN32_WCE) */
615 /* Restrict to [-32768, 32767] to match X11 behaviour */
616 /* See comment in "freeglut_developer" mailing list 10/4/04 */
617 if ( window->State.MouseX > 32767 ) window->State.MouseX -= 65536;
618 if ( window->State.MouseY > 32767 ) window->State.MouseY -= 65536;
624 button = GLUT_LEFT_BUTTON;
628 button = GLUT_MIDDLE_BUTTON;
632 button = GLUT_RIGHT_BUTTON;
636 button = GLUT_LEFT_BUTTON;
640 button = GLUT_MIDDLE_BUTTON;
644 button = GLUT_RIGHT_BUTTON;
652 #if !defined(_WIN32_WCE)
653 if( GetSystemMetrics( SM_SWAPBUTTON ) )
655 if( button == GLUT_LEFT_BUTTON )
656 button = GLUT_RIGHT_BUTTON;
658 if( button == GLUT_RIGHT_BUTTON )
659 button = GLUT_LEFT_BUTTON;
661 #endif /* !defined(_WIN32_WCE) */
664 return DefWindowProc( hWnd, uMsg, lParam, wParam );
667 * Do not execute the application's mouse callback if a menu
668 * is hooked to this button. In that case an appropriate
669 * private call should be generated.
671 if( fgCheckActiveMenu( window, button, pressed,
672 window->State.MouseX, window->State.MouseY ) )
675 /* Set capture so that the window captures all the mouse messages */
677 * XXX - Multiple button support: Under X11, the mouse is not released
678 * XXX - from the window until all buttons have been released, even if the
679 * XXX - user presses a button in another window. This will take more
680 * XXX - code changes than I am up to at the moment (10/5/04). The present
681 * XXX - is a 90 percent solution.
683 if ( pressed == GL_TRUE )
684 SetCapture ( window->Window.Handle ) ;
688 if( ! FETCH_WCB( *window, Mouse ) )
691 fgSetWindow( window );
692 fgState.Modifiers = fgPlatformGetModifiers( );
697 pressed ? GLUT_DOWN : GLUT_UP,
698 window->State.MouseX,
703 fgState.Modifiers = INVALID_MODIFIERS;
709 int wheel_number = LOWORD( wParam );
710 short ticks = ( short )HIWORD( wParam );
711 fgState.MouseWheelTicks += ticks;
713 if ( abs ( fgState.MouseWheelTicks ) >= WHEEL_DELTA )
715 int direction = ( fgState.MouseWheelTicks > 0 ) ? 1 : -1;
717 if( ! FETCH_WCB( *window, MouseWheel ) &&
718 ! FETCH_WCB( *window, Mouse ) )
721 fgSetWindow( window );
722 fgState.Modifiers = fgPlatformGetModifiers( );
724 while( abs ( fgState.MouseWheelTicks ) >= WHEEL_DELTA )
726 if( FETCH_WCB( *window, MouseWheel ) )
727 INVOKE_WCB( *window, MouseWheel,
730 window->State.MouseX,
734 else /* No mouse wheel, call the mouse button callback twice */
737 * Map wheel zero to button 3 and 4; +1 to 3, -1 to 4
738 * " " one +1 to 5, -1 to 6, ...
740 * XXX The below assumes that you have no more than 3 mouse
741 * XXX buttons. Sorry.
743 int button = wheel_number * 2 + 3;
746 INVOKE_WCB( *window, Mouse,
748 window->State.MouseX, window->State.MouseY )
750 INVOKE_WCB( *window, Mouse,
752 window->State.MouseX, window->State.MouseY )
756 fgState.MouseWheelTicks -= WHEEL_DELTA * direction;
759 fgState.Modifiers = INVALID_MODIFIERS;
771 window = child_window;
773 if( ( fgState.KeyRepeat==GLUT_KEY_REPEAT_OFF || window->State.IgnoreKeyRepeat==GL_TRUE ) && (HIWORD(lParam) & KF_REPEAT) )
777 * Remember the current modifiers state. This is done here in order
778 * to make sure the VK_DELETE keyboard callback is executed properly.
780 fgState.Modifiers = fgPlatformGetModifiers( );
782 GetCursorPos( &mouse_pos );
783 ScreenToClient( window->Window.Handle, &mouse_pos );
785 window->State.MouseX = mouse_pos.x;
786 window->State.MouseY = mouse_pos.y;
788 /* Convert the Win32 keystroke codes to GLUTtish way */
789 # define KEY(a,b) case a: keypress = b; break;
793 KEY( VK_F1, GLUT_KEY_F1 );
794 KEY( VK_F2, GLUT_KEY_F2 );
795 KEY( VK_F3, GLUT_KEY_F3 );
796 KEY( VK_F4, GLUT_KEY_F4 );
797 KEY( VK_F5, GLUT_KEY_F5 );
798 KEY( VK_F6, GLUT_KEY_F6 );
799 KEY( VK_F7, GLUT_KEY_F7 );
800 KEY( VK_F8, GLUT_KEY_F8 );
801 KEY( VK_F9, GLUT_KEY_F9 );
802 KEY( VK_F10, GLUT_KEY_F10 );
803 KEY( VK_F11, GLUT_KEY_F11 );
804 KEY( VK_F12, GLUT_KEY_F12 );
805 KEY( VK_PRIOR, GLUT_KEY_PAGE_UP );
806 KEY( VK_NEXT, GLUT_KEY_PAGE_DOWN );
807 KEY( VK_HOME, GLUT_KEY_HOME );
808 KEY( VK_END, GLUT_KEY_END );
809 KEY( VK_LEFT, GLUT_KEY_LEFT );
810 KEY( VK_UP, GLUT_KEY_UP );
811 KEY( VK_RIGHT, GLUT_KEY_RIGHT );
812 KEY( VK_DOWN, GLUT_KEY_DOWN );
813 KEY( VK_INSERT, GLUT_KEY_INSERT );
815 case VK_LCONTROL: case VK_RCONTROL: case VK_CONTROL:
816 case VK_LSHIFT: case VK_RSHIFT: case VK_SHIFT:
817 case VK_LMENU: case VK_RMENU: case VK_MENU:
818 /* These keypresses and releases are handled earlier in the function */
822 /* The delete key should be treated as an ASCII keypress: */
823 INVOKE_WCB( *window, Keyboard,
824 ( 127, window->State.MouseX, window->State.MouseY )
828 #if defined(_WIN32_WCE)
829 if(!(lParam & 0x40000000)) /* Prevent auto-repeat */
831 if(wParam==(unsigned)gxKeyList.vkRight)
832 keypress = GLUT_KEY_RIGHT;
833 else if(wParam==(unsigned)gxKeyList.vkLeft)
834 keypress = GLUT_KEY_LEFT;
835 else if(wParam==(unsigned)gxKeyList.vkUp)
836 keypress = GLUT_KEY_UP;
837 else if(wParam==(unsigned)gxKeyList.vkDown)
838 keypress = GLUT_KEY_DOWN;
839 else if(wParam==(unsigned)gxKeyList.vkA)
840 keypress = GLUT_KEY_F1;
841 else if(wParam==(unsigned)gxKeyList.vkB)
842 keypress = GLUT_KEY_F2;
843 else if(wParam==(unsigned)gxKeyList.vkC)
844 keypress = GLUT_KEY_F3;
845 else if(wParam==(unsigned)gxKeyList.vkStart)
846 keypress = GLUT_KEY_F4;
851 INVOKE_WCB( *window, Special,
853 window->State.MouseX, window->State.MouseY )
856 fgState.Modifiers = INVALID_MODIFIERS;
867 window = child_window;
870 * Remember the current modifiers state. This is done here in order
871 * to make sure the VK_DELETE keyboard callback is executed properly.
873 fgState.Modifiers = fgPlatformGetModifiers( );
875 GetCursorPos( &mouse_pos );
876 ScreenToClient( window->Window.Handle, &mouse_pos );
878 window->State.MouseX = mouse_pos.x;
879 window->State.MouseY = mouse_pos.y;
882 * Convert the Win32 keystroke codes to GLUTtish way.
883 * "KEY(a,b)" was defined under "WM_KEYDOWN"
888 KEY( VK_F1, GLUT_KEY_F1 );
889 KEY( VK_F2, GLUT_KEY_F2 );
890 KEY( VK_F3, GLUT_KEY_F3 );
891 KEY( VK_F4, GLUT_KEY_F4 );
892 KEY( VK_F5, GLUT_KEY_F5 );
893 KEY( VK_F6, GLUT_KEY_F6 );
894 KEY( VK_F7, GLUT_KEY_F7 );
895 KEY( VK_F8, GLUT_KEY_F8 );
896 KEY( VK_F9, GLUT_KEY_F9 );
897 KEY( VK_F10, GLUT_KEY_F10 );
898 KEY( VK_F11, GLUT_KEY_F11 );
899 KEY( VK_F12, GLUT_KEY_F12 );
900 KEY( VK_PRIOR, GLUT_KEY_PAGE_UP );
901 KEY( VK_NEXT, GLUT_KEY_PAGE_DOWN );
902 KEY( VK_HOME, GLUT_KEY_HOME );
903 KEY( VK_END, GLUT_KEY_END );
904 KEY( VK_LEFT, GLUT_KEY_LEFT );
905 KEY( VK_UP, GLUT_KEY_UP );
906 KEY( VK_RIGHT, GLUT_KEY_RIGHT );
907 KEY( VK_DOWN, GLUT_KEY_DOWN );
908 KEY( VK_INSERT, GLUT_KEY_INSERT );
910 case VK_LCONTROL: case VK_RCONTROL: case VK_CONTROL:
911 case VK_LSHIFT: case VK_RSHIFT: case VK_SHIFT:
912 case VK_LMENU: case VK_RMENU: case VK_MENU:
913 /* These keypresses and releases are handled earlier in the function */
917 /* The delete key should be treated as an ASCII keypress: */
918 INVOKE_WCB( *window, KeyboardUp,
919 ( 127, window->State.MouseX, window->State.MouseY )
925 #if !defined(_WIN32_WCE)
929 GetKeyboardState( state );
931 if( ToAscii( (UINT)wParam, 0, state, code, 0 ) == 1 )
934 INVOKE_WCB( *window, KeyboardUp,
936 window->State.MouseX, window->State.MouseY )
938 #endif /* !defined(_WIN32_WCE) */
943 INVOKE_WCB( *window, SpecialUp,
945 window->State.MouseX, window->State.MouseY )
948 fgState.Modifiers = INVALID_MODIFIERS;
956 window = child_window;
958 if( (fgState.KeyRepeat==GLUT_KEY_REPEAT_OFF || window->State.IgnoreKeyRepeat==GL_TRUE) && (HIWORD(lParam) & KF_REPEAT) )
961 fgState.Modifiers = fgPlatformGetModifiers( );
962 INVOKE_WCB( *window, Keyboard,
964 window->State.MouseX, window->State.MouseY )
966 fgState.Modifiers = INVALID_MODIFIERS;
970 case WM_CAPTURECHANGED:
971 /* User has finished resizing the window, force a redraw */
972 INVOKE_WCB( *window, Display, ( ) );
974 /*lRet = DefWindowProc( hWnd, uMsg, wParam, lParam ); */
977 /* Other messages that I have seen and which are not handled already */
978 case WM_SETTEXT: /* 0x000c */
979 lRet = DefWindowProc( hWnd, uMsg, wParam, lParam );
980 /* Pass it on to "DefWindowProc" to set the window text */
983 case WM_GETTEXT: /* 0x000d */
984 /* Ideally we would copy the title of the window into "lParam" */
985 /* strncpy ( (char *)lParam, "Window Title", wParam );
986 lRet = ( wParam > 12 ) ? 12 : wParam; */
987 /* the number of characters copied */
988 lRet = DefWindowProc( hWnd, uMsg, wParam, lParam );
991 case WM_GETTEXTLENGTH: /* 0x000e */
992 /* Ideally we would get the length of the title of the window */
994 /* the number of characters in "Window Title\0" (see above) */
997 case WM_ERASEBKGND: /* 0x0014 */
998 lRet = DefWindowProc( hWnd, uMsg, wParam, lParam );
1001 #if !defined(_WIN32_WCE)
1002 case WM_SYNCPAINT: /* 0x0088 */
1003 /* Another window has moved, need to update this one */
1004 window->State.Redisplay = GL_TRUE;
1005 lRet = DefWindowProc( hWnd, uMsg, wParam, lParam );
1006 /* Help screen says this message must be passed to "DefWindowProc" */
1009 case WM_NCPAINT: /* 0x0085 */
1010 /* Need to update the border of this window */
1011 lRet = DefWindowProc( hWnd, uMsg, wParam, lParam );
1012 /* Pass it on to "DefWindowProc" to repaint a standard border */
1015 case WM_SYSCOMMAND : /* 0x0112 */
1018 * We have received a system command message. Try to act on it.
1019 * The commands are passed in through the "wParam" parameter:
1020 * The least significant digit seems to be which edge of the window
1021 * is being used for a resize event:
1025 * Congratulations and thanks to Richard Rauch for figuring this out..
1027 switch ( wParam & 0xfff0 )
1036 /* User has clicked on the "-" to minimize the window */
1037 /* Turn off the visibility */
1038 window->State.Visible = GL_FALSE ;
1045 case SC_NEXTWINDOW :
1048 case SC_PREVWINDOW :
1052 /* Followed very closely by a WM_CLOSE message */
1076 case SC_SCREENSAVE :
1082 #if(WINVER >= 0x0400)
1086 case SC_MONITORPOWER :
1089 case SC_CONTEXTHELP :
1091 #endif /* WINVER >= 0x0400 */
1095 fgWarning( "Unknown wParam type 0x%x", wParam );
1100 #endif /* !defined(_WIN32_WCE) */
1102 /* We need to pass the message on to the operating system as well */
1103 lRet = DefWindowProc( hWnd, uMsg, wParam, lParam );
1107 /* handle multi-touch messages */
1110 unsigned int numInputs = (unsigned int)wParam;
1112 TOUCHINPUT* ti = (TOUCHINPUT*)malloc( sizeof(TOUCHINPUT)*numInputs);
1114 if (fghGetTouchInputInfo == (pGetTouchInputInfo)0xDEADBEEF) {
1115 fghGetTouchInputInfo = (pGetTouchInputInfo)GetProcAddress(GetModuleHandle("user32"),"GetTouchInputInfo");
1116 fghCloseTouchInputHandle = (pCloseTouchInputHandle)GetProcAddress(GetModuleHandle("user32"),"CloseTouchInputHandle");
1119 if (!fghGetTouchInputInfo) {
1124 if (fghGetTouchInputInfo( (HTOUCHINPUT)lParam, numInputs, ti, sizeof(TOUCHINPUT) )) {
1125 /* Handle each contact point */
1126 for (i = 0; i < numInputs; ++i ) {
1129 tp.x = TOUCH_COORD_TO_PIXEL(ti[i].x);
1130 tp.y = TOUCH_COORD_TO_PIXEL(ti[i].y);
1131 ScreenToClient( hWnd, &tp );
1133 ti[i].dwID = ti[i].dwID * 2;
1135 if (ti[i].dwFlags & TOUCHEVENTF_DOWN) {
1136 INVOKE_WCB( *window, MultiEntry, ( ti[i].dwID, GLUT_ENTERED ) );
1137 INVOKE_WCB( *window, MultiButton, ( ti[i].dwID, tp.x, tp.y, 0, GLUT_DOWN ) );
1138 } else if (ti[i].dwFlags & TOUCHEVENTF_MOVE) {
1139 INVOKE_WCB( *window, MultiMotion, ( ti[i].dwID, tp.x, tp.y ) );
1140 } else if (ti[i].dwFlags & TOUCHEVENTF_UP) {
1141 INVOKE_WCB( *window, MultiButton, ( ti[i].dwID, tp.x, tp.y, 0, GLUT_UP ) );
1142 INVOKE_WCB( *window, MultiEntry, ( ti[i].dwID, GLUT_LEFT ) );
1146 fghCloseTouchInputHandle((HTOUCHINPUT)lParam);
1148 lRet = 0; /*DefWindowProc( hWnd, uMsg, wParam, lParam );*/
1153 /* Handle unhandled messages */
1154 lRet = DefWindowProc( hWnd, uMsg, wParam, lParam );