/*
- * freeglut_main_mswin.c
+ * fg_main_mswin.c
*
* The Windows-specific mouse cursor related stuff.
*
#endif /* _WIN32_WCE */
#ifdef _DEBUG
-/*
+/*
* WM_ message to string, for debugging
* This is taken from the 8.0 SDK, so Windows 8 API and everything earlier is included
*/
-# if(_WIN32_WINNT >= 0x0500)
+# if(_WIN32_WINNT >= 0x0500) && defined(WM_NCXBUTTONDOWN)
DEFINE_MESSAGE(WM_NCXBUTTONDOWN),
DEFINE_MESSAGE(WM_NCXBUTTONUP),
DEFINE_MESSAGE(WM_NCXBUTTONDBLCLK),
DEFINE_MESSAGE(WM_UNINITMENUPOPUP),
DEFINE_MESSAGE(WM_MENUCOMMAND),
-# if(_WIN32_WINNT >= 0x0500)
+# if(_WIN32_WINNT >= 0x0500) && defined(WM_CHANGEUISTATE)
DEFINE_MESSAGE(WM_CHANGEUISTATE),
DEFINE_MESSAGE(WM_UPDATEUISTATE),
DEFINE_MESSAGE(WM_QUERYUISTATE),
# if (_WIN32_WINNT >= 0x0400) || (_WIN32_WINDOWS > 0x0400)
DEFINE_MESSAGE(WM_MOUSEWHEEL),
# endif
-# if (_WIN32_WINNT >= 0x0500)
+# if (_WIN32_WINNT >= 0x0500) && defined(WM_XBUTTONDOWN)
DEFINE_MESSAGE(WM_XBUTTONDOWN),
DEFINE_MESSAGE(WM_XBUTTONUP),
DEFINE_MESSAGE(WM_XBUTTONDBLCLK),
DEFINE_MESSAGE(WM_MOUSEHOVER),
DEFINE_MESSAGE(WM_MOUSELEAVE),
# endif
-# if(WINVER >= 0x0500)
+# if(WINVER >= 0x0500) && defined(WM_NCMOUSEHOVER)
DEFINE_MESSAGE(WM_NCMOUSEHOVER),
DEFINE_MESSAGE(WM_NCMOUSELEAVE),
# endif /* WINVER >= 0x0500 */
DEFINE_MESSAGE(WM_PRINTCLIENT),
# endif /* WINVER >= 0x0400 */
-# if(_WIN32_WINNT >= 0x0500)
+# if(_WIN32_WINNT >= 0x0500) && defined(WM_APPCOMMAND)
DEFINE_MESSAGE(WM_APPCOMMAND),
# endif /* _WIN32_WINNT >= 0x0500 */
/* Check if we just wrapped */
if (currTime32 < lastTime32)
timeEpoch++;
-
+
lastTime32 = currTime32;
return currTime32 | timeEpoch << 32;
{
SFG_Window *saved_window = fgStructure.CurrentWindow;
- /* On win32 we only have two states, window displayed and window not displayed (iconified)
+ /* On win32 we only have two states, window displayed and window not displayed (iconified)
* We map these to GLUT_FULLY_RETAINED and GLUT_HIDDEN respectively.
*/
INVOKE_WCB( *window, WindowStatus, ( visState ? GLUT_FULLY_RETAINED:GLUT_HIDDEN ) );
rControl = 0, rShift = 0, rAlt = 0;
int keypress = -1;
-
+
/* if keydown, check for repeat */
/* If repeat is globally switched off, it cannot be switched back on per window.
* But if it is globally switched on, it can be switched off per window. This matches
*/
if( keydown && ( fgState.KeyRepeat==GLUT_KEY_REPEAT_OFF || window->State.IgnoreKeyRepeat==GL_TRUE ) && (HIWORD(lParam) & KF_REPEAT) )
return 1;
-
+
/* Remember the current modifiers state so user can query it from their callback */
fgState.Modifiers = fgPlatformGetModifiers( );
/* Convert the Win32 keystroke codes to GLUTtish way */
-# define KEY(a,b) case a: keypress = b; break;
+# define FG_KEY(a,b) case a: keypress = b; break;
switch( wParam )
{
- KEY( VK_F1, GLUT_KEY_F1 );
- KEY( VK_F2, GLUT_KEY_F2 );
- KEY( VK_F3, GLUT_KEY_F3 );
- KEY( VK_F4, GLUT_KEY_F4 );
- KEY( VK_F5, GLUT_KEY_F5 );
- KEY( VK_F6, GLUT_KEY_F6 );
- KEY( VK_F7, GLUT_KEY_F7 );
- KEY( VK_F8, GLUT_KEY_F8 );
- KEY( VK_F9, GLUT_KEY_F9 );
- KEY( VK_F10, GLUT_KEY_F10 );
- KEY( VK_F11, GLUT_KEY_F11 );
- KEY( VK_F12, GLUT_KEY_F12 );
- KEY( VK_PRIOR, GLUT_KEY_PAGE_UP );
- KEY( VK_NEXT, GLUT_KEY_PAGE_DOWN );
- KEY( VK_HOME, GLUT_KEY_HOME );
- KEY( VK_END, GLUT_KEY_END );
- KEY( VK_LEFT, GLUT_KEY_LEFT );
- KEY( VK_UP, GLUT_KEY_UP );
- KEY( VK_RIGHT, GLUT_KEY_RIGHT );
- KEY( VK_DOWN, GLUT_KEY_DOWN );
- KEY( VK_INSERT, GLUT_KEY_INSERT );
+ FG_KEY( VK_F1, GLUT_KEY_F1 );
+ FG_KEY( VK_F2, GLUT_KEY_F2 );
+ FG_KEY( VK_F3, GLUT_KEY_F3 );
+ FG_KEY( VK_F4, GLUT_KEY_F4 );
+ FG_KEY( VK_F5, GLUT_KEY_F5 );
+ FG_KEY( VK_F6, GLUT_KEY_F6 );
+ FG_KEY( VK_F7, GLUT_KEY_F7 );
+ FG_KEY( VK_F8, GLUT_KEY_F8 );
+ FG_KEY( VK_F9, GLUT_KEY_F9 );
+ FG_KEY( VK_F10, GLUT_KEY_F10 );
+ FG_KEY( VK_F11, GLUT_KEY_F11 );
+ FG_KEY( VK_F12, GLUT_KEY_F12 );
+ FG_KEY( VK_PRIOR, GLUT_KEY_PAGE_UP );
+ FG_KEY( VK_NEXT, GLUT_KEY_PAGE_DOWN );
+ FG_KEY( VK_HOME, GLUT_KEY_HOME );
+ FG_KEY( VK_END, GLUT_KEY_END );
+ FG_KEY( VK_LEFT, GLUT_KEY_LEFT );
+ FG_KEY( VK_UP, GLUT_KEY_UP );
+ FG_KEY( VK_RIGHT, GLUT_KEY_RIGHT );
+ FG_KEY( VK_DOWN, GLUT_KEY_DOWN );
+ FG_KEY( VK_INSERT, GLUT_KEY_INSERT );
/* handle control, alt and shift. For GLUT, we want to distinguish between left and right presses.
* The VK_L* & VK_R* left and right Alt, Ctrl and Shift virtual keys are however only used as parameters to GetAsyncKeyState() and GetKeyState()
* so when we get an alt, shift or control keypress here, we manually check whether it was the left or the right
*/
-#define KEY_EVENT(winKey,glutKey,keyStateVar)\
+#define FG_KEY_EVENT(winKey,glutKey,keyStateVar)\
if (!keyStateVar && fgGetKeyState ( winKey ))\
{\
keypress = glutKey;\
keyStateVar = 0;\
}
case VK_CONTROL:
- KEY_EVENT(VK_LCONTROL,GLUT_KEY_CTRL_L,lControl);
- KEY_EVENT(VK_RCONTROL,GLUT_KEY_CTRL_R,rControl);
+ FG_KEY_EVENT(VK_LCONTROL,GLUT_KEY_CTRL_L,lControl);
+ FG_KEY_EVENT(VK_RCONTROL,GLUT_KEY_CTRL_R,rControl);
break;
case VK_SHIFT:
- KEY_EVENT(VK_LSHIFT,GLUT_KEY_SHIFT_L,lShift);
- KEY_EVENT(VK_RSHIFT,GLUT_KEY_SHIFT_R,rShift);
+ FG_KEY_EVENT(VK_LSHIFT,GLUT_KEY_SHIFT_L,lShift);
+ FG_KEY_EVENT(VK_RSHIFT,GLUT_KEY_SHIFT_R,rShift);
break;
case VK_MENU:
- KEY_EVENT(VK_LMENU,GLUT_KEY_ALT_L,lAlt);
- KEY_EVENT(VK_RMENU,GLUT_KEY_ALT_R,rAlt);
+ FG_KEY_EVENT(VK_LMENU,GLUT_KEY_ALT_L,lAlt);
+ FG_KEY_EVENT(VK_RMENU,GLUT_KEY_ALT_R,rAlt);
break;
#undef KEY_EVENT
keypress = GLUT_KEY_F4;
}
#endif
-
+
if( keypress != -1 )
if (keydown)
INVOKE_WCB( *window, Special,
/* Get mouse position at time of message */
DWORD mouse_pos_dw = GetMessagePos();
- POINT mouse_pos = {GET_X_LPARAM(mouse_pos_dw), GET_Y_LPARAM(mouse_pos_dw)};
+ POINT mouse_pos;
+ mouse_pos.x = GET_X_LPARAM(mouse_pos_dw);
+ mouse_pos.y = GET_Y_LPARAM(mouse_pos_dw);
ScreenToClient( window->Window.Handle, &mouse_pos );
-
+
hwnd = ChildWindowFromPoint(window->Window.Handle, mouse_pos);
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 */
{
/* Update visibility state of the window */
if (wParam==SIZE_MINIMIZED)
fghPlatformOnWindowStatusNotify(window,GL_FALSE,GL_FALSE);
- else if (wParam==SIZE_RESTORED && !window->State.Visible)
+ else if ((wParam==SIZE_RESTORED || wParam == SIZE_MAXIMIZED) && !window->State.Visible)
fghPlatformOnWindowStatusNotify(window,GL_TRUE,GL_FALSE);
/* Check window visible, we don't want do anything when we get a WM_SIZE because the user or glutIconifyWindow minimized the window */
width = LOWORD(lParam);
height = HIWORD(lParam);
#endif /* defined(_WIN32_WCE) */
-
+
/* Update state and call callback, if there was a change */
fghOnReshapeNotify(window, width, height, GL_FALSE);
}
if (!IsIconic(window->Window.Handle))
{
RECT windowRect;
-
+
/* lParam contains coordinates of top-left of client area.
* Get top-left of non-client area of window, matching coordinates of
- * glutInitPosition and glutPositionWindow, but not those of
+ * glutInitPosition and glutPositionWindow, but not those of
* glutGet(GLUT_WINDOW_X) and glutGet(GLUT_WINDOW_Y), which return
* top-left of client area.
*/
GetWindowRect( window->Window.Handle, &windowRect );
-
+
if (window->Parent)
{
/* For child window, we should return relative to upper-left
* of parent's client area.
*/
- POINT topleft = {windowRect.left,windowRect.top};
+ POINT topleft;
+ topleft.x = windowRect.left;
+ topleft.y = windowRect.top;
ScreenToClient(window->Parent->Window.Handle,&topleft);
windowRect.left = topleft.x;
{
TRACKMOUSEEVENT tme;
- /* Cursor just entered window, set cursor look */
+ /* Cursor just entered window, set cursor look */
fgSetCursor ( window, window->State.Cursor ) ;
/* If an EntryFunc callback is specified by the user, also
case WM_PAINT:
{
RECT rect;
-
+
/* As per docs, upon receiving WM_PAINT, first check if the update region is not empty before you call BeginPaint */
if (GetUpdateRect(hWnd,&rect,FALSE))
{
{
int wheel_number = 0; /* Only one scroll wheel on windows */
#if defined(_WIN32_WCE)
- int modkeys = LOWORD(wParam);
+ int modkeys = LOWORD(wParam);
short ticks = (short)HIWORD(wParam);
/* commented out as should not be needed here, mouse motion is processed in WM_MOUSEMOVE first:
xPos = LOWORD(lParam); -- straight from docs, not consistent with mouse nutton and mouse motion above (which i think is wrong)
*/
#else
/* int modkeys = GET_KEYSTATE_WPARAM( wParam ); */
- short ticks = GET_WHEEL_DELTA_WPARAM( wParam );
+ short ticks = HIWORD( wParam );
/* commented out as should not be needed here, mouse motion is processed in WM_MOUSEMOVE first:
window->State.MouseX = GET_X_LPARAM( lParam );
window->State.MouseY = GET_Y_LPARAM( lParam );
window = fghWindowUnderCursor(window);
- fgState.MouseWheelTicks += ticks;
+ fgState.MouseWheelTicks += ticks;
if ( abs ( fgState.MouseWheelTicks ) >= WHEEL_DELTA )
- {
- int direction = ( fgState.MouseWheelTicks > 0 ) ? 1 : -1;
+ {
+ int direction = ( fgState.MouseWheelTicks > 0 ) ? 1 : -1;
if( ! FETCH_WCB( *window, MouseWheel ) &&
! FETCH_WCB( *window, Mouse ) )
fgState.Modifiers = fgPlatformGetModifiers( );
while( abs ( fgState.MouseWheelTicks ) >= WHEEL_DELTA )
- {
+ {
if( FETCH_WCB( *window, MouseWheel ) )
INVOKE_WCB( *window, MouseWheel,
( wheel_number,
)
);
else /* No mouse wheel, call the mouse button callback twice */
- {
+ {
/*
* Map wheel zero to button 3 and 4; +1 to 3, -1 to 4
* " " one +1 to 5, -1 to 6, ...
( button, GLUT_UP,
window->State.MouseX, window->State.MouseY )
);
- }
+ }
- fgState.MouseWheelTicks -= WHEEL_DELTA * direction;
- }
+ fgState.MouseWheelTicks -= WHEEL_DELTA * direction;
+ }
fgState.Modifiers = INVALID_MODIFIERS;
- }
+ }
/* Per docs, should return zero */
lRet = 0;
}
break;
#ifdef WM_TOUCH
- /* handle multi-touch messages */
- case WM_TOUCH:
- {
- unsigned int numInputs = (unsigned int)wParam;
- unsigned int i = 0;
- TOUCHINPUT* ti = (TOUCHINPUT*)malloc( sizeof(TOUCHINPUT)*numInputs);
-
- if (fghGetTouchInputInfo == (pGetTouchInputInfo)0xDEADBEEF) {
- fghGetTouchInputInfo = (pGetTouchInputInfo)GetProcAddress(GetModuleHandle("user32"),"GetTouchInputInfo");
- fghCloseTouchInputHandle = (pCloseTouchInputHandle)GetProcAddress(GetModuleHandle("user32"),"CloseTouchInputHandle");
- }
-
- if (!fghGetTouchInputInfo) {
- free( (void*)ti );
- break;
- }
-
- if (fghGetTouchInputInfo( (HTOUCHINPUT)lParam, numInputs, ti, sizeof(TOUCHINPUT) )) {
- /* Handle each contact point */
- for (i = 0; i < numInputs; ++i ) {
-
- POINT tp;
- tp.x = TOUCH_COORD_TO_PIXEL(ti[i].x);
- tp.y = TOUCH_COORD_TO_PIXEL(ti[i].y);
- ScreenToClient( hWnd, &tp );
-
- ti[i].dwID = ti[i].dwID * 2;
-
- if (ti[i].dwFlags & TOUCHEVENTF_DOWN) {
- INVOKE_WCB( *window, MultiEntry, ( ti[i].dwID, GLUT_ENTERED ) );
- INVOKE_WCB( *window, MultiButton, ( ti[i].dwID, tp.x, tp.y, 0, GLUT_DOWN ) );
- } else if (ti[i].dwFlags & TOUCHEVENTF_MOVE) {
- INVOKE_WCB( *window, MultiMotion, ( ti[i].dwID, tp.x, tp.y ) );
- } else if (ti[i].dwFlags & TOUCHEVENTF_UP) {
- INVOKE_WCB( *window, MultiButton, ( ti[i].dwID, tp.x, tp.y, 0, GLUT_UP ) );
- INVOKE_WCB( *window, MultiEntry, ( ti[i].dwID, GLUT_LEFT ) );
- }
- }
- }
- fghCloseTouchInputHandle((HTOUCHINPUT)lParam);
- free( (void*)ti );
- lRet = 0; /*DefWindowProc( hWnd, uMsg, wParam, lParam );*/
- break;
- }
+ /* handle multi-touch messages */
+ case WM_TOUCH:
+ {
+ unsigned int numInputs = (unsigned int)wParam;
+ unsigned int i = 0;
+ TOUCHINPUT* ti = (TOUCHINPUT*)malloc( sizeof(TOUCHINPUT)*numInputs);
+
+ if (fghGetTouchInputInfo == (pGetTouchInputInfo)0xDEADBEEF) {
+ fghGetTouchInputInfo = (pGetTouchInputInfo)GetProcAddress(GetModuleHandle("user32"),"GetTouchInputInfo");
+ fghCloseTouchInputHandle = (pCloseTouchInputHandle)GetProcAddress(GetModuleHandle("user32"),"CloseTouchInputHandle");
+ }
+
+ if (!fghGetTouchInputInfo) {
+ free( (void*)ti );
+ break;
+ }
+
+ if (fghGetTouchInputInfo( (HTOUCHINPUT)lParam, numInputs, ti, sizeof(TOUCHINPUT) )) {
+ /* Handle each contact point */
+ for (i = 0; i < numInputs; ++i ) {
+
+ POINT tp;
+ tp.x = TOUCH_COORD_TO_PIXEL(ti[i].x);
+ tp.y = TOUCH_COORD_TO_PIXEL(ti[i].y);
+ ScreenToClient( hWnd, &tp );
+
+ ti[i].dwID = ti[i].dwID * 2;
+
+ if (ti[i].dwFlags & TOUCHEVENTF_DOWN) {
+ INVOKE_WCB( *window, MultiEntry, ( ti[i].dwID, GLUT_ENTERED ) );
+ INVOKE_WCB( *window, MultiButton, ( ti[i].dwID, tp.x, tp.y, 0, GLUT_DOWN ) );
+ } else if (ti[i].dwFlags & TOUCHEVENTF_MOVE) {
+ INVOKE_WCB( *window, MultiMotion, ( ti[i].dwID, tp.x, tp.y ) );
+ } else if (ti[i].dwFlags & TOUCHEVENTF_UP) {
+ INVOKE_WCB( *window, MultiButton, ( ti[i].dwID, tp.x, tp.y, 0, GLUT_UP ) );
+ INVOKE_WCB( *window, MultiEntry, ( ti[i].dwID, GLUT_LEFT ) );
+ }
+ }
+ }
+ fghCloseTouchInputHandle((HTOUCHINPUT)lParam);
+ free( (void*)ti );
+ lRet = 0; /*DefWindowProc( hWnd, uMsg, wParam, lParam );*/
+ break;
+ }
+#endif
+
+#ifdef WM_INPUT
+ case WM_INPUT:
+ /* Added by Jinrong Xie <stonexjr at gmail.com> for SpaceNavigator support on Windows. Dec 2014 */
+ if (fgHasSpaceball())
+ {
+ fgSpaceballHandleWinEvent(hWnd, wParam, lParam);
+ }
+ break;
#endif
default:
/* Handle unhandled messages */
window->State.DesiredWidth = window->State.pWState.OldRect.right - window->State.pWState.OldRect.left;
window->State.DesiredHeight = window->State.pWState.OldRect.bottom - window->State.pWState.OldRect.top;
}
-
+
/* We'll finish off the fullscreen operation below after the other GLUT_POSITION_WORK|GLUT_SIZE_WORK|GLUT_ZORDER_WORK */
}
else
RECT rect;
HMONITOR hMonitor;
MONITORINFO mi;
-
+
/* save current window rect, style, exstyle and maximized state */
window->State.pWState.OldMaximized = !!IsZoomed(window->Window.Handle);
if (window->State.pWState.OldMaximized)
/* For fullscreen mode, find the monitor that is covered the most
* by the window and get its rect as the resize target.
- */
- GetWindowRect(window->Window.Handle, &rect);
- hMonitor= MonitorFromRect(&rect, MONITOR_DEFAULTTONEAREST);
+ */
+ hMonitor= MonitorFromWindow(window->Window.Handle, MONITOR_DEFAULTTONEAREST);
mi.cbSize = sizeof(mi);
GetMonitorInfo(hMonitor, &mi);
rect = mi.rcMonitor;
/* Now deal with normal position, reshape and z order requests (some might have been set when handling GLUT_FULLSCREEN_WORK above */
{
- /* get rect describing window's current position and size,
+ /* get rect describing window's current position and size,
* in screen coordinates and in FreeGLUT format
* (size (right-left, bottom-top) is client area size, top and left
* are outside of window including decorations).
if (workMask & GLUT_POSITION_WORK)
{
flags &= ~SWP_NOMOVE;
-
+
/* Move rect so that top-left is at requested position */
/* This also automatically makes sure that child window requested coordinates are relative
* to top-left of parent's client area (needed input for SetWindowPos on child windows),
if (workMask & GLUT_SIZE_WORK)
{
flags &= ~SWP_NOSIZE;
-
+
/* Note on maximizing behavior of Windows: the resize borders are off
* the screen such that the client area extends all the way from the
* leftmost corner to the rightmost corner to maximize screen real
if (!window->Parent)
/* get the window rect from this to feed to SetWindowPos, correct for window decorations */
fghComputeWindowRectFromClientArea_QueryWindow(&clientRect,window,TRUE);
-
+
/* Do the requested positioning, moving, and z order push/pop. */
SetWindowPos( window->Window.Handle,
insertAfter,
win = win->Parent;
break;
case DesireNormalState:
- if (win->IsMenu && (!fgStructure.GameModeWindow || win->ActiveMenu->ParentWindow != fgStructure.GameModeWindow))
- cmdShow = SW_SHOWNA; /* Just show, don't activate window if its a menu. Only exception is when the parent is a gamemode window as the menu would pop under it when we do this... */
+ if (win->IsMenu && !fgStructure.GameModeWindow)
+ cmdShow = SW_SHOWNA; /* Just show, don't activate window if its a menu. Only exception is when there is a gamemode window as the menu would pop under it when we do this... */
else
cmdShow = SW_SHOW;
break;
}
ShowWindow( win->Window.Handle, cmdShow );
-}
\ No newline at end of file
+}