| | |
| | | /* |
| | | Simple DirectMedia Layer |
| | | Copyright (C) 1997-2013 Sam Lantinga <slouken@libsdl.org> |
| | | Copyright (C) 1997-2014 Sam Lantinga <slouken@libsdl.org> |
| | | |
| | | This software is provided 'as-is', without any express or implied |
| | | warranty. In no event will the authors be held liable for any damages |
| | |
| | | misrepresented as being the original software. |
| | | 3. This notice may not be removed or altered from any source distribution. |
| | | */ |
| | | #include "SDL_config.h" |
| | | #include "../../SDL_internal.h" |
| | | |
| | | #if SDL_VIDEO_DRIVER_WINDOWS |
| | | |
| | | #include "SDL_windowsvideo.h" |
| | | #include "SDL_windowsshape.h" |
| | | #include "SDL_syswm.h" |
| | | #include "SDL_timer.h" |
| | | #include "SDL_vkeys.h" |
| | | #include "../../events/SDL_events_c.h" |
| | | #include "../../events/SDL_touch_c.h" |
| | |
| | | #endif |
| | | #ifndef WM_TOUCH |
| | | #define WM_TOUCH 0x0240 |
| | | #endif |
| | | #ifndef WM_MOUSEHWHEEL |
| | | #define WM_MOUSEHWHEEL 0x020E |
| | | #endif |
| | | |
| | | static SDL_Scancode |
| | |
| | | } |
| | | } |
| | | |
| | | void |
| | | WIN_CheckAsyncMouseRelease( SDL_WindowData *data ) |
| | | { |
| | | Uint32 mouseFlags; |
| | | SHORT keyState; |
| | | |
| | | /* mouse buttons may have changed state here, we need to resync them, |
| | | but we will get a WM_MOUSEMOVE right away which will fix things up if in non raw mode also |
| | | */ |
| | | mouseFlags = SDL_GetMouseState( NULL, NULL ); |
| | | |
| | | keyState = GetAsyncKeyState( VK_LBUTTON ); |
| | | WIN_CheckWParamMouseButton( ( keyState & 0x8000 ), ( mouseFlags & SDL_BUTTON_LMASK ), data, SDL_BUTTON_LEFT ); |
| | | keyState = GetAsyncKeyState( VK_RBUTTON ); |
| | | WIN_CheckWParamMouseButton( ( keyState & 0x8000 ), ( mouseFlags & SDL_BUTTON_RMASK ), data, SDL_BUTTON_RIGHT ); |
| | | keyState = GetAsyncKeyState( VK_MBUTTON ); |
| | | WIN_CheckWParamMouseButton( ( keyState & 0x8000 ), ( mouseFlags & SDL_BUTTON_MMASK ), data, SDL_BUTTON_MIDDLE ); |
| | | keyState = GetAsyncKeyState( VK_XBUTTON1 ); |
| | | WIN_CheckWParamMouseButton( ( keyState & 0x8000 ), ( mouseFlags & SDL_BUTTON_X1MASK ), data, SDL_BUTTON_X1 ); |
| | | keyState = GetAsyncKeyState( VK_XBUTTON2 ); |
| | | WIN_CheckWParamMouseButton( ( keyState & 0x8000 ), ( mouseFlags & SDL_BUTTON_X2MASK ), data, SDL_BUTTON_X2 ); |
| | | data->mouse_button_flags = 0; |
| | | } |
| | | |
| | | SDL_FORCE_INLINE BOOL |
| | | WIN_ConvertUTF32toUTF8(UINT32 codepoint, char * text) |
| | | { |
| | |
| | | } |
| | | |
| | | #ifdef WMMSG_DEBUG |
| | | { |
| | | char message[1024]; |
| | | if (msg > MAX_WMMSG) { |
| | | SDL_snprintf(message, sizeof(message), "Received windows message: %p UNKNOWN (%d) -- 0x%X, 0x%X\n", hwnd, msg, wParam, lParam); |
| | | } else { |
| | | SDL_snprintf(message, sizeof(message), "Received windows message: %p %s -- 0x%X, 0x%X\n", hwnd, wmtab[msg], wParam, lParam); |
| | | } |
| | | OutputDebugStringA(message); |
| | | } |
| | | { |
| | | char message[1024]; |
| | | if (msg > MAX_WMMSG) { |
| | | SDL_snprintf(message, sizeof(message), "Received windows message: %p UNKNOWN (%d) -- 0x%X, 0x%X\n", hwnd, msg, wParam, lParam); |
| | | } else { |
| | | SDL_snprintf(message, sizeof(message), "Received windows message: %p %s -- 0x%X, 0x%X\n", hwnd, wmtab[msg], wParam, lParam); |
| | | } |
| | | OutputDebugStringA(message); |
| | | } |
| | | #endif /* WMMSG_DEBUG */ |
| | | |
| | | if (IME_HandleMessage(hwnd, msg, wParam, &lParam, data->videodata)) |
| | |
| | | |
| | | minimized = HIWORD(wParam); |
| | | if (!minimized && (LOWORD(wParam) != WA_INACTIVE)) { |
| | | Uint32 mouseFlags; |
| | | SHORT keyState; |
| | | |
| | | SDL_SendWindowEvent(data->window, SDL_WINDOWEVENT_SHOWN, 0, 0); |
| | | SDL_SendWindowEvent(data->window, |
| | | SDL_WINDOWEVENT_RESTORED, 0, 0); |
| | | if (IsZoomed(hwnd)) { |
| | | SDL_SendWindowEvent(data->window, |
| | | SDL_WINDOWEVENT_MAXIMIZED, 0, 0); |
| | | } |
| | | if (SDL_GetKeyboardFocus() != data->window) { |
| | | SDL_SetKeyboardFocus(data->window); |
| | | } |
| | | /* mouse buttons may have changed state here, we need |
| | | to resync them, but we will get a WM_MOUSEMOVE right away which will fix |
| | | things up if in non raw mode also |
| | | */ |
| | | mouseFlags = SDL_GetMouseState( NULL, NULL ); |
| | | |
| | | keyState = GetAsyncKeyState( VK_LBUTTON ); |
| | | WIN_CheckWParamMouseButton( ( keyState & 0x8000 ), (mouseFlags & SDL_BUTTON_LMASK), data, SDL_BUTTON_LEFT ); |
| | | keyState = GetAsyncKeyState( VK_RBUTTON ); |
| | | WIN_CheckWParamMouseButton( ( keyState & 0x8000 ), (mouseFlags & SDL_BUTTON_RMASK), data, SDL_BUTTON_RIGHT ); |
| | | keyState = GetAsyncKeyState( VK_MBUTTON ); |
| | | WIN_CheckWParamMouseButton( ( keyState & 0x8000 ), (mouseFlags & SDL_BUTTON_MMASK), data, SDL_BUTTON_MIDDLE ); |
| | | keyState = GetAsyncKeyState( VK_XBUTTON1 ); |
| | | WIN_CheckWParamMouseButton( ( keyState & 0x8000 ), (mouseFlags & SDL_BUTTON_X1MASK), data, SDL_BUTTON_X1 ); |
| | | keyState = GetAsyncKeyState( VK_XBUTTON2 ); |
| | | WIN_CheckWParamMouseButton( ( keyState & 0x8000 ), (mouseFlags & SDL_BUTTON_X2MASK), data, SDL_BUTTON_X2 ); |
| | | data->mouse_button_flags = 0; |
| | | |
| | | if(SDL_GetMouse()->relative_mode) { |
| | | LONG cx, cy; |
| | | RECT rect; |
| | | GetWindowRect(hwnd, &rect); |
| | | |
| | | cx = (rect.left + rect.right) / 2; |
| | | cy = (rect.top + rect.bottom) / 2; |
| | | |
| | | /* Make an absurdly small clip rect */ |
| | | rect.left = cx-1; |
| | | rect.right = cx+1; |
| | | rect.top = cy-1; |
| | | rect.bottom = cy+1; |
| | | |
| | | ClipCursor(&rect); |
| | | } |
| | | WIN_UpdateClipCursor(data->window); |
| | | WIN_CheckAsyncMouseRelease(data); |
| | | |
| | | /* |
| | | * FIXME: Update keyboard state |
| | |
| | | if (SDL_GetKeyboardFocus() == data->window) { |
| | | SDL_SetKeyboardFocus(NULL); |
| | | } |
| | | if (minimized) { |
| | | SDL_SendWindowEvent(data->window, |
| | | SDL_WINDOWEVENT_MINIMIZED, 0, 0); |
| | | } |
| | | |
| | | ClipCursor(NULL); |
| | | } |
| | | } |
| | | returnCode = 0; |
| | | break; |
| | | |
| | | case WM_MOUSEMOVE: |
| | | if( !SDL_GetMouse()->relative_mode ) |
| | | SDL_SendMouseMotion(data->window, 0, 0, GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam)); |
| | | { |
| | | SDL_Mouse *mouse = SDL_GetMouse(); |
| | | if (!mouse->relative_mode || mouse->relative_mode_warp) { |
| | | SDL_SendMouseMotion(data->window, 0, 0, GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam)); |
| | | } |
| | | } |
| | | /* don't break here, fall through to check the wParam like the button presses */ |
| | | case WM_LBUTTONUP: |
| | | case WM_RBUTTONUP: |
| | |
| | | case WM_RBUTTONDOWN: |
| | | case WM_MBUTTONDOWN: |
| | | case WM_XBUTTONDOWN: |
| | | if( !SDL_GetMouse()->relative_mode ) |
| | | WIN_CheckWParamMouseButtons( wParam, data ); |
| | | { |
| | | SDL_Mouse *mouse = SDL_GetMouse(); |
| | | if (!mouse->relative_mode || mouse->relative_mode_warp) { |
| | | WIN_CheckWParamMouseButtons(wParam, data); |
| | | } |
| | | } |
| | | break; |
| | | |
| | | case WM_INPUT: |
| | | { |
| | | HRAWINPUT hRawInput = (HRAWINPUT)lParam; |
| | | RAWINPUT inp; |
| | | UINT size = sizeof(inp); |
| | | |
| | | if(!SDL_GetMouse()->relative_mode) |
| | | break; |
| | | |
| | | GetRawInputData(hRawInput, RID_INPUT, &inp, &size, sizeof(RAWINPUTHEADER)); |
| | | |
| | | /* Mouse data */ |
| | | if(inp.header.dwType == RIM_TYPEMOUSE) |
| | | { |
| | | RAWMOUSE* mouse = &inp.data.mouse; |
| | | SDL_Mouse *mouse = SDL_GetMouse(); |
| | | HRAWINPUT hRawInput = (HRAWINPUT)lParam; |
| | | RAWINPUT inp; |
| | | UINT size = sizeof(inp); |
| | | |
| | | if((mouse->usFlags & 0x01) == MOUSE_MOVE_RELATIVE) |
| | | { |
| | | SDL_SendMouseMotion(data->window, 0, 1, (int)mouse->lLastX, (int)mouse->lLastY); |
| | | if (!mouse->relative_mode || mouse->relative_mode_warp || mouse->focus != data->window) { |
| | | break; |
| | | } |
| | | else |
| | | { |
| | | /* synthesize relative moves from the abs position */ |
| | | static SDL_Point initialMousePoint; |
| | | if ( initialMousePoint.x == 0 && initialMousePoint.y == 0 ) |
| | | { |
| | | |
| | | GetRawInputData(hRawInput, RID_INPUT, &inp, &size, sizeof(RAWINPUTHEADER)); |
| | | |
| | | /* Mouse data */ |
| | | if (inp.header.dwType == RIM_TYPEMOUSE) { |
| | | RAWMOUSE* mouse = &inp.data.mouse; |
| | | |
| | | if ((mouse->usFlags & 0x01) == MOUSE_MOVE_RELATIVE) { |
| | | SDL_SendMouseMotion(data->window, 0, 1, (int)mouse->lLastX, (int)mouse->lLastY); |
| | | } else { |
| | | /* synthesize relative moves from the abs position */ |
| | | static SDL_Point initialMousePoint; |
| | | if (initialMousePoint.x == 0 && initialMousePoint.y == 0) { |
| | | initialMousePoint.x = mouse->lLastX; |
| | | initialMousePoint.y = mouse->lLastY; |
| | | } |
| | | |
| | | SDL_SendMouseMotion(data->window, 0, 1, (int)(mouse->lLastX-initialMousePoint.x), (int)(mouse->lLastY-initialMousePoint.y) ); |
| | | |
| | | initialMousePoint.x = mouse->lLastX; |
| | | initialMousePoint.y = mouse->lLastY; |
| | | } |
| | | |
| | | SDL_SendMouseMotion(data->window, 0, 1, (int)(mouse->lLastX-initialMousePoint.x), (int)(mouse->lLastY-initialMousePoint.y) ); |
| | | |
| | | initialMousePoint.x = mouse->lLastX; |
| | | initialMousePoint.y = mouse->lLastY; |
| | | WIN_CheckRawMouseButtons( mouse->usButtonFlags, data ); |
| | | } |
| | | WIN_CheckRawMouseButtons( mouse->usButtonFlags, data ); |
| | | } |
| | | break; |
| | | } |
| | | |
| | | case WM_MOUSEWHEEL: |
| | | { |
| | |
| | | s_AccumulatedMotion += WHEEL_DELTA; |
| | | } |
| | | } |
| | | break; |
| | | } |
| | | break; |
| | | |
| | | case WM_MOUSEHWHEEL: |
| | | { |
| | | static short s_AccumulatedMotion; |
| | | |
| | | s_AccumulatedMotion += GET_WHEEL_DELTA_WPARAM(wParam); |
| | | if (s_AccumulatedMotion > 0) { |
| | | while (s_AccumulatedMotion >= WHEEL_DELTA) { |
| | | SDL_SendMouseWheel(data->window, 0, 1, 0); |
| | | s_AccumulatedMotion -= WHEEL_DELTA; |
| | | } |
| | | } else { |
| | | while (s_AccumulatedMotion <= -WHEEL_DELTA) { |
| | | SDL_SendMouseWheel(data->window, 0, -1, 0); |
| | | s_AccumulatedMotion += WHEEL_DELTA; |
| | | } |
| | | } |
| | | } |
| | | break; |
| | | |
| | | #ifdef WM_MOUSELEAVE |
| | | case WM_MOUSELEAVE: |
| | | if (SDL_GetMouseFocus() == data->window && !SDL_GetMouse()->relative_mode) { |
| | | POINT cursorPos; |
| | | GetCursorPos(&cursorPos); |
| | | ScreenToClient(hwnd, &cursorPos); |
| | | SDL_SendMouseMotion(data->window, 0, 0, cursorPos.x, cursorPos.y); |
| | | if (!IsIconic(hwnd)) { |
| | | POINT cursorPos; |
| | | GetCursorPos(&cursorPos); |
| | | ScreenToClient(hwnd, &cursorPos); |
| | | SDL_SendMouseMotion(data->window, 0, 0, cursorPos.x, cursorPos.y); |
| | | } |
| | | SDL_SetMouseFocus(NULL); |
| | | } |
| | | returnCode = 0; |
| | |
| | | |
| | | GetKeyboardState(keyboardState); |
| | | if (ToUnicode(wParam, (lParam >> 16) & 0xff, keyboardState, (LPWSTR)&utf32, 1, 0) > 0) { |
| | | WORD repitition; |
| | | for (repitition = lParam & 0xffff; repitition > 0; repitition--) { |
| | | WORD repetition; |
| | | for (repetition = lParam & 0xffff; repetition > 0; repetition--) { |
| | | WIN_ConvertUTF32toUTF8(utf32, text); |
| | | SDL_SendKeyboardText(text); |
| | | } |
| | |
| | | case WM_KEYUP: |
| | | { |
| | | SDL_Scancode code = WindowsScanCodeToSDLScanCode( lParam, wParam ); |
| | | const Uint8 *keyboardState = SDL_GetKeyboardState(NULL); |
| | | |
| | | /* Detect relevant keyboard shortcuts */ |
| | | if (keyboardState[SDL_SCANCODE_LALT] == SDL_PRESSED || keyboardState[SDL_SCANCODE_RALT] == SDL_PRESSED ) { |
| | | /* ALT+F4: Close window */ |
| | | if (code == SDL_SCANCODE_F4) { |
| | | SDL_SendWindowEvent(data->window, SDL_WINDOWEVENT_CLOSE, 0, 0); |
| | | } |
| | | } |
| | | |
| | | if ( code != SDL_SCANCODE_UNKNOWN ) { |
| | | if (code == SDL_SCANCODE_PRINTSCREEN && |
| | | SDL_GetKeyboardState(NULL)[code] == SDL_RELEASED) { |
| | | keyboardState[code] == SDL_RELEASED) { |
| | | SDL_SendKeyboardKey(SDL_PRESSED, code); |
| | | } |
| | | SDL_SendKeyboardKey(SDL_RELEASED, code); |
| | |
| | | break; |
| | | |
| | | case WM_UNICHAR: |
| | | { |
| | | if (wParam == UNICODE_NOCHAR) { |
| | | returnCode = 1; |
| | | break; |
| | | } |
| | | } |
| | | /* no break */ |
| | | case WM_CHAR: |
| | | { |
| | | char text[5]; |
| | | |
| | | WIN_ConvertUTF32toUTF8(wParam, text); |
| | | SDL_SendKeyboardText(text); |
| | | } |
| | | /* Ignore WM_CHAR messages that come from TranslateMessage(), since we handle WM_KEY* messages directly */ |
| | | returnCode = 0; |
| | | break; |
| | | |
| | |
| | | returnCode = 1; |
| | | break; |
| | | #endif /* WM_INPUTLANGCHANGE */ |
| | | |
| | | case WM_NCLBUTTONDOWN: |
| | | { |
| | | data->in_title_click = SDL_TRUE; |
| | | WIN_UpdateClipCursor(data->window); |
| | | } |
| | | break; |
| | | |
| | | case WM_NCMOUSELEAVE: |
| | | { |
| | | data->in_title_click = SDL_FALSE; |
| | | WIN_UpdateClipCursor(data->window); |
| | | } |
| | | break; |
| | | |
| | | case WM_ENTERSIZEMOVE: |
| | | case WM_ENTERMENULOOP: |
| | | { |
| | | data->in_modal_loop = SDL_TRUE; |
| | | WIN_UpdateClipCursor(data->window); |
| | | } |
| | | break; |
| | | |
| | | case WM_EXITSIZEMOVE: |
| | | case WM_EXITMENULOOP: |
| | | { |
| | | data->in_modal_loop = SDL_FALSE; |
| | | WIN_UpdateClipCursor(data->window); |
| | | |
| | | /* The mouse may have been released during the modal loop */ |
| | | WIN_CheckAsyncMouseRelease(data); |
| | | } |
| | | break; |
| | | |
| | | #ifdef WM_GETMINMAXINFO |
| | | case WM_GETMINMAXINFO: |
| | |
| | | BOOL menu; |
| | | BOOL constrain_max_size; |
| | | |
| | | /* If we allow resizing, let the resize happen naturally */ |
| | | if (SDL_IsShapedWindow(data->window)) |
| | | Win32_ResizeWindowShape(data->window); |
| | | |
| | | /* If this is an expected size change, allow it */ |
| | | if (data->expected_resize) { |
| | | break; |
| | | } |
| | | |
| | | /* Get the current position of our window */ |
| | | GetWindowRect(hwnd, &size); |
| | |
| | | RECT rect; |
| | | int x, y; |
| | | int w, h; |
| | | Uint32 window_flags; |
| | | |
| | | if (!GetClientRect(hwnd, &rect) || |
| | | (rect.right == rect.left && rect.bottom == rect.top)) { |
| | | if (!GetClientRect(hwnd, &rect) || IsRectEmpty(&rect)) { |
| | | break; |
| | | } |
| | | ClientToScreen(hwnd, (LPPOINT) & rect); |
| | | ClientToScreen(hwnd, (LPPOINT) & rect + 1); |
| | | |
| | | window_flags = SDL_GetWindowFlags(data->window); |
| | | if ((window_flags & SDL_WINDOW_INPUT_GRABBED) && |
| | | (window_flags & SDL_WINDOW_INPUT_FOCUS)) { |
| | | ClipCursor(&rect); |
| | | } |
| | | WIN_UpdateClipCursor(data->window); |
| | | |
| | | x = rect.left; |
| | | y = rect.top; |
| | |
| | | h = rect.bottom - rect.top; |
| | | SDL_SendWindowEvent(data->window, SDL_WINDOWEVENT_RESIZED, w, |
| | | h); |
| | | } |
| | | break; |
| | | |
| | | case WM_SIZE: |
| | | { |
| | | switch (wParam) |
| | | { |
| | | case SIZE_MAXIMIZED: |
| | | SDL_SendWindowEvent(data->window, |
| | | SDL_WINDOWEVENT_MAXIMIZED, 0, 0); |
| | | break; |
| | | case SIZE_MINIMIZED: |
| | | SDL_SendWindowEvent(data->window, |
| | | SDL_WINDOWEVENT_MINIMIZED, 0, 0); |
| | | break; |
| | | default: |
| | | SDL_SendWindowEvent(data->window, |
| | | SDL_WINDOWEVENT_RESTORED, 0, 0); |
| | | break; |
| | | } |
| | | } |
| | | break; |
| | | |
| | |
| | | { |
| | | const Uint8 *keystate; |
| | | MSG msg; |
| | | DWORD start_ticks = GetTickCount(); |
| | | |
| | | while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) { |
| | | DispatchMessage(&msg); |
| | | /* Always translate the message in case it's a non-SDL window (e.g. with Qt integration) */ |
| | | TranslateMessage(&msg); |
| | | DispatchMessage( &msg ); |
| | | |
| | | /* Make sure we don't busy loop here forever if there are lots of events coming in */ |
| | | if (SDL_TICKS_PASSED(msg.time, start_ticks)) { |
| | | break; |
| | | } |
| | | } |
| | | |
| | | /* Windows loses a shift KEYUP event when you have both pressed at once and let go of one. |