2 * freeglut_main_mswin.c
4 * The Windows-specific mouse cursor related stuff.
6 * Copyright (c) 2012 Stephen J. Baker. All Rights Reserved.
7 * Written by John F. Fay, <fayjf@sourceforge.net>
8 * Creation date: Sat Jan 21, 2012
10 * Permission is hereby granted, free of charge, to any person obtaining a
11 * copy of this software and associated documentation files (the "Software"),
12 * to deal in the Software without restriction, including without limitation
13 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
14 * and/or sell copies of the Software, and to permit persons to whom the
15 * Software is furnished to do so, subject to the following conditions:
17 * The above copyright notice and this permission notice shall be included
18 * in all copies or substantial portions of the Software.
20 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
21 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
23 * PAWEL W. OLSZTA BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
24 * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
25 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
28 #include <GL/freeglut.h>
29 #include "../fg_internal.h"
32 extern void fghRedrawWindow ( SFG_Window *window );
34 extern void fgNewWGLCreateContext( SFG_Window* window );
35 extern GLboolean fgSetupPixelFormat( SFG_Window* window, GLboolean checkOnly,
36 unsigned char layer_type );
38 extern void fgPlatformCheckMenuDeactivate();
41 typedef BOOL (WINAPI *pGetTouchInputInfo)(HTOUCHINPUT,UINT,PTOUCHINPUT,int);
42 typedef BOOL (WINAPI *pCloseTouchInputHandle)(HTOUCHINPUT);
43 static pGetTouchInputInfo fghGetTouchInputInfo = (pGetTouchInputInfo)0xDEADBEEF;
44 static pCloseTouchInputHandle fghCloseTouchInputHandle = (pCloseTouchInputHandle)0xDEADBEEF;
48 typedef struct GXDisplayProperties GXDisplayProperties;
49 typedef struct GXKeyList GXKeyList;
52 typedef struct GXKeyList (*GXGETDEFAULTKEYS)(int);
53 typedef int (*GXOPENINPUT)();
55 GXGETDEFAULTKEYS GXGetDefaultKeys_ = NULL;
56 GXOPENINPUT GXOpenInput_ = NULL;
58 struct GXKeyList gxKeyList;
59 #endif /* _WIN32_WCE */
62 /* Get system time, taking special precautions against 32bit timer wrap.
63 We use timeGetTime and not GetTickCount because of its better stability,
64 and because we can increase its granularity (to 1 ms in
65 fgPlatformInitialize). For that reason we can't use GetTickCount64 which
66 wouldn't have the wrap issue.
67 Credit: this is based on code in glibc (https://mail.gnome.org/archives/commits-list/2011-November/msg04588.html)
69 static fg_time_t lastTime32 = 0;
70 static fg_time_t timeEpoch = 0;
71 void fgPlatformInitSystemTime()
73 #if defined(_WIN32_WCE)
74 lastTime32 = GetTickCount();
76 lastTime32 = timeGetTime();
79 fg_time_t fgPlatformSystemTime ( void )
82 #if defined(_WIN32_WCE)
83 currTime32 = GetTickCount();
85 currTime32 = timeGetTime();
87 /* Check if we just wrapped */
88 if (currTime32 < lastTime32)
91 lastTime32 = currTime32;
93 return currTime32 | timeEpoch << 32;
97 void fgPlatformSleepForEvents( fg_time_t msec )
99 MsgWaitForMultipleObjects( 0, NULL, FALSE, (DWORD) msec, QS_ALLINPUT );
103 void fgPlatformProcessSingleEvent ( void )
107 FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutMainLoopEvent" );
109 while( PeekMessage( &stMsg, NULL, 0, 0, PM_NOREMOVE ) )
111 if( GetMessage( &stMsg, NULL, 0, 0 ) == 0 )
113 if( fgState.ActionOnWindowClose == GLUT_ACTION_EXIT )
118 else if( fgState.ActionOnWindowClose == GLUT_ACTION_GLUTMAINLOOP_RETURNS )
119 fgState.ExecState = GLUT_EXEC_STATE_STOP;
124 TranslateMessage( &stMsg );
125 DispatchMessage( &stMsg );
131 static void fghUpdateWindowStatus(SFG_Window *window, GLboolean visState)
135 if (window->State.Visible != visState)
137 window->State.Visible = visState;
138 /* On win32 we only have two states, window displayed and window not displayed (iconified)
139 * We map these to GLUT_FULLY_RETAINED and GLUT_HIDDEN respectively.
141 INVOKE_WCB( *window, WindowStatus, ( visState ? GLUT_FULLY_RETAINED:GLUT_HIDDEN ) );
143 /* If top level window (not a subwindow/child), and icon title text available, switch titles based on visibility state */
144 if (!window->Parent && window->State.pWState.IconTitle)
147 /* visible, set window title */
148 SetWindowText( window->Window.Handle, window->State.pWState.WindowTitle );
150 /* not visible, set icon title */
151 SetWindowText( window->Window.Handle, window->State.pWState.IconTitle );
155 /* Also set visibility state for children */
156 for( child = ( SFG_Window * )window->Children.First;
158 child = ( SFG_Window * )child->Node.Next )
160 fghUpdateWindowStatus(child, visState);
164 void fghNotifyWindowStatus(SFG_Window *window)
166 INVOKE_WCB( *window, WindowStatus, ( window->State.Visible?GLUT_FULLY_RETAINED:GLUT_HIDDEN ) );
168 /* Don't notify children, they get their own just before first time they're drawn */
171 void fgPlatformMainLoopPreliminaryWork ( void )
178 * Determine a GLUT modifier mask based on MS-WINDOWS system info.
180 static int fgPlatformGetModifiers (void)
183 ( ( ( GetKeyState( VK_LSHIFT ) < 0 ) ||
184 ( GetKeyState( VK_RSHIFT ) < 0 )) ? GLUT_ACTIVE_SHIFT : 0 ) |
185 ( ( ( GetKeyState( VK_LCONTROL ) < 0 ) ||
186 ( GetKeyState( VK_RCONTROL ) < 0 )) ? GLUT_ACTIVE_CTRL : 0 ) |
187 ( ( ( GetKeyState( VK_LMENU ) < 0 ) ||
188 ( GetKeyState( VK_RMENU ) < 0 )) ? GLUT_ACTIVE_ALT : 0 );
191 static LRESULT fghWindowProcKeyPress(SFG_Window *window, UINT uMsg, GLboolean keydown, WPARAM wParam, LPARAM lParam)
193 static unsigned char lControl = 0, lShift = 0, lAlt = 0,
194 rControl = 0, rShift = 0, rAlt = 0;
198 /* if keydown, check for repeat */
199 /* If repeat is globally switched off, it cannot be switched back on per window.
200 * But if it is globally switched on, it can be switched off per window. This matches
201 * GLUT's behavior on X11, but not Nate Robbins' win32 GLUT, as he didn't implement the
202 * global state switch.
204 if( keydown && ( fgState.KeyRepeat==GLUT_KEY_REPEAT_OFF || window->State.IgnoreKeyRepeat==GL_TRUE ) && (HIWORD(lParam) & KF_REPEAT) )
207 /* Remember the current modifiers state so user can query it from their callback */
208 fgState.Modifiers = fgPlatformGetModifiers( );
210 /* Convert the Win32 keystroke codes to GLUTtish way */
211 # define KEY(a,b) case a: keypress = b; break;
215 KEY( VK_F1, GLUT_KEY_F1 );
216 KEY( VK_F2, GLUT_KEY_F2 );
217 KEY( VK_F3, GLUT_KEY_F3 );
218 KEY( VK_F4, GLUT_KEY_F4 );
219 KEY( VK_F5, GLUT_KEY_F5 );
220 KEY( VK_F6, GLUT_KEY_F6 );
221 KEY( VK_F7, GLUT_KEY_F7 );
222 KEY( VK_F8, GLUT_KEY_F8 );
223 KEY( VK_F9, GLUT_KEY_F9 );
224 KEY( VK_F10, GLUT_KEY_F10 );
225 KEY( VK_F11, GLUT_KEY_F11 );
226 KEY( VK_F12, GLUT_KEY_F12 );
227 KEY( VK_PRIOR, GLUT_KEY_PAGE_UP );
228 KEY( VK_NEXT, GLUT_KEY_PAGE_DOWN );
229 KEY( VK_HOME, GLUT_KEY_HOME );
230 KEY( VK_END, GLUT_KEY_END );
231 KEY( VK_LEFT, GLUT_KEY_LEFT );
232 KEY( VK_UP, GLUT_KEY_UP );
233 KEY( VK_RIGHT, GLUT_KEY_RIGHT );
234 KEY( VK_DOWN, GLUT_KEY_DOWN );
235 KEY( VK_INSERT, GLUT_KEY_INSERT );
237 /* handle control, alt and shift. For GLUT, we want to distinguish between left and right presses.
238 * The VK_L* & VK_R* left and right Alt, Ctrl and Shift virtual keys are however only used as parameters to GetAsyncKeyState() and GetKeyState()
239 * so when we get an alt, shift or control keypress here, we manually check whether it was the left or the right
241 #define ASYNC_KEY_EVENT(winKey,glutKey,keyStateVar)\
242 if (!keyStateVar && GetAsyncKeyState ( winKey ))\
247 else if (keyStateVar && !GetAsyncKeyState ( winKey ))\
253 ASYNC_KEY_EVENT(VK_LCONTROL,GLUT_KEY_CTRL_L,lControl);
254 ASYNC_KEY_EVENT(VK_RCONTROL,GLUT_KEY_CTRL_R,rControl);
257 ASYNC_KEY_EVENT(VK_LSHIFT,GLUT_KEY_SHIFT_L,lShift);
258 ASYNC_KEY_EVENT(VK_RSHIFT,GLUT_KEY_SHIFT_R,rShift);
261 ASYNC_KEY_EVENT(VK_LMENU,GLUT_KEY_ALT_L,lAlt);
262 ASYNC_KEY_EVENT(VK_RMENU,GLUT_KEY_ALT_R,rAlt);
264 #undef ASYNC_KEY_EVENT
267 /* The delete key should be treated as an ASCII keypress: */
269 INVOKE_WCB( *window, Keyboard,
270 ( 127, window->State.MouseX, window->State.MouseY )
273 INVOKE_WCB( *window, KeyboardUp,
274 ( 127, window->State.MouseX, window->State.MouseY )
278 #if !defined(_WIN32_WCE)
280 /* keydown displayable characters are handled with WM_CHAR message, but no corresponding up is generated. So get that here. */
286 GetKeyboardState( state );
288 if( ToAscii( (UINT)wParam, 0, state, code, 0 ) == 1 )
291 INVOKE_WCB( *window, KeyboardUp,
293 window->State.MouseX, window->State.MouseY )
299 #if defined(_WIN32_WCE)
300 if(keydown && !(lParam & 0x40000000)) /* Prevent auto-repeat */
302 if(wParam==(unsigned)gxKeyList.vkRight)
303 keypress = GLUT_KEY_RIGHT;
304 else if(wParam==(unsigned)gxKeyList.vkLeft)
305 keypress = GLUT_KEY_LEFT;
306 else if(wParam==(unsigned)gxKeyList.vkUp)
307 keypress = GLUT_KEY_UP;
308 else if(wParam==(unsigned)gxKeyList.vkDown)
309 keypress = GLUT_KEY_DOWN;
310 else if(wParam==(unsigned)gxKeyList.vkA)
311 keypress = GLUT_KEY_F1;
312 else if(wParam==(unsigned)gxKeyList.vkB)
313 keypress = GLUT_KEY_F2;
314 else if(wParam==(unsigned)gxKeyList.vkC)
315 keypress = GLUT_KEY_F3;
316 else if(wParam==(unsigned)gxKeyList.vkStart)
317 keypress = GLUT_KEY_F4;
323 INVOKE_WCB( *window, Special,
325 window->State.MouseX, window->State.MouseY )
328 INVOKE_WCB( *window, SpecialUp,
330 window->State.MouseX, window->State.MouseY )
333 fgState.Modifiers = INVALID_MODIFIERS;
335 /* SYSKEY events should be sent to default window proc for system to handle them */
336 if (uMsg==WM_SYSKEYDOWN || uMsg==WM_SYSKEYUP)
337 return DefWindowProc( window->Window.Handle, uMsg, wParam, lParam );
342 SFG_Window* fghWindowUnderCursor(SFG_Window *window)
344 /* Check if the current window that the mouse is over is a child window
345 * of the window the message was sent to. Some events only sent to main window,
346 * and when handling some messages, we need to make sure that we process
347 * callbacks on the child window instead. This mirrors how GLUT does things.
348 * returns either the original window or the found child.
350 if (window && window->Children.First) /* This window has childs */
353 SFG_Window* child_window;
355 /* Get mouse position at time of message */
356 DWORD mouse_pos_dw = GetMessagePos();
357 POINT mouse_pos = {GET_X_LPARAM(mouse_pos_dw), GET_Y_LPARAM(mouse_pos_dw)};
358 ScreenToClient( window->Window.Handle, &mouse_pos );
360 hwnd = ChildWindowFromPoint(window->Window.Handle, mouse_pos);
361 if (hwnd && hwnd!=window->Window.Handle) /* can be NULL if mouse outside parent by the time we get here, or can be same as parent if we didn't find a child */
363 child_window = fgWindowByHandle(hwnd);
364 if (child_window) /* Verify we got a FreeGLUT window */
366 /* ChildWindowFromPoint only searches immediate children, so search again to see if actually in grandchild or further descendant */
367 window = fghWindowUnderCursor(child_window);
376 * The window procedure for handling Win32 events
378 LRESULT CALLBACK fgPlatformWindowProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam )
382 static int setCaptureActive = 0;
384 FREEGLUT_INTERNAL_ERROR_EXIT_IF_NOT_INITIALISED ( "Event Handler" ) ;
386 window = fgWindowByHandle( hWnd );
388 if ( ( window == NULL ) && ( uMsg != WM_CREATE ) )
389 return DefWindowProc( hWnd, uMsg, wParam, lParam );
391 /* printf ( "Window %3d message <%04x> %12d %12d\n", window?window->ID:0,
392 uMsg, wParam, lParam ); */
397 /* The window structure is passed as the creation structure parameter... */
398 window = (SFG_Window *) (((LPCREATESTRUCT) lParam)->lpCreateParams);
399 FREEGLUT_INTERNAL_ERROR_EXIT ( ( window != NULL ), "Cannot create window",
400 "fgPlatformWindowProc" );
402 window->Window.Handle = hWnd;
403 window->Window.pContext.Device = GetDC( hWnd );
406 unsigned int current_DisplayMode = fgState.DisplayMode;
407 fgState.DisplayMode = GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH;
408 #if !defined(_WIN32_WCE)
409 fgSetupPixelFormat( window, GL_FALSE, PFD_MAIN_PLANE );
411 fgState.DisplayMode = current_DisplayMode;
413 if( fgStructure.MenuContext )
414 wglMakeCurrent( window->Window.pContext.Device,
415 fgStructure.MenuContext->MContext
419 fgStructure.MenuContext =
420 (SFG_MenuContext *)malloc( sizeof(SFG_MenuContext) );
421 fgStructure.MenuContext->MContext =
422 wglCreateContext( window->Window.pContext.Device );
425 /* window->Window.Context = wglGetCurrentContext (); */
426 window->Window.Context = wglCreateContext( window->Window.pContext.Device );
430 #if !defined(_WIN32_WCE)
431 fgSetupPixelFormat( window, GL_FALSE, PFD_MAIN_PLANE );
434 if( ! fgState.UseCurrentContext )
435 window->Window.Context =
436 wglCreateContext( window->Window.pContext.Device );
439 window->Window.Context = wglGetCurrentContext( );
440 if( ! window->Window.Context )
441 window->Window.Context =
442 wglCreateContext( window->Window.pContext.Device );
445 #if !defined(_WIN32_WCE)
446 fgNewWGLCreateContext( window );
450 window->State.NeedToResize = GL_TRUE;
451 /* if we used CW_USEDEFAULT (thats a negative value) for the size
452 * of the window, query the window now for the size at which it
455 if( ( window->State.Width < 0 ) || ( window->State.Height < 0 ) )
457 SFG_Window *current_window = fgStructure.CurrentWindow;
459 fgSetWindow( window );
460 window->State.Width = glutGet( GLUT_WINDOW_WIDTH );
461 window->State.Height = glutGet( GLUT_WINDOW_HEIGHT );
462 fgSetWindow( current_window );
465 ReleaseDC( window->Window.Handle, window->Window.pContext.Device );
467 #if defined(_WIN32_WCE)
468 /* Take over button handling */
470 HINSTANCE dxDllLib=LoadLibrary(_T("gx.dll"));
473 GXGetDefaultKeys_=(GXGETDEFAULTKEYS)GetProcAddress(dxDllLib, _T("?GXGetDefaultKeys@@YA?AUGXKeyList@@H@Z"));
474 GXOpenInput_=(GXOPENINPUT)GetProcAddress(dxDllLib, _T("?GXOpenInput@@YAHXZ"));
479 if(GXGetDefaultKeys_)
480 gxKeyList = (*GXGetDefaultKeys_)(GX_LANDSCAPEKEYS);
483 #endif /* defined(_WIN32_WCE) */
487 /* printf("WM_SIZE (ID: %i): wParam: %i, new size: %ix%i \n",window->ID,wParam,LOWORD(lParam),HIWORD(lParam)); */
489 /* Update visibility state of the window */
490 if (wParam==SIZE_MINIMIZED)
491 fghUpdateWindowStatus(window,GL_FALSE);
492 else if (wParam==SIZE_RESTORED && !window->State.Visible)
493 fghUpdateWindowStatus(window,GL_TRUE);
495 /* Check window visible, we don't want to resize when the user or glutIconifyWindow minimized the window */
496 if( window->State.Visible )
498 /* get old values first to compare to below */
499 int width = window->State.Width, height=window->State.Height;
500 #if defined(_WIN32_WCE)
501 window->State.Width = HIWORD(lParam);
502 window->State.Height = LOWORD(lParam);
504 window->State.Width = LOWORD(lParam);
505 window->State.Height = HIWORD(lParam);
506 #endif /* defined(_WIN32_WCE) */
508 if (width!=window->State.Width || height!=window->State.Height)
510 SFG_Window* saved_window = fgStructure.CurrentWindow;
512 /* size changed, call reshape callback */
513 INVOKE_WCB( *window, Reshape, ( width, height ) );
514 glutPostRedisplay( );
516 fgSetWindow( saved_window );
520 /* according to docs, should return 0 */
526 SFG_Window* saved_window = fgStructure.CurrentWindow;
529 /* Check window is minimized, we don't want to call the position callback when the user or glutIconifyWindow minimized the window */
530 if (!IsIconic(window->Window.Handle))
532 /* Get top-left of non-client area of window, matching coordinates of
533 * glutInitPosition and glutPositionWindow, but not those of
534 * glutGet(GLUT_WINDOW_X) and glutGet(GLUT_WINDOW_Y), which return
535 * top-left of client area.
537 GetWindowRect( window->Window.Handle, &windowRect );
541 /* For child window, we should return relative to upper-left
542 * of parent's client area.
544 POINT topleft = {windowRect.left,windowRect.top};
546 ScreenToClient(window->Parent->Window.Handle,&topleft);
547 windowRect.left = topleft.x;
548 windowRect.top = topleft.y;
551 INVOKE_WCB( *window, Position, ( windowRect.left, windowRect.top ) );
552 fgSetWindow(saved_window);
556 /* according to docs, should return 0 */
561 /*printf("WM_SETFOCUS: %p\n", window );*/
562 lRet = DefWindowProc( hWnd, uMsg, wParam, lParam );
564 SetActiveWindow( window->Window.Handle );
565 UpdateWindow ( hWnd );
570 /*printf("WM_KILLFOCUS: %p\n", window ); */
571 lRet = DefWindowProc( hWnd, uMsg, wParam, lParam );
573 /* Check if there are any open menus that need to be closed */
574 fgPlatformCheckMenuDeactivate();
579 //printf("WM_ACTIVATE: %x (ID: %i) %d %d\n",lParam, window->ID, HIWORD(wParam), LOWORD(wParam));
580 if (LOWORD(wParam) != WA_INACTIVE)
582 /* printf("WM_ACTIVATE: fgSetCursor( %p, %d)\n", window,
583 window->State.Cursor ); */
584 fgSetCursor( window, window->State.Cursor );
587 lRet = DefWindowProc( hWnd, uMsg, wParam, lParam );
592 /* printf ( "Cursor event %x %x %x %x\n", window, window->State.Cursor, lParam, wParam ) ; */
593 if( LOWORD( lParam ) == HTCLIENT )
595 if (!window->State.pWState.MouseTracking)
599 /* Cursor just entered window, set cursor look */
600 fgSetCursor ( window, window->State.Cursor ) ;
602 /* If an EntryFunc callback is specified by the user, also
603 * invoke that callback and start mouse tracking so that
604 * we get a WM_MOUSELEAVE message
606 if (FETCH_WCB( *window, Entry ))
608 SFG_Window* saved_window = fgStructure.CurrentWindow;
609 INVOKE_WCB( *window, Entry, ( GLUT_ENTERED ) );
610 fgSetWindow(saved_window);
612 tme.cbSize = sizeof(TRACKMOUSEEVENT);
613 tme.dwFlags = TME_LEAVE;
614 tme.hwndTrack = window->Window.Handle;
615 TrackMouseEvent(&tme);
617 window->State.pWState.MouseTracking = GL_TRUE;
622 /* Only pass non-client WM_SETCURSOR to DefWindowProc, or we get WM_SETCURSOR on parents of children as well */
623 lRet = DefWindowProc( hWnd, uMsg, wParam, lParam );
628 /* NB: This message is only received when a EntryFunc callback
629 * is specified by the user, as that is the only condition under
630 * which mouse tracking is setup in WM_SETCURSOR handler above
632 SFG_Window* saved_window = fgStructure.CurrentWindow;
633 INVOKE_WCB( *window, Entry, ( GLUT_LEFT ) );
634 fgSetWindow(saved_window);
636 window->State.pWState.MouseTracking = GL_FALSE;
637 lRet = 0; /* As per docs, must return zero */
642 /* printf("WM_SHOWWINDOW, shown? %i, source: %i\n",wParam,lParam); */
645 fghUpdateWindowStatus(window, GL_TRUE);
646 window->State.Redisplay = GL_TRUE;
650 fghUpdateWindowStatus(window, GL_FALSE);
651 window->State.Redisplay = GL_FALSE;
659 if (GetUpdateRect(hWnd,&rect,FALSE))
661 /* As per docs, upon receiving WM_PAINT, first check if the update region is not empty before you call BeginPaint */
664 /* Turn on the visibility in case it was turned off somehow */
665 window->State.Visible = GL_TRUE;
667 InvalidateRect( hWnd, NULL, GL_FALSE );
668 BeginPaint( hWnd, &ps );
669 fghRedrawWindow( window );
670 EndPaint( hWnd, &ps );
672 lRet = 0; /* As per docs, should return 0 */
677 fgDestroyWindow ( window );
678 if ( fgState.ActionOnWindowClose != GLUT_ACTION_CONTINUE_EXECUTION )
684 * The window already got destroyed, so don't bother with it.
690 /* Per docs, use LOWORD/HIWORD for WinCE and GET_X_LPARAM/GET_Y_LPARAM for desktop windows */
691 #if defined(_WIN32_WCE)
692 window->State.MouseX = 320-HIWORD( lParam ); /* XXX: Docs say x should be loword and y hiword? */
693 window->State.MouseY = LOWORD( lParam );
695 window->State.MouseX = GET_X_LPARAM( lParam );
696 window->State.MouseY = GET_Y_LPARAM( lParam );
697 #endif /* defined(_WIN32_WCE) */
698 /* Restrict to [-32768, 32767] to match X11 behaviour */
699 /* See comment in "freeglut_developer" mailing list 10/4/04 */
700 if ( window->State.MouseX > 32767 ) window->State.MouseX -= 65536;
701 if ( window->State.MouseY > 32767 ) window->State.MouseY -= 65536;
703 if ( window->ActiveMenu )
705 fgUpdateMenuHighlight( window->ActiveMenu );
709 fgState.Modifiers = fgPlatformGetModifiers( );
711 if( ( wParam & MK_LBUTTON ) ||
712 ( wParam & MK_MBUTTON ) ||
713 ( wParam & MK_RBUTTON ) )
714 INVOKE_WCB( *window, Motion, ( window->State.MouseX,
715 window->State.MouseY ) );
717 INVOKE_WCB( *window, Passive, ( window->State.MouseX,
718 window->State.MouseY ) );
720 fgState.Modifiers = INVALID_MODIFIERS;
731 GLboolean pressed = GL_TRUE;
734 /* Per docs, use LOWORD/HIWORD for WinCE and GET_X_LPARAM/GET_Y_LPARAM for desktop windows */
735 #if defined(_WIN32_WCE)
736 window->State.MouseX = 320-HIWORD( lParam ); /* XXX: Docs say x should be loword and y hiword? */
737 window->State.MouseY = LOWORD( lParam );
739 window->State.MouseX = GET_X_LPARAM( lParam );
740 window->State.MouseY = GET_Y_LPARAM( lParam );
741 #endif /* defined(_WIN32_WCE) */
743 /* Restrict to [-32768, 32767] to match X11 behaviour */
744 /* See comment in "freeglut_developer" mailing list 10/4/04 */
745 if ( window->State.MouseX > 32767 ) window->State.MouseX -= 65536;
746 if ( window->State.MouseY > 32767 ) window->State.MouseY -= 65536;
752 button = GLUT_LEFT_BUTTON;
756 button = GLUT_MIDDLE_BUTTON;
760 button = GLUT_RIGHT_BUTTON;
764 button = GLUT_LEFT_BUTTON;
768 button = GLUT_MIDDLE_BUTTON;
772 button = GLUT_RIGHT_BUTTON;
780 #if !defined(_WIN32_WCE)
781 if( GetSystemMetrics( SM_SWAPBUTTON ) )
783 if( button == GLUT_LEFT_BUTTON )
784 button = GLUT_RIGHT_BUTTON;
786 if( button == GLUT_RIGHT_BUTTON )
787 button = GLUT_LEFT_BUTTON;
789 #endif /* !defined(_WIN32_WCE) */
792 return DefWindowProc( hWnd, uMsg, lParam, wParam );
795 * Do not execute the application's mouse callback if a menu
796 * is hooked to this button. In that case an appropriate
797 * private call should be generated.
799 if( fgCheckActiveMenu( window, button, pressed,
800 window->State.MouseX, window->State.MouseY ) )
803 /* Set capture so that the window captures all the mouse messages
805 * The mouse is not released from the window until all buttons have
806 * been released, even if the user presses a button in another window.
807 * This is consistent with the behavior on X11.
809 if ( pressed == GL_TRUE )
811 if (!setCaptureActive)
812 SetCapture ( window->Window.Handle ) ;
813 setCaptureActive = 1; /* Set to false in WM_CAPTURECHANGED handler */
815 else if (!GetAsyncKeyState(VK_LBUTTON) && !GetAsyncKeyState(VK_MBUTTON) && !GetAsyncKeyState(VK_RBUTTON))
816 /* Make sure all mouse buttons are released before releasing capture */
819 if( ! FETCH_WCB( *window, Mouse ) )
822 fgSetWindow( window );
823 fgState.Modifiers = fgPlatformGetModifiers( );
828 pressed ? GLUT_DOWN : GLUT_UP,
829 window->State.MouseX,
834 fgState.Modifiers = INVALID_MODIFIERS;
836 /* As per docs, should return zero */
843 int wheel_number = 0; /* Only one scroll wheel on windows */
844 #if defined(_WIN32_WCE)
845 int modkeys = LOWORD(wParam);
846 short ticks = (short)HIWORD(wParam);
847 /* commented out as should not be needed here, mouse motion is processed in WM_MOUSEMOVE first:
848 xPos = LOWORD(lParam); -- straight from docs, not consistent with mouse nutton and mouse motion above (which i think is wrong)
849 yPos = HIWORD(lParam);
852 /* int modkeys = GET_KEYSTATE_WPARAM( wParam ); */
853 short ticks = GET_WHEEL_DELTA_WPARAM( wParam );
854 /* commented out as should not be needed here, mouse motion is processed in WM_MOUSEMOVE first:
855 window->State.MouseX = GET_X_LPARAM( lParam );
856 window->State.MouseY = GET_Y_LPARAM( lParam );
858 #endif /* defined(_WIN32_WCE) */
860 window = fghWindowUnderCursor(window);
862 fgState.MouseWheelTicks += ticks;
863 if ( abs ( fgState.MouseWheelTicks ) >= WHEEL_DELTA )
865 int direction = ( fgState.MouseWheelTicks > 0 ) ? 1 : -1;
867 if( ! FETCH_WCB( *window, MouseWheel ) &&
868 ! FETCH_WCB( *window, Mouse ) )
871 fgSetWindow( window );
872 fgState.Modifiers = fgPlatformGetModifiers( );
874 while( abs ( fgState.MouseWheelTicks ) >= WHEEL_DELTA )
876 if( FETCH_WCB( *window, MouseWheel ) )
877 INVOKE_WCB( *window, MouseWheel,
880 window->State.MouseX,
884 else /* No mouse wheel, call the mouse button callback twice */
887 * Map wheel zero to button 3 and 4; +1 to 3, -1 to 4
888 * " " one +1 to 5, -1 to 6, ...
890 * XXX The below assumes that you have no more than 3 mouse
891 * XXX buttons. Sorry.
893 int button = wheel_number * 2 + 3;
896 INVOKE_WCB( *window, Mouse,
898 window->State.MouseX, window->State.MouseY )
900 INVOKE_WCB( *window, Mouse,
902 window->State.MouseX, window->State.MouseY )
906 fgState.MouseWheelTicks -= WHEEL_DELTA * direction;
909 fgState.Modifiers = INVALID_MODIFIERS;
911 /* Per docs, should return zero */
919 window = fghWindowUnderCursor(window);
920 lRet = fghWindowProcKeyPress(window,uMsg,GL_TRUE,wParam,lParam);
927 window = fghWindowUnderCursor(window);
928 lRet = fghWindowProcKeyPress(window,uMsg,GL_FALSE,wParam,lParam);
935 window = fghWindowUnderCursor(window);
937 if( (fgState.KeyRepeat==GLUT_KEY_REPEAT_OFF || window->State.IgnoreKeyRepeat==GL_TRUE) && (HIWORD(lParam) & KF_REPEAT) )
940 fgState.Modifiers = fgPlatformGetModifiers( );
941 INVOKE_WCB( *window, Keyboard,
943 window->State.MouseX, window->State.MouseY )
945 fgState.Modifiers = INVALID_MODIFIERS;
949 case WM_CAPTURECHANGED:
950 if (!lParam || !fgWindowByHandle((HWND)lParam))
951 /* Capture released or capture taken by non-FreeGLUT window */
952 setCaptureActive = 0;
953 /* Docs advise a redraw */
954 InvalidateRect( hWnd, NULL, GL_FALSE );
956 lRet = 0; /* Per docs, should return zero */
959 #if !defined(_WIN32_WCE)
960 case WM_SYNCPAINT: /* 0x0088 */
961 /* Another window has moved, need to update this one */
962 window->State.Redisplay = GL_TRUE;
963 lRet = DefWindowProc( hWnd, uMsg, wParam, lParam );
964 /* Help screen says this message must be passed to "DefWindowProc" */
967 case WM_SYSCOMMAND : /* 0x0112 */
970 * We have received a system command message. Try to act on it.
971 * The commands are passed in through the "wParam" parameter:
972 * The least significant digit seems to be which edge of the window
973 * is being used for a resize event:
977 * Congratulations and thanks to Richard Rauch for figuring this out..
979 switch ( wParam & 0xfff0 )
988 /* User has clicked on the "-" to minimize the window */
989 /* Turning off the visibility is handled in WM_SIZE handler */
1003 /* Followed very closely by a WM_CLOSE message */
1027 case SC_SCREENSAVE :
1033 #if(WINVER >= 0x0400)
1037 case SC_MONITORPOWER :
1040 case SC_CONTEXTHELP :
1042 #endif /* WINVER >= 0x0400 */
1046 fgWarning( "Unknown wParam type 0x%x", wParam );
1051 #endif /* !defined(_WIN32_WCE) */
1053 /* We need to pass the message on to the operating system as well */
1054 lRet = DefWindowProc( hWnd, uMsg, wParam, lParam );
1058 /* handle multi-touch messages */
1061 unsigned int numInputs = (unsigned int)wParam;
1063 TOUCHINPUT* ti = (TOUCHINPUT*)malloc( sizeof(TOUCHINPUT)*numInputs);
1065 if (fghGetTouchInputInfo == (pGetTouchInputInfo)0xDEADBEEF) {
1066 fghGetTouchInputInfo = (pGetTouchInputInfo)GetProcAddress(GetModuleHandle("user32"),"GetTouchInputInfo");
1067 fghCloseTouchInputHandle = (pCloseTouchInputHandle)GetProcAddress(GetModuleHandle("user32"),"CloseTouchInputHandle");
1070 if (!fghGetTouchInputInfo) {
1075 if (fghGetTouchInputInfo( (HTOUCHINPUT)lParam, numInputs, ti, sizeof(TOUCHINPUT) )) {
1076 /* Handle each contact point */
1077 for (i = 0; i < numInputs; ++i ) {
1080 tp.x = TOUCH_COORD_TO_PIXEL(ti[i].x);
1081 tp.y = TOUCH_COORD_TO_PIXEL(ti[i].y);
1082 ScreenToClient( hWnd, &tp );
1084 ti[i].dwID = ti[i].dwID * 2;
1086 if (ti[i].dwFlags & TOUCHEVENTF_DOWN) {
1087 INVOKE_WCB( *window, MultiEntry, ( ti[i].dwID, GLUT_ENTERED ) );
1088 INVOKE_WCB( *window, MultiButton, ( ti[i].dwID, tp.x, tp.y, 0, GLUT_DOWN ) );
1089 } else if (ti[i].dwFlags & TOUCHEVENTF_MOVE) {
1090 INVOKE_WCB( *window, MultiMotion, ( ti[i].dwID, tp.x, tp.y ) );
1091 } else if (ti[i].dwFlags & TOUCHEVENTF_UP) {
1092 INVOKE_WCB( *window, MultiButton, ( ti[i].dwID, tp.x, tp.y, 0, GLUT_UP ) );
1093 INVOKE_WCB( *window, MultiEntry, ( ti[i].dwID, GLUT_LEFT ) );
1097 fghCloseTouchInputHandle((HTOUCHINPUT)lParam);
1099 lRet = 0; /*DefWindowProc( hWnd, uMsg, wParam, lParam );*/
1104 /* Handle unhandled messages */
1105 lRet = DefWindowProc( hWnd, uMsg, wParam, lParam );