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 INVOKE_WCB( *window, WindowStatus, ( visState ? GLUT_FULLY_RETAINED:GLUT_HIDDEN ) );
141 /* Also set visibility state for children */
142 for( child = ( SFG_Window * )window->Children.First;
144 child = ( SFG_Window * )child->Node.Next )
146 fghUpdateWindowStatus(child, visState);
150 static void fghNotifyWindowStatus(SFG_Window *window)
154 INVOKE_WCB( *window, WindowStatus, ( window->State.Visible?GLUT_FULLY_RETAINED:GLUT_HIDDEN ) );
156 /* Also notify children */
157 for( child = ( SFG_Window * )window->Children.First;
159 child = ( SFG_Window * )child->Node.Next )
161 fghNotifyWindowStatus(child);
165 void fgPlatformMainLoopPreliminaryWork ( void )
167 SFG_Window *window = (SFG_Window *)fgStructure.Windows.First ;
170 * Processing before the main loop: If there is a window which is open and
171 * which has a visibility/windowStatus callback, call it to inform the client
172 * code that the window is visible. I know this is an ugly hack,
173 * but I'm not sure what else to do about it. Depending on WM_ACTIVATE would
174 * not work as not all windows get this when you are opening multiple before
175 * the mainloop starts. WM_SHOWWINDOW looked like an interesting candidate, but
176 * it is generated and processed before glutCreate(Sub)Window returns, so no
177 * callback can yet be set on the window.
181 if ( FETCH_WCB( *window, WindowStatus ) )
183 SFG_Window *current_window = fgStructure.CurrentWindow ;
185 fghNotifyWindowStatus(window);
186 fgSetWindow( current_window );
189 window = (SFG_Window *)window->Node.Next ;
195 * Determine a GLUT modifier mask based on MS-WINDOWS system info.
197 static int fgPlatformGetModifiers (void)
200 ( ( ( GetKeyState( VK_LSHIFT ) < 0 ) ||
201 ( GetKeyState( VK_RSHIFT ) < 0 )) ? GLUT_ACTIVE_SHIFT : 0 ) |
202 ( ( ( GetKeyState( VK_LCONTROL ) < 0 ) ||
203 ( GetKeyState( VK_RCONTROL ) < 0 )) ? GLUT_ACTIVE_CTRL : 0 ) |
204 ( ( ( GetKeyState( VK_LMENU ) < 0 ) ||
205 ( GetKeyState( VK_RMENU ) < 0 )) ? GLUT_ACTIVE_ALT : 0 );
208 static LRESULT fghWindowProcKeyPress(SFG_Window *window, UINT uMsg, GLboolean keydown, WPARAM wParam, LPARAM lParam)
210 static unsigned char lControl = 0, lShift = 0, lAlt = 0,
211 rControl = 0, rShift = 0, rAlt = 0;
215 /* if keydown, check for repeat */
216 /* If repeat is globally switched off, it cannot be switched back on per window.
217 * But if it is globally switched on, it can be switched off per window. This matches
218 * GLUT's behavior on X11, but not Nate Robbins' win32 GLUT, as he didn't implement the
219 * global state switch.
221 if( keydown && ( fgState.KeyRepeat==GLUT_KEY_REPEAT_OFF || window->State.IgnoreKeyRepeat==GL_TRUE ) && (HIWORD(lParam) & KF_REPEAT) )
224 /* Remember the current modifiers state so user can query it from their callback */
225 fgState.Modifiers = fgPlatformGetModifiers( );
227 /* Convert the Win32 keystroke codes to GLUTtish way */
228 # define KEY(a,b) case a: keypress = b; break;
232 KEY( VK_F1, GLUT_KEY_F1 );
233 KEY( VK_F2, GLUT_KEY_F2 );
234 KEY( VK_F3, GLUT_KEY_F3 );
235 KEY( VK_F4, GLUT_KEY_F4 );
236 KEY( VK_F5, GLUT_KEY_F5 );
237 KEY( VK_F6, GLUT_KEY_F6 );
238 KEY( VK_F7, GLUT_KEY_F7 );
239 KEY( VK_F8, GLUT_KEY_F8 );
240 KEY( VK_F9, GLUT_KEY_F9 );
241 KEY( VK_F10, GLUT_KEY_F10 );
242 KEY( VK_F11, GLUT_KEY_F11 );
243 KEY( VK_F12, GLUT_KEY_F12 );
244 KEY( VK_PRIOR, GLUT_KEY_PAGE_UP );
245 KEY( VK_NEXT, GLUT_KEY_PAGE_DOWN );
246 KEY( VK_HOME, GLUT_KEY_HOME );
247 KEY( VK_END, GLUT_KEY_END );
248 KEY( VK_LEFT, GLUT_KEY_LEFT );
249 KEY( VK_UP, GLUT_KEY_UP );
250 KEY( VK_RIGHT, GLUT_KEY_RIGHT );
251 KEY( VK_DOWN, GLUT_KEY_DOWN );
252 KEY( VK_INSERT, GLUT_KEY_INSERT );
254 /* handle control, alt and shift. For GLUT, we want to distinguish between left and right presses.
255 * The VK_L* & VK_R* left and right Alt, Ctrl and Shift virtual keys are however only used as parameters to GetAsyncKeyState() and GetKeyState()
256 * so when we get an alt, shift or control keypress here, we manually check whether it was the left or the right
258 #define ASYNC_KEY_EVENT(winKey,glutKey,keyStateVar)\
259 if (!keyStateVar && GetAsyncKeyState ( winKey ))\
264 else if (keyStateVar && !GetAsyncKeyState ( winKey ))\
270 ASYNC_KEY_EVENT(VK_LCONTROL,GLUT_KEY_CTRL_L,lControl);
271 ASYNC_KEY_EVENT(VK_RCONTROL,GLUT_KEY_CTRL_R,rControl);
274 ASYNC_KEY_EVENT(VK_LSHIFT,GLUT_KEY_SHIFT_L,lShift);
275 ASYNC_KEY_EVENT(VK_RSHIFT,GLUT_KEY_SHIFT_R,rShift);
278 ASYNC_KEY_EVENT(VK_LMENU,GLUT_KEY_ALT_L,lAlt);
279 ASYNC_KEY_EVENT(VK_RMENU,GLUT_KEY_ALT_R,rAlt);
281 #undef ASYNC_KEY_EVENT
284 /* The delete key should be treated as an ASCII keypress: */
286 INVOKE_WCB( *window, Keyboard,
287 ( 127, window->State.MouseX, window->State.MouseY )
290 INVOKE_WCB( *window, KeyboardUp,
291 ( 127, window->State.MouseX, window->State.MouseY )
295 #if !defined(_WIN32_WCE)
297 /* keydown displayable characters are handled with WM_CHAR message, but no corresponding up is generated. So get that here. */
303 GetKeyboardState( state );
305 if( ToAscii( (UINT)wParam, 0, state, code, 0 ) == 1 )
308 INVOKE_WCB( *window, KeyboardUp,
310 window->State.MouseX, window->State.MouseY )
316 #if defined(_WIN32_WCE)
317 if(keydown && !(lParam & 0x40000000)) /* Prevent auto-repeat */
319 if(wParam==(unsigned)gxKeyList.vkRight)
320 keypress = GLUT_KEY_RIGHT;
321 else if(wParam==(unsigned)gxKeyList.vkLeft)
322 keypress = GLUT_KEY_LEFT;
323 else if(wParam==(unsigned)gxKeyList.vkUp)
324 keypress = GLUT_KEY_UP;
325 else if(wParam==(unsigned)gxKeyList.vkDown)
326 keypress = GLUT_KEY_DOWN;
327 else if(wParam==(unsigned)gxKeyList.vkA)
328 keypress = GLUT_KEY_F1;
329 else if(wParam==(unsigned)gxKeyList.vkB)
330 keypress = GLUT_KEY_F2;
331 else if(wParam==(unsigned)gxKeyList.vkC)
332 keypress = GLUT_KEY_F3;
333 else if(wParam==(unsigned)gxKeyList.vkStart)
334 keypress = GLUT_KEY_F4;
340 INVOKE_WCB( *window, Special,
342 window->State.MouseX, window->State.MouseY )
345 INVOKE_WCB( *window, SpecialUp,
347 window->State.MouseX, window->State.MouseY )
350 fgState.Modifiers = INVALID_MODIFIERS;
352 /* SYSKEY events should be sent to default window proc for system to handle them */
353 if (uMsg==WM_SYSKEYDOWN || uMsg==WM_SYSKEYUP)
354 return DefWindowProc( window->Window.Handle, uMsg, wParam, lParam );
359 static SFG_Window* fghWindowUnderCursor(SFG_Window *window)
361 /* Check if the current window that the mouse is over is a child window
362 * of the window the message was sent to. Some events only sent to main window,
363 * and when handling some messages, we need to make sure that we process
364 * callbacks on the child window instead. This mirrors how GLUT does things.
365 * returns either the original window or the found child.
367 if (window && window->Children.First) /* This window has childs */
369 SFG_WindowHandleType hwnd;
370 SFG_Window* child_window;
372 /* Get mouse position at time of message */
373 DWORD mouse_pos_dw = GetMessagePos();
374 POINT mouse_pos = {GET_X_LPARAM(mouse_pos_dw), GET_Y_LPARAM(mouse_pos_dw)};
375 ScreenToClient( window->Window.Handle, &mouse_pos );
377 hwnd = ChildWindowFromPoint(window->Window.Handle, mouse_pos);
378 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 */
380 child_window = fgWindowByHandle(hwnd);
381 if (child_window) /* Verify we got a FreeGLUT window */
383 /* ChildWindowFromPoint only searches immediate children, so search again to see if actually in grandchild or further descendant */
384 window = fghWindowUnderCursor(child_window);
393 * The window procedure for handling Win32 events
395 LRESULT CALLBACK fgPlatformWindowProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam )
399 static int setCaptureActive = 0;
401 FREEGLUT_INTERNAL_ERROR_EXIT_IF_NOT_INITIALISED ( "Event Handler" ) ;
403 window = fgWindowByHandle( hWnd );
405 if ( ( window == NULL ) && ( uMsg != WM_CREATE ) )
406 return DefWindowProc( hWnd, uMsg, wParam, lParam );
408 /* printf ( "Window %3d message <%04x> %12d %12d\n", window?window->ID:0,
409 uMsg, wParam, lParam ); */
414 /* The window structure is passed as the creation structure parameter... */
415 window = (SFG_Window *) (((LPCREATESTRUCT) lParam)->lpCreateParams);
416 FREEGLUT_INTERNAL_ERROR_EXIT ( ( window != NULL ), "Cannot create window",
417 "fgPlatformWindowProc" );
419 window->Window.Handle = hWnd;
420 window->Window.pContext.Device = GetDC( hWnd );
423 unsigned int current_DisplayMode = fgState.DisplayMode;
424 fgState.DisplayMode = GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH;
425 #if !defined(_WIN32_WCE)
426 fgSetupPixelFormat( window, GL_FALSE, PFD_MAIN_PLANE );
428 fgState.DisplayMode = current_DisplayMode;
430 if( fgStructure.MenuContext )
431 wglMakeCurrent( window->Window.pContext.Device,
432 fgStructure.MenuContext->MContext
436 fgStructure.MenuContext =
437 (SFG_MenuContext *)malloc( sizeof(SFG_MenuContext) );
438 fgStructure.MenuContext->MContext =
439 wglCreateContext( window->Window.pContext.Device );
442 /* window->Window.Context = wglGetCurrentContext (); */
443 window->Window.Context = wglCreateContext( window->Window.pContext.Device );
447 #if !defined(_WIN32_WCE)
448 fgSetupPixelFormat( window, GL_FALSE, PFD_MAIN_PLANE );
451 if( ! fgState.UseCurrentContext )
452 window->Window.Context =
453 wglCreateContext( window->Window.pContext.Device );
456 window->Window.Context = wglGetCurrentContext( );
457 if( ! window->Window.Context )
458 window->Window.Context =
459 wglCreateContext( window->Window.pContext.Device );
462 #if !defined(_WIN32_WCE)
463 fgNewWGLCreateContext( window );
467 window->State.NeedToResize = GL_TRUE;
468 /* if we used CW_USEDEFAULT (thats a negative value) for the size
469 * of the window, query the window now for the size at which it
472 if( ( window->State.Width < 0 ) || ( window->State.Height < 0 ) )
474 SFG_Window *current_window = fgStructure.CurrentWindow;
476 fgSetWindow( window );
477 window->State.Width = glutGet( GLUT_WINDOW_WIDTH );
478 window->State.Height = glutGet( GLUT_WINDOW_HEIGHT );
479 fgSetWindow( current_window );
482 ReleaseDC( window->Window.Handle, window->Window.pContext.Device );
484 #if defined(_WIN32_WCE)
485 /* Take over button handling */
487 HINSTANCE dxDllLib=LoadLibrary(_T("gx.dll"));
490 GXGetDefaultKeys_=(GXGETDEFAULTKEYS)GetProcAddress(dxDllLib, _T("?GXGetDefaultKeys@@YA?AUGXKeyList@@H@Z"));
491 GXOpenInput_=(GXOPENINPUT)GetProcAddress(dxDllLib, _T("?GXOpenInput@@YAHXZ"));
496 if(GXGetDefaultKeys_)
497 gxKeyList = (*GXGetDefaultKeys_)(GX_LANDSCAPEKEYS);
500 #endif /* defined(_WIN32_WCE) */
504 //printf("WM_SIZE (ID: %i): wParam: %i, new size: %ix%i \n",window->ID,wParam,LOWORD(lParam),HIWORD(lParam));
506 * If the window is visible, then it is the user manually resizing it.
507 * If it is not, then it is the system sending us a dummy resize with
508 * zero dimensions on a "glutIconifyWindow" call.
510 if( window->State.Visible )
512 /* get old values first to compare to below */
513 int width = window->State.Width, height=window->State.Height;
514 #if defined(_WIN32_WCE)
515 window->State.Width = HIWORD(lParam);
516 window->State.Height = LOWORD(lParam);
518 window->State.Width = LOWORD(lParam);
519 window->State.Height = HIWORD(lParam);
520 #endif /* defined(_WIN32_WCE) */
522 if (width!=window->State.Width || height!=window->State.Height)
523 /* Something changed, need to resize */
524 window->State.NeedToResize = GL_TRUE;
527 /* according to docs, should return 0 */
533 SFG_Window* saved_window = fgStructure.CurrentWindow;
536 /* Check window visible, we don't want to call the position callback when the user minimized the window */
537 if (window->State.Visible)
539 /* Get top-left of non-client area of window, matching coordinates of
540 * glutInitPosition and glutPositionWindow, but not those of
541 * glutGet(GLUT_WINDOW_X) and glutGet(GLUT_WINDOW_Y), which return
542 * top-left of client area.
544 GetWindowRect( window->Window.Handle, &windowRect );
548 /* For child window, we should return relative to upper-left
549 * of parent's client area.
551 POINT topleft = {windowRect.left,windowRect.top};
553 ScreenToClient(window->Parent->Window.Handle,&topleft);
554 windowRect.left = topleft.x;
555 windowRect.top = topleft.y;
558 INVOKE_WCB( *window, Position, ( windowRect.left, windowRect.top ) );
559 fgSetWindow(saved_window);
565 /* printf("WM_SETFOCUS: %p\n", window ); */
567 lRet = DefWindowProc( hWnd, uMsg, wParam, lParam );
569 SetActiveWindow( window->Window.Handle );
570 UpdateWindow ( hWnd );
576 /* printf("WM_KILLFOCUS: %p\n", window ); */
577 lRet = DefWindowProc( hWnd, uMsg, wParam, lParam );
579 /* Check if there are any open menus that need to be closed */
580 fgPlatformCheckMenuDeactivate();
586 //printf("WM_ACTIVATE: %x (ID: %i) %d %d\n",lParam, window->ID, HIWORD(wParam), LOWORD(wParam));
587 if (LOWORD(wParam) != WA_INACTIVE)
589 /* printf("WM_ACTIVATE: fgSetCursor( %p, %d)\n", window,
590 window->State.Cursor ); */
591 fgSetCursor( window, window->State.Cursor );
594 lRet = DefWindowProc( hWnd, uMsg, wParam, lParam );
599 /* printf ( "Cursor event %x %x %x %x\n", window, window->State.Cursor, lParam, wParam ) ; */
600 if( LOWORD( lParam ) == HTCLIENT )
602 if (!window->State.pWState.MouseTracking)
606 /* Cursor just entered window, set cursor look */
607 fgSetCursor ( window, window->State.Cursor ) ;
609 /* If an EntryFunc callback is specified by the user, also
610 * invoke that callback and start mouse tracking so that
611 * we get a WM_MOUSELEAVE message
613 if (FETCH_WCB( *window, Entry ))
615 INVOKE_WCB( *window, Entry, ( GLUT_ENTERED ) );
617 tme.cbSize = sizeof(TRACKMOUSEEVENT);
618 tme.dwFlags = TME_LEAVE;
619 tme.hwndTrack = window->Window.Handle;
620 TrackMouseEvent(&tme);
622 window->State.pWState.MouseTracking = GL_TRUE;
627 /* Only pass non-client WM_SETCURSOR to DefWindowProc, or we get WM_SETCURSOR on parents of children as well */
628 lRet = DefWindowProc( hWnd, uMsg, wParam, lParam );
633 /* NB: This message is only received when a EntryFunc callback
634 * is specified by the user, as that is the only condition under
635 * which mouse tracking is setup in WM_SETCURSOR handler above
637 SFG_Window* saved_window = fgStructure.CurrentWindow;
638 INVOKE_WCB( *window, Entry, ( GLUT_LEFT ) );
639 fgSetWindow(saved_window);
641 window->State.pWState.MouseTracking = GL_FALSE;
642 lRet = 0; /* As per docs, must return zero */
647 //printf("WM_SHOWWINDOW\n");
648 fghUpdateWindowStatus(window, GL_TRUE);
649 window->State.Redisplay = GL_TRUE;
655 /* Turn on the visibility in case it was turned off somehow */
656 window->State.Visible = GL_TRUE;
658 InvalidateRect( hWnd, NULL, GL_FALSE ); /* Make sure whole window is repainted. Bit of a hack, but a safe one from what google turns up... */
659 BeginPaint( hWnd, &ps );
660 fghRedrawWindow( window );
661 EndPaint( hWnd, &ps );
666 fgDestroyWindow ( window );
667 if ( fgState.ActionOnWindowClose != GLUT_ACTION_CONTINUE_EXECUTION )
673 * The window already got destroyed, so don't bother with it.
679 #if defined(_WIN32_WCE)
680 window->State.MouseX = 320-HIWORD( lParam );
681 window->State.MouseY = LOWORD( lParam );
683 window->State.MouseX = LOWORD( lParam );
684 window->State.MouseY = HIWORD( lParam );
685 #endif /* defined(_WIN32_WCE) */
686 /* Restrict to [-32768, 32767] to match X11 behaviour */
687 /* See comment in "freeglut_developer" mailing list 10/4/04 */
688 if ( window->State.MouseX > 32767 ) window->State.MouseX -= 65536;
689 if ( window->State.MouseY > 32767 ) window->State.MouseY -= 65536;
691 if ( window->ActiveMenu )
693 fgUpdateMenuHighlight( window->ActiveMenu );
697 fgState.Modifiers = fgPlatformGetModifiers( );
699 if( ( wParam & MK_LBUTTON ) ||
700 ( wParam & MK_MBUTTON ) ||
701 ( wParam & MK_RBUTTON ) )
702 INVOKE_WCB( *window, Motion, ( window->State.MouseX,
703 window->State.MouseY ) );
705 INVOKE_WCB( *window, Passive, ( window->State.MouseX,
706 window->State.MouseY ) );
708 fgState.Modifiers = INVALID_MODIFIERS;
719 GLboolean pressed = GL_TRUE;
722 #if defined(_WIN32_WCE)
723 window->State.MouseX = 320-HIWORD( lParam );
724 window->State.MouseY = LOWORD( lParam );
726 window->State.MouseX = LOWORD( lParam );
727 window->State.MouseY = HIWORD( lParam );
728 #endif /* defined(_WIN32_WCE) */
730 /* Restrict to [-32768, 32767] to match X11 behaviour */
731 /* See comment in "freeglut_developer" mailing list 10/4/04 */
732 if ( window->State.MouseX > 32767 ) window->State.MouseX -= 65536;
733 if ( window->State.MouseY > 32767 ) window->State.MouseY -= 65536;
739 button = GLUT_LEFT_BUTTON;
743 button = GLUT_MIDDLE_BUTTON;
747 button = GLUT_RIGHT_BUTTON;
751 button = GLUT_LEFT_BUTTON;
755 button = GLUT_MIDDLE_BUTTON;
759 button = GLUT_RIGHT_BUTTON;
767 #if !defined(_WIN32_WCE)
768 if( GetSystemMetrics( SM_SWAPBUTTON ) )
770 if( button == GLUT_LEFT_BUTTON )
771 button = GLUT_RIGHT_BUTTON;
773 if( button == GLUT_RIGHT_BUTTON )
774 button = GLUT_LEFT_BUTTON;
776 #endif /* !defined(_WIN32_WCE) */
779 return DefWindowProc( hWnd, uMsg, lParam, wParam );
782 * Do not execute the application's mouse callback if a menu
783 * is hooked to this button. In that case an appropriate
784 * private call should be generated.
786 if( fgCheckActiveMenu( window, button, pressed,
787 window->State.MouseX, window->State.MouseY ) )
790 /* Set capture so that the window captures all the mouse messages
792 * The mouse is not released from the window until all buttons have
793 * been released, even if the user presses a button in another window.
794 * This is consistent with the behavior on X11.
796 if ( pressed == GL_TRUE )
798 if (!setCaptureActive)
799 SetCapture ( window->Window.Handle ) ;
800 setCaptureActive = 1; /* Set to false in WM_CAPTURECHANGED handler */
802 else if (!GetAsyncKeyState(VK_LBUTTON) && !GetAsyncKeyState(VK_MBUTTON) && !GetAsyncKeyState(VK_RBUTTON))
803 /* Make sure all mouse buttons are released before releasing capture */
806 if( ! FETCH_WCB( *window, Mouse ) )
809 fgSetWindow( window );
810 fgState.Modifiers = fgPlatformGetModifiers( );
815 pressed ? GLUT_DOWN : GLUT_UP,
816 window->State.MouseX,
821 fgState.Modifiers = INVALID_MODIFIERS;
823 /* As per docs, should return zero */
830 SFG_Window *child_window = NULL;
831 int wheel_number = LOWORD( wParam );
832 short ticks = ( short )HIWORD( wParam );
834 window = fghWindowUnderCursor(window);
836 fgState.MouseWheelTicks += ticks;
837 if ( abs ( fgState.MouseWheelTicks ) >= WHEEL_DELTA )
839 int direction = ( fgState.MouseWheelTicks > 0 ) ? 1 : -1;
841 if( ! FETCH_WCB( *window, MouseWheel ) &&
842 ! FETCH_WCB( *window, Mouse ) )
845 fgSetWindow( window );
846 fgState.Modifiers = fgPlatformGetModifiers( );
848 while( abs ( fgState.MouseWheelTicks ) >= WHEEL_DELTA )
850 if( FETCH_WCB( *window, MouseWheel ) )
851 INVOKE_WCB( *window, MouseWheel,
854 window->State.MouseX,
858 else /* No mouse wheel, call the mouse button callback twice */
861 * Map wheel zero to button 3 and 4; +1 to 3, -1 to 4
862 * " " one +1 to 5, -1 to 6, ...
864 * XXX The below assumes that you have no more than 3 mouse
865 * XXX buttons. Sorry.
867 int button = wheel_number * 2 + 3;
870 INVOKE_WCB( *window, Mouse,
872 window->State.MouseX, window->State.MouseY )
874 INVOKE_WCB( *window, Mouse,
876 window->State.MouseX, window->State.MouseY )
880 fgState.MouseWheelTicks -= WHEEL_DELTA * direction;
883 fgState.Modifiers = INVALID_MODIFIERS;
891 window = fghWindowUnderCursor(window);
892 lRet = fghWindowProcKeyPress(window,uMsg,GL_TRUE,wParam,lParam);
899 window = fghWindowUnderCursor(window);
900 lRet = fghWindowProcKeyPress(window,uMsg,GL_FALSE,wParam,lParam);
907 window = fghWindowUnderCursor(window);
909 if( (fgState.KeyRepeat==GLUT_KEY_REPEAT_OFF || window->State.IgnoreKeyRepeat==GL_TRUE) && (HIWORD(lParam) & KF_REPEAT) )
912 fgState.Modifiers = fgPlatformGetModifiers( );
913 INVOKE_WCB( *window, Keyboard,
915 window->State.MouseX, window->State.MouseY )
917 fgState.Modifiers = INVALID_MODIFIERS;
921 case WM_CAPTURECHANGED:
922 if (!lParam || !fgWindowByHandle((HWND)lParam))
923 /* Capture released or capture taken by non-FreeGLUT window */
924 setCaptureActive = 0;
925 /* Docs advise a redraw */
926 InvalidateRect( hWnd, NULL, GL_FALSE );
928 lRet = 0; /* Per docs, should return zero */
931 /* Other messages that I have seen and which are not handled already */
932 case WM_SETTEXT: /* 0x000c */
933 lRet = DefWindowProc( hWnd, uMsg, wParam, lParam );
934 /* Pass it on to "DefWindowProc" to set the window text */
937 case WM_GETTEXT: /* 0x000d */
938 /* Ideally we would copy the title of the window into "lParam" */
939 /* strncpy ( (char *)lParam, "Window Title", wParam );
940 lRet = ( wParam > 12 ) ? 12 : wParam; */
941 /* the number of characters copied */
942 lRet = DefWindowProc( hWnd, uMsg, wParam, lParam );
945 case WM_GETTEXTLENGTH: /* 0x000e */
946 /* Ideally we would get the length of the title of the window */
948 /* the number of characters in "Window Title\0" (see above) */
951 case WM_ERASEBKGND: /* 0x0014 */
952 lRet = DefWindowProc( hWnd, uMsg, wParam, lParam );
955 #if !defined(_WIN32_WCE)
956 case WM_SYNCPAINT: /* 0x0088 */
957 /* Another window has moved, need to update this one */
958 window->State.Redisplay = GL_TRUE;
959 lRet = DefWindowProc( hWnd, uMsg, wParam, lParam );
960 /* Help screen says this message must be passed to "DefWindowProc" */
963 case WM_NCPAINT: /* 0x0085 */
964 /* Need to update the border of this window */
965 lRet = DefWindowProc( hWnd, uMsg, wParam, lParam );
966 /* Pass it on to "DefWindowProc" to repaint a standard border */
969 case WM_SYSCOMMAND : /* 0x0112 */
972 * We have received a system command message. Try to act on it.
973 * The commands are passed in through the "wParam" parameter:
974 * The least significant digit seems to be which edge of the window
975 * is being used for a resize event:
979 * Congratulations and thanks to Richard Rauch for figuring this out..
981 switch ( wParam & 0xfff0 )
990 /* User has clicked on the "-" to minimize the window */
991 /* Turn off the visibility */
992 fghUpdateWindowStatus(window, GL_FALSE);
1002 case SC_PREVWINDOW :
1006 /* Followed very closely by a WM_CLOSE message */
1025 fghUpdateWindowStatus(window, GL_TRUE);
1031 case SC_SCREENSAVE :
1037 #if(WINVER >= 0x0400)
1041 case SC_MONITORPOWER :
1044 case SC_CONTEXTHELP :
1046 #endif /* WINVER >= 0x0400 */
1050 fgWarning( "Unknown wParam type 0x%x", wParam );
1055 #endif /* !defined(_WIN32_WCE) */
1057 /* We need to pass the message on to the operating system as well */
1058 lRet = DefWindowProc( hWnd, uMsg, wParam, lParam );
1062 /* handle multi-touch messages */
1065 unsigned int numInputs = (unsigned int)wParam;
1067 TOUCHINPUT* ti = (TOUCHINPUT*)malloc( sizeof(TOUCHINPUT)*numInputs);
1069 if (fghGetTouchInputInfo == (pGetTouchInputInfo)0xDEADBEEF) {
1070 fghGetTouchInputInfo = (pGetTouchInputInfo)GetProcAddress(GetModuleHandle("user32"),"GetTouchInputInfo");
1071 fghCloseTouchInputHandle = (pCloseTouchInputHandle)GetProcAddress(GetModuleHandle("user32"),"CloseTouchInputHandle");
1074 if (!fghGetTouchInputInfo) {
1079 if (fghGetTouchInputInfo( (HTOUCHINPUT)lParam, numInputs, ti, sizeof(TOUCHINPUT) )) {
1080 /* Handle each contact point */
1081 for (i = 0; i < numInputs; ++i ) {
1084 tp.x = TOUCH_COORD_TO_PIXEL(ti[i].x);
1085 tp.y = TOUCH_COORD_TO_PIXEL(ti[i].y);
1086 ScreenToClient( hWnd, &tp );
1088 ti[i].dwID = ti[i].dwID * 2;
1090 if (ti[i].dwFlags & TOUCHEVENTF_DOWN) {
1091 INVOKE_WCB( *window, MultiEntry, ( ti[i].dwID, GLUT_ENTERED ) );
1092 INVOKE_WCB( *window, MultiButton, ( ti[i].dwID, tp.x, tp.y, 0, GLUT_DOWN ) );
1093 } else if (ti[i].dwFlags & TOUCHEVENTF_MOVE) {
1094 INVOKE_WCB( *window, MultiMotion, ( ti[i].dwID, tp.x, tp.y ) );
1095 } else if (ti[i].dwFlags & TOUCHEVENTF_UP) {
1096 INVOKE_WCB( *window, MultiButton, ( ti[i].dwID, tp.x, tp.y, 0, GLUT_UP ) );
1097 INVOKE_WCB( *window, MultiEntry, ( ti[i].dwID, GLUT_LEFT ) );
1101 fghCloseTouchInputHandle((HTOUCHINPUT)lParam);
1103 lRet = 0; /*DefWindowProc( hWnd, uMsg, wParam, lParam );*/
1108 /* Handle unhandled messages */
1109 lRet = DefWindowProc( hWnd, uMsg, wParam, lParam );