early-access version 2281
This commit is contained in:
+318
-196
@@ -81,6 +81,16 @@
|
||||
#define WM_UNICHAR 0x0109
|
||||
#endif
|
||||
|
||||
#ifndef IS_HIGH_SURROGATE
|
||||
#define IS_HIGH_SURROGATE(x) (((x) >= 0xd800) && ((x) <= 0xdbff))
|
||||
#endif
|
||||
#ifndef IS_LOW_SURROGATE
|
||||
#define IS_LOW_SURROGATE(x) (((x) >= 0xdc00) && ((x) <= 0xdfff))
|
||||
#endif
|
||||
#ifndef IS_SURROGATE_PAIR
|
||||
#define IS_SURROGATE_PAIR(h,l) (IS_HIGH_SURROGATE(h) && IS_LOW_SURROGATE(l))
|
||||
#endif
|
||||
|
||||
static SDL_Scancode
|
||||
VKeytoScancodeFallback(WPARAM vkey)
|
||||
{
|
||||
@@ -359,6 +369,76 @@ WIN_CheckAsyncMouseRelease(SDL_WindowData *data)
|
||||
data->mouse_button_flags = 0;
|
||||
}
|
||||
|
||||
static void
|
||||
WIN_UpdateFocus(SDL_Window *window)
|
||||
{
|
||||
SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
|
||||
HWND hwnd = data->hwnd;
|
||||
SDL_bool had_focus = (SDL_GetKeyboardFocus() == window) ? SDL_TRUE : SDL_FALSE;
|
||||
SDL_bool has_focus = (GetForegroundWindow() == hwnd) ? SDL_TRUE : SDL_FALSE;
|
||||
|
||||
if (had_focus == has_focus) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (has_focus) {
|
||||
POINT cursorPos;
|
||||
|
||||
SDL_bool swapButtons = GetSystemMetrics(SM_SWAPBUTTON) != 0;
|
||||
if (GetAsyncKeyState(VK_LBUTTON)) {
|
||||
data->focus_click_pending |= !swapButtons ? SDL_BUTTON_LMASK : SDL_BUTTON_RMASK;
|
||||
}
|
||||
if (GetAsyncKeyState(VK_RBUTTON)) {
|
||||
data->focus_click_pending |= !swapButtons ? SDL_BUTTON_RMASK : SDL_BUTTON_LMASK;
|
||||
}
|
||||
if (GetAsyncKeyState(VK_MBUTTON)) {
|
||||
data->focus_click_pending |= SDL_BUTTON_MMASK;
|
||||
}
|
||||
if (GetAsyncKeyState(VK_XBUTTON1)) {
|
||||
data->focus_click_pending |= SDL_BUTTON_X1MASK;
|
||||
}
|
||||
if (GetAsyncKeyState(VK_XBUTTON2)) {
|
||||
data->focus_click_pending |= SDL_BUTTON_X2MASK;
|
||||
}
|
||||
|
||||
SDL_SetKeyboardFocus(window);
|
||||
|
||||
/* In relative mode we are guaranteed to have mouse focus if we have keyboard focus */
|
||||
if (!SDL_GetMouse()->relative_mode) {
|
||||
GetCursorPos(&cursorPos);
|
||||
ScreenToClient(hwnd, &cursorPos);
|
||||
SDL_SendMouseMotion(window, 0, 0, cursorPos.x, cursorPos.y);
|
||||
}
|
||||
|
||||
WIN_CheckAsyncMouseRelease(data);
|
||||
WIN_UpdateClipCursor(window);
|
||||
|
||||
/*
|
||||
* FIXME: Update keyboard state
|
||||
*/
|
||||
WIN_CheckClipboardUpdate(data->videodata);
|
||||
|
||||
SDL_ToggleModState(KMOD_CAPS, (GetKeyState(VK_CAPITAL) & 0x0001) != 0);
|
||||
SDL_ToggleModState(KMOD_NUM, (GetKeyState(VK_NUMLOCK) & 0x0001) != 0);
|
||||
SDL_ToggleModState(KMOD_SCROLL, (GetKeyState(VK_SCROLL) & 0x0001) != 0);
|
||||
|
||||
} else {
|
||||
RECT rect;
|
||||
|
||||
data->in_window_deactivation = SDL_TRUE;
|
||||
|
||||
SDL_SetKeyboardFocus(NULL);
|
||||
WIN_ResetDeadKeys();
|
||||
|
||||
if (GetClipCursor(&rect) && SDL_memcmp(&rect, &data->cursor_clipped_rect, sizeof(rect)) == 0) {
|
||||
ClipCursor(NULL);
|
||||
SDL_zero(data->cursor_clipped_rect);
|
||||
}
|
||||
|
||||
data->in_window_deactivation = SDL_FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
static BOOL
|
||||
WIN_ConvertUTF32toUTF8(UINT32 codepoint, char * text)
|
||||
{
|
||||
@@ -386,17 +466,20 @@ WIN_ConvertUTF32toUTF8(UINT32 codepoint, char * text)
|
||||
return SDL_TRUE;
|
||||
}
|
||||
|
||||
static BOOL
|
||||
WIN_ConvertUTF16toUTF8(UINT32 high_surrogate, UINT32 low_surrogate, char * text)
|
||||
{
|
||||
const UINT32 SURROGATE_OFFSET = 0x10000 - (0xD800 << 10) - 0xDC00;
|
||||
const UINT32 codepoint = (high_surrogate << 10) + low_surrogate + SURROGATE_OFFSET;
|
||||
return WIN_ConvertUTF32toUTF8(codepoint, text);
|
||||
}
|
||||
|
||||
static SDL_bool
|
||||
ShouldGenerateWindowCloseOnAltF4(void)
|
||||
{
|
||||
return !SDL_GetHintBoolean(SDL_HINT_WINDOWS_NO_CLOSE_ON_ALT_F4, SDL_FALSE);
|
||||
}
|
||||
|
||||
/* Win10 "Fall Creators Update" introduced the bug that SetCursorPos() (as used by SDL_WarpMouseInWindow())
|
||||
doesn't reliably generate WM_MOUSEMOVE events anymore (see #3931) which breaks relative mouse mode via warping.
|
||||
This is used to implement a workaround.. */
|
||||
static SDL_bool isWin10FCUorNewer = SDL_FALSE;
|
||||
|
||||
/* We want to generate mouse events from mouse and pen, and touch events from touchscreens */
|
||||
#define MI_WP_SIGNATURE 0xFF515700
|
||||
#define MI_WP_SIGNATURE_MASK 0xFFFFFF00
|
||||
@@ -507,6 +590,30 @@ WIN_KeyboardHookProc(int nCode, WPARAM wParam, LPARAM lParam)
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void WIN_CheckICMProfileChanged(SDL_Window* window)
|
||||
{
|
||||
SDL_VideoDisplay* display = SDL_GetDisplayForWindow(window);
|
||||
SDL_DisplayData* data = (SDL_DisplayData*)display->driverdata;
|
||||
static WCHAR currentIcmFileName[MAX_PATH] = { '\0' };
|
||||
WCHAR icmFileName[MAX_PATH];
|
||||
HDC hdc;
|
||||
SDL_bool succeeded;
|
||||
DWORD fileNameSize = MAX_PATH;
|
||||
|
||||
hdc = CreateDCW(data->DeviceName, NULL, NULL, NULL);
|
||||
if (hdc) {
|
||||
succeeded = GetICMProfileW(hdc, &fileNameSize, icmFileName);
|
||||
DeleteDC(hdc);
|
||||
if (succeeded) {
|
||||
|
||||
if (SDL_wcsncmp(currentIcmFileName, icmFileName, fileNameSize)) {
|
||||
SDL_wcslcpy(currentIcmFileName, icmFileName, fileNameSize);
|
||||
SDL_SendWindowEvent(window, SDL_WINDOWEVENT_ICCPROF_CHANGED, 0, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
LRESULT CALLBACK
|
||||
WIN_WindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
|
||||
{
|
||||
@@ -567,77 +674,28 @@ WIN_WindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
|
||||
{
|
||||
/* Don't immediately clip the cursor in case we're clicking minimize/maximize buttons */
|
||||
data->skip_update_clipcursor = SDL_TRUE;
|
||||
|
||||
/* Update the focus here, since it's possible to get WM_ACTIVATE and WM_SETFOCUS without
|
||||
actually being the foreground window, but this appears to get called in all cases where
|
||||
the global foreground window changes to and from this window. */
|
||||
WIN_UpdateFocus(data->window);
|
||||
WIN_CheckICMProfileChanged(data->window);
|
||||
}
|
||||
break;
|
||||
|
||||
case WM_ACTIVATE:
|
||||
{
|
||||
POINT cursorPos;
|
||||
BOOL minimized;
|
||||
|
||||
minimized = HIWORD(wParam);
|
||||
if (!minimized && (LOWORD(wParam) != WA_INACTIVE)) {
|
||||
/* Don't mark the window as shown if it's activated before being shown */
|
||||
if (!IsWindowVisible(hwnd)) {
|
||||
break;
|
||||
}
|
||||
if (LOWORD(wParam) == WA_CLICKACTIVE) {
|
||||
SDL_bool swapButtons = GetSystemMetrics(SM_SWAPBUTTON) != 0;
|
||||
if (GetAsyncKeyState(VK_LBUTTON)) {
|
||||
data->focus_click_pending |= !swapButtons ? SDL_BUTTON_LMASK : SDL_BUTTON_RMASK;
|
||||
}
|
||||
if (GetAsyncKeyState(VK_RBUTTON)) {
|
||||
data->focus_click_pending |= !swapButtons ? SDL_BUTTON_RMASK : SDL_BUTTON_LMASK;
|
||||
}
|
||||
if (GetAsyncKeyState(VK_MBUTTON)) {
|
||||
data->focus_click_pending |= SDL_BUTTON_MMASK;
|
||||
}
|
||||
if (GetAsyncKeyState(VK_XBUTTON1)) {
|
||||
data->focus_click_pending |= SDL_BUTTON_X1MASK;
|
||||
}
|
||||
if (GetAsyncKeyState(VK_XBUTTON2)) {
|
||||
data->focus_click_pending |= SDL_BUTTON_X2MASK;
|
||||
}
|
||||
}
|
||||
|
||||
SDL_SendWindowEvent(data->window, SDL_WINDOWEVENT_SHOWN, 0, 0);
|
||||
if (SDL_GetKeyboardFocus() != data->window) {
|
||||
SDL_SetKeyboardFocus(data->window);
|
||||
}
|
||||
|
||||
GetCursorPos(&cursorPos);
|
||||
ScreenToClient(hwnd, &cursorPos);
|
||||
SDL_SendMouseMotion(data->window, 0, 0, cursorPos.x, cursorPos.y);
|
||||
|
||||
WIN_CheckAsyncMouseRelease(data);
|
||||
WIN_UpdateClipCursor(data->window);
|
||||
|
||||
/*
|
||||
* FIXME: Update keyboard state
|
||||
*/
|
||||
WIN_CheckClipboardUpdate(data->videodata);
|
||||
|
||||
SDL_ToggleModState(KMOD_CAPS, (GetKeyState(VK_CAPITAL) & 0x0001) != 0);
|
||||
SDL_ToggleModState(KMOD_NUM, (GetKeyState(VK_NUMLOCK) & 0x0001) != 0);
|
||||
} else {
|
||||
RECT rect;
|
||||
|
||||
data->in_window_deactivation = SDL_TRUE;
|
||||
|
||||
if (SDL_GetKeyboardFocus() == data->window) {
|
||||
SDL_SetKeyboardFocus(NULL);
|
||||
WIN_ResetDeadKeys();
|
||||
}
|
||||
|
||||
if (GetClipCursor(&rect) && SDL_memcmp(&rect, &data->cursor_clipped_rect, sizeof(rect)) == 0) {
|
||||
ClipCursor(NULL);
|
||||
SDL_zero(data->cursor_clipped_rect);
|
||||
}
|
||||
|
||||
data->in_window_deactivation = SDL_FALSE;
|
||||
}
|
||||
/* Update the focus in case we changed focus to a child window and then away from the application */
|
||||
WIN_UpdateFocus(data->window);
|
||||
}
|
||||
break;
|
||||
|
||||
case WM_SETFOCUS:
|
||||
case WM_KILLFOCUS:
|
||||
{
|
||||
/* Update the focus in case it's changing between top-level windows in the same application */
|
||||
WIN_UpdateFocus(data->window);
|
||||
}
|
||||
returnCode = 0;
|
||||
break;
|
||||
|
||||
case WM_POINTERUPDATE:
|
||||
@@ -649,29 +707,29 @@ WIN_WindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
|
||||
case WM_MOUSEMOVE:
|
||||
{
|
||||
SDL_Mouse *mouse = SDL_GetMouse();
|
||||
|
||||
if (!data->mouse_tracked) {
|
||||
TRACKMOUSEEVENT trackMouseEvent;
|
||||
|
||||
trackMouseEvent.cbSize = sizeof(TRACKMOUSEEVENT);
|
||||
trackMouseEvent.dwFlags = TME_LEAVE;
|
||||
trackMouseEvent.hwndTrack = data->hwnd;
|
||||
|
||||
if (TrackMouseEvent(&trackMouseEvent)) {
|
||||
data->mouse_tracked = SDL_TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
if (!mouse->relative_mode || mouse->relative_mode_warp) {
|
||||
/* Only generate mouse events for real mouse */
|
||||
if (GetMouseMessageSource() != SDL_MOUSE_EVENT_SOURCE_TOUCH &&
|
||||
lParam != data->last_pointer_update) {
|
||||
SDL_SendMouseMotion(data->window, 0, 0, GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam));
|
||||
if (isWin10FCUorNewer && mouse->relative_mode_warp) {
|
||||
/* To work around #3931, Win10 bug introduced in Fall Creators Update, where
|
||||
SetCursorPos() (SDL_WarpMouseInWindow()) doesn't reliably generate mouse events anymore,
|
||||
after each windows mouse event generate a fake event for the middle of the window
|
||||
if relative_mode_warp is used */
|
||||
int center_x = 0, center_y = 0;
|
||||
SDL_GetWindowSize(data->window, ¢er_x, ¢er_y);
|
||||
center_x /= 2;
|
||||
center_y /= 2;
|
||||
SDL_SendMouseMotion(data->window, 0, 0, center_x, center_y);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
/* We still need to update focus */
|
||||
SDL_SetMouseFocus(data->window);
|
||||
}
|
||||
}
|
||||
/* don't break here, fall through to check the wParam like the button presses */
|
||||
SDL_FALLTHROUGH;
|
||||
case WM_LBUTTONUP:
|
||||
case WM_RBUTTONUP:
|
||||
case WM_MBUTTONUP:
|
||||
@@ -701,13 +759,15 @@ WIN_WindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
|
||||
HRAWINPUT hRawInput = (HRAWINPUT)lParam;
|
||||
RAWINPUT inp;
|
||||
UINT size = sizeof(inp);
|
||||
const SDL_bool isRelative = mouse->relative_mode || mouse->relative_mode_warp;
|
||||
const SDL_bool isCapture = ((data->window->flags & SDL_WINDOW_MOUSE_CAPTURE) != 0);
|
||||
|
||||
if (!isRelative || mouse->focus != data->window) {
|
||||
if (!isCapture) {
|
||||
break;
|
||||
}
|
||||
/* We only use raw mouse input in relative mode */
|
||||
if (!mouse->relative_mode || mouse->relative_mode_warp) {
|
||||
break;
|
||||
}
|
||||
|
||||
/* Relative mouse motion is delivered to the window with keyboard focus */
|
||||
if (data->window != SDL_GetKeyboardFocus()) {
|
||||
break;
|
||||
}
|
||||
|
||||
GetRawInputData(hRawInput, RID_INPUT, &inp, &size, sizeof(RAWINPUTHEADER));
|
||||
@@ -715,61 +775,93 @@ WIN_WindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
|
||||
/* Mouse data (ignoring synthetic mouse events generated for touchscreens) */
|
||||
if (inp.header.dwType == RIM_TYPEMOUSE) {
|
||||
SDL_MouseID mouseID;
|
||||
RAWMOUSE* rawmouse;
|
||||
if (SDL_GetNumTouchDevices() > 0 &&
|
||||
(GetMouseMessageSource() == SDL_MOUSE_EVENT_SOURCE_TOUCH || (GetMessageExtraInfo() & 0x82) == 0x82)) {
|
||||
break;
|
||||
}
|
||||
mouseID = (SDL_MouseID)(uintptr_t)inp.header.hDevice;
|
||||
if (isRelative) {
|
||||
RAWMOUSE* rawmouse = &inp.data.mouse;
|
||||
/* We do all of our mouse state checking against mouse ID 0
|
||||
* We would only use the actual hDevice if we were tracking
|
||||
* all mouse motion independently, and never using mouse ID 0.
|
||||
*/
|
||||
mouseID = 0; /* (SDL_MouseID)(uintptr_t)inp.header.hDevice; */
|
||||
rawmouse = &inp.data.mouse;
|
||||
|
||||
if ((rawmouse->usFlags & 0x01) == MOUSE_MOVE_RELATIVE) {
|
||||
SDL_SendMouseMotion(data->window, mouseID, 1, (int)rawmouse->lLastX, (int)rawmouse->lLastY);
|
||||
} else if (rawmouse->lLastX || rawmouse->lLastY) {
|
||||
/* synthesize relative moves from the abs position */
|
||||
static SDL_Point lastMousePoint;
|
||||
SDL_bool virtual_desktop = (rawmouse->usFlags & MOUSE_VIRTUAL_DESKTOP) ? SDL_TRUE : SDL_FALSE;
|
||||
int w = GetSystemMetrics(virtual_desktop ? SM_CXVIRTUALSCREEN : SM_CXSCREEN);
|
||||
int h = GetSystemMetrics(virtual_desktop ? SM_CYVIRTUALSCREEN : SM_CYSCREEN);
|
||||
int x = (int)(((float)rawmouse->lLastX / 65535.0f) * w);
|
||||
int y = (int)(((float)rawmouse->lLastY / 65535.0f) * h);
|
||||
if ((rawmouse->usFlags & 0x01) == MOUSE_MOVE_RELATIVE) {
|
||||
SDL_SendMouseMotion(data->window, mouseID, 1, (int)rawmouse->lLastX, (int)rawmouse->lLastY);
|
||||
} else if (rawmouse->lLastX || rawmouse->lLastY) {
|
||||
/* This is absolute motion, either using a tablet or mouse over RDP
|
||||
|
||||
if (lastMousePoint.x == 0 && lastMousePoint.y == 0) {
|
||||
lastMousePoint.x = x;
|
||||
lastMousePoint.y = y;
|
||||
Notes on how RDP appears to work, as of Windows 10 2004:
|
||||
- SetCursorPos() calls are cached, with multiple calls coalesced into a single call that's sent to the RDP client. If the last call to SetCursorPos() has the same value as the last one that was sent to the client, it appears to be ignored and not sent. This means that we need to jitter the SetCursorPos() position slightly in order for the recentering to work correctly.
|
||||
- User mouse motion is coalesced with SetCursorPos(), so the WM_INPUT positions we see will not necessarily match the positon we requested with SetCursorPos().
|
||||
- SetCursorPos() outside of the bounds of the focus window appears not to do anything.
|
||||
- SetCursorPos() while the cursor is NULL doesn't do anything
|
||||
|
||||
We handle this by creating a safe area within the application window, and when the mouse leaves that safe area, we warp back to the opposite side. Any single motion > 50% of the safe area is assumed to be a warp and ignored.
|
||||
*/
|
||||
SDL_bool remote_desktop = GetSystemMetrics(SM_REMOTESESSION) ? SDL_TRUE : SDL_FALSE;
|
||||
SDL_bool virtual_desktop = (rawmouse->usFlags & MOUSE_VIRTUAL_DESKTOP) ? SDL_TRUE : SDL_FALSE;
|
||||
SDL_bool normalized_coordinates = ((rawmouse->usFlags & 0x40) == 0) ? SDL_TRUE : SDL_FALSE;
|
||||
int w = GetSystemMetrics(virtual_desktop ? SM_CXVIRTUALSCREEN : SM_CXSCREEN);
|
||||
int h = GetSystemMetrics(virtual_desktop ? SM_CYVIRTUALSCREEN : SM_CYSCREEN);
|
||||
int x = normalized_coordinates ? (int)(((float)rawmouse->lLastX / 65535.0f) * w) : (int)rawmouse->lLastX;
|
||||
int y = normalized_coordinates ? (int)(((float)rawmouse->lLastY / 65535.0f) * h) : (int)rawmouse->lLastY;
|
||||
int relX, relY;
|
||||
|
||||
/* Calculate relative motion */
|
||||
if (data->last_raw_mouse_position.x == 0 && data->last_raw_mouse_position.y == 0) {
|
||||
data->last_raw_mouse_position.x = x;
|
||||
data->last_raw_mouse_position.y = y;
|
||||
}
|
||||
relX = (int)(x - data->last_raw_mouse_position.x);
|
||||
relY = (int)(y - data->last_raw_mouse_position.y);
|
||||
|
||||
if (remote_desktop) {
|
||||
if (!data->in_title_click && !data->focus_click_pending) {
|
||||
static int wobble;
|
||||
float floatX = (float)x / w;
|
||||
float floatY = (float)y / h;
|
||||
|
||||
/* See if the mouse is at the edge of the screen, or in the RDP title bar area */
|
||||
if (floatX <= 0.01f || floatX >= 0.99f || floatY <= 0.01f || floatY >= 0.99f || y < 32) {
|
||||
/* Wobble the cursor position so it's not ignored if the last warp didn't have any effect */
|
||||
RECT rect = data->cursor_clipped_rect;
|
||||
int warpX = rect.left + ((rect.right - rect.left) / 2) + wobble;
|
||||
int warpY = rect.top + ((rect.bottom - rect.top) / 2);
|
||||
|
||||
WIN_SetCursorPos(warpX, warpY);
|
||||
|
||||
++wobble;
|
||||
if (wobble > 1) {
|
||||
wobble = -1;
|
||||
}
|
||||
} else {
|
||||
/* Send relative motion if we didn't warp last frame (had good position data)
|
||||
We also sometimes get large deltas due to coalesced mouse motion and warping,
|
||||
so ignore those.
|
||||
*/
|
||||
const int MAX_RELATIVE_MOTION = (h / 6);
|
||||
if (SDL_abs(relX) < MAX_RELATIVE_MOTION &&
|
||||
SDL_abs(relY) < MAX_RELATIVE_MOTION) {
|
||||
SDL_SendMouseMotion(data->window, mouseID, 1, relX, relY);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
const int MAXIMUM_TABLET_RELATIVE_MOTION = 32;
|
||||
if (SDL_abs(relX) > MAXIMUM_TABLET_RELATIVE_MOTION ||
|
||||
SDL_abs(relY) > MAXIMUM_TABLET_RELATIVE_MOTION) {
|
||||
/* Ignore this motion, probably a pen lift and drop */
|
||||
} else {
|
||||
SDL_SendMouseMotion(data->window, mouseID, 1, relX, relY);
|
||||
}
|
||||
|
||||
SDL_SendMouseMotion(data->window, mouseID, 1, (int)(x-lastMousePoint.x), (int)(y-lastMousePoint.y));
|
||||
|
||||
lastMousePoint.x = x;
|
||||
lastMousePoint.y = y;
|
||||
}
|
||||
WIN_CheckRawMouseButtons(rawmouse->usButtonFlags, data, mouseID);
|
||||
} else if (isCapture) {
|
||||
/* we check for where Windows thinks the system cursor lives in this case, so we don't really lose mouse accel, etc. */
|
||||
POINT pt;
|
||||
RECT hwndRect;
|
||||
HWND currentHnd;
|
||||
|
||||
GetCursorPos(&pt);
|
||||
currentHnd = WindowFromPoint(pt);
|
||||
ScreenToClient(hwnd, &pt);
|
||||
GetClientRect(hwnd, &hwndRect);
|
||||
|
||||
/* if in the window, WM_MOUSEMOVE, etc, will cover it. */
|
||||
if(currentHnd != hwnd || pt.x < 0 || pt.y < 0 || pt.x > hwndRect.right || pt.y > hwndRect.right) {
|
||||
SDL_bool swapButtons = GetSystemMetrics(SM_SWAPBUTTON) != 0;
|
||||
|
||||
SDL_SendMouseMotion(data->window, mouseID, 0, (int)pt.x, (int)pt.y);
|
||||
SDL_SendMouseButton(data->window, mouseID, GetAsyncKeyState(VK_LBUTTON) & 0x8000 ? SDL_PRESSED : SDL_RELEASED, !swapButtons ? SDL_BUTTON_LEFT : SDL_BUTTON_RIGHT);
|
||||
SDL_SendMouseButton(data->window, mouseID, GetAsyncKeyState(VK_RBUTTON) & 0x8000 ? SDL_PRESSED : SDL_RELEASED, !swapButtons ? SDL_BUTTON_RIGHT : SDL_BUTTON_LEFT);
|
||||
SDL_SendMouseButton(data->window, mouseID, GetAsyncKeyState(VK_MBUTTON) & 0x8000 ? SDL_PRESSED : SDL_RELEASED, SDL_BUTTON_MIDDLE);
|
||||
SDL_SendMouseButton(data->window, mouseID, GetAsyncKeyState(VK_XBUTTON1) & 0x8000 ? SDL_PRESSED : SDL_RELEASED, SDL_BUTTON_X1);
|
||||
SDL_SendMouseButton(data->window, mouseID, GetAsyncKeyState(VK_XBUTTON2) & 0x8000 ? SDL_PRESSED : SDL_RELEASED, SDL_BUTTON_X2);
|
||||
}
|
||||
} else {
|
||||
SDL_assert(0 && "Shouldn't happen");
|
||||
data->last_raw_mouse_position.x = x;
|
||||
data->last_raw_mouse_position.y = y;
|
||||
}
|
||||
WIN_CheckRawMouseButtons(rawmouse->usButtonFlags, data, mouseID);
|
||||
}
|
||||
}
|
||||
break;
|
||||
@@ -786,10 +878,9 @@ WIN_WindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
|
||||
}
|
||||
break;
|
||||
|
||||
#ifdef WM_MOUSELEAVE
|
||||
case WM_MOUSELEAVE:
|
||||
if (SDL_GetMouseFocus() == data->window && !SDL_GetMouse()->relative_mode && !(data->window->flags & SDL_WINDOW_MOUSE_CAPTURE)) {
|
||||
if (!IsIconic(hwnd)) {
|
||||
if (!(data->window->flags & SDL_WINDOW_MOUSE_CAPTURE)) {
|
||||
if (SDL_GetMouseFocus() == data->window && !SDL_GetMouse()->relative_mode && !IsIconic(hwnd)) {
|
||||
SDL_Mouse *mouse;
|
||||
POINT cursorPos;
|
||||
GetCursorPos(&cursorPos);
|
||||
@@ -806,19 +897,16 @@ WIN_WindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* When WM_MOUSELEAVE is fired we can be assured that the cursor has left the window */
|
||||
SDL_SetMouseFocus(NULL);
|
||||
}
|
||||
|
||||
/* When WM_MOUSELEAVE is fired we can be assured that the cursor has left the window.
|
||||
Regardless of relative mode, it is important that mouse focus is reset as there is a potential
|
||||
race condition when in the process of leaving/entering relative mode, resulting in focus never
|
||||
being lost. This then causes a cascading failure where SDL_WINDOWEVENT_ENTER / SDL_WINDOWEVENT_LEAVE
|
||||
can stop firing permanently, due to the focus being in the wrong state and TrackMouseEvent never
|
||||
resubscribing. */
|
||||
SDL_SetMouseFocus(NULL);
|
||||
/* Once we get WM_MOUSELEAVE we're guaranteed that the window is no longer tracked */
|
||||
data->mouse_tracked = SDL_FALSE;
|
||||
|
||||
returnCode = 0;
|
||||
break;
|
||||
#endif /* WM_MOUSELEAVE */
|
||||
|
||||
case WM_KEYDOWN:
|
||||
case WM_SYSKEYDOWN:
|
||||
@@ -862,11 +950,36 @@ WIN_WindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
|
||||
case WM_UNICHAR:
|
||||
if (wParam == UNICODE_NOCHAR) {
|
||||
returnCode = 1;
|
||||
break;
|
||||
} else {
|
||||
char text[5];
|
||||
if (WIN_ConvertUTF32toUTF8((UINT32)wParam, text)) {
|
||||
SDL_SendKeyboardText(text);
|
||||
}
|
||||
returnCode = 0;
|
||||
}
|
||||
/* otherwise fall through to below */
|
||||
break;
|
||||
|
||||
case WM_CHAR:
|
||||
{
|
||||
/* When a user enters a Unicode code point defined in the Basic Multilingual Plane, Windows sends a WM_CHAR
|
||||
message with the code point encoded as UTF-16. When a user enters a Unicode code point from a Supplementary
|
||||
Plane, Windows sends the code point in two separate WM_CHAR messages: The first message includes the UTF-16
|
||||
High Surrogate and the second the UTF-16 Low Surrogate. The High and Low Surrogates cannot be individually
|
||||
converted to valid UTF-8, therefore, we must save the High Surrogate from the first WM_CHAR message and
|
||||
concatenate it with the Low Surrogate from the second WM_CHAR message. At that point, we have a valid
|
||||
UTF-16 surrogate pair ready to re-encode as UTF-8. */
|
||||
if (IS_HIGH_SURROGATE(wParam)) {
|
||||
data->high_surrogate = (WCHAR)wParam;
|
||||
} else if (IS_SURROGATE_PAIR(data->high_surrogate, wParam)) {
|
||||
/* The code point is in a Supplementary Plane.
|
||||
Here wParam is the Low Surrogate. */
|
||||
char text[5];
|
||||
if (WIN_ConvertUTF16toUTF8((UINT32)data->high_surrogate, (UINT32)wParam, text)) {
|
||||
SDL_SendKeyboardText(text);
|
||||
}
|
||||
data->high_surrogate = 0;
|
||||
} else {
|
||||
/* The code point is in the Basic Multilingual Plane.
|
||||
It's numerically equal to UTF-32. */
|
||||
char text[5];
|
||||
if (WIN_ConvertUTF32toUTF8((UINT32)wParam, text)) {
|
||||
SDL_SendKeyboardText(text);
|
||||
@@ -1027,6 +1140,8 @@ WIN_WindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
|
||||
|
||||
/* Forces a WM_PAINT event */
|
||||
InvalidateRect(hwnd, NULL, FALSE);
|
||||
|
||||
WIN_CheckICMProfileChanged(data->window);
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -1276,6 +1391,31 @@ static void WIN_UpdateClipCursorForWindows()
|
||||
}
|
||||
}
|
||||
|
||||
static void WIN_UpdateMouseCapture()
|
||||
{
|
||||
SDL_Window* focusWindow = SDL_GetKeyboardFocus();
|
||||
|
||||
if (focusWindow && (focusWindow->flags & SDL_WINDOW_MOUSE_CAPTURE)) {
|
||||
SDL_WindowData *data = (SDL_WindowData *) focusWindow->driverdata;
|
||||
|
||||
if (!data->mouse_tracked) {
|
||||
POINT pt;
|
||||
|
||||
if (GetCursorPos(&pt) && ScreenToClient(data->hwnd, &pt)) {
|
||||
SDL_bool swapButtons = GetSystemMetrics(SM_SWAPBUTTON) != 0;
|
||||
SDL_MouseID mouseID = SDL_GetMouse()->mouseID;
|
||||
|
||||
SDL_SendMouseMotion(data->window, mouseID, 0, (int)pt.x, (int)pt.y);
|
||||
SDL_SendMouseButton(data->window, mouseID, GetAsyncKeyState(VK_LBUTTON) & 0x8000 ? SDL_PRESSED : SDL_RELEASED, !swapButtons ? SDL_BUTTON_LEFT : SDL_BUTTON_RIGHT);
|
||||
SDL_SendMouseButton(data->window, mouseID, GetAsyncKeyState(VK_RBUTTON) & 0x8000 ? SDL_PRESSED : SDL_RELEASED, !swapButtons ? SDL_BUTTON_RIGHT : SDL_BUTTON_LEFT);
|
||||
SDL_SendMouseButton(data->window, mouseID, GetAsyncKeyState(VK_MBUTTON) & 0x8000 ? SDL_PRESSED : SDL_RELEASED, SDL_BUTTON_MIDDLE);
|
||||
SDL_SendMouseButton(data->window, mouseID, GetAsyncKeyState(VK_XBUTTON1) & 0x8000 ? SDL_PRESSED : SDL_RELEASED, SDL_BUTTON_X1);
|
||||
SDL_SendMouseButton(data->window, mouseID, GetAsyncKeyState(VK_XBUTTON2) & 0x8000 ? SDL_PRESSED : SDL_RELEASED, SDL_BUTTON_X2);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* A message hook called before TranslateMessage() */
|
||||
static SDL_WindowsMessageHook g_WindowsMessageHook = NULL;
|
||||
static void *g_WindowsMessageHookData = NULL;
|
||||
@@ -1334,8 +1474,9 @@ WIN_PumpEvents(_THIS)
|
||||
{
|
||||
const Uint8 *keystate;
|
||||
MSG msg;
|
||||
DWORD start_ticks = GetTickCount();
|
||||
DWORD end_ticks = GetTickCount() + 1;
|
||||
int new_messages = 0;
|
||||
SDL_Window *focusWindow;
|
||||
|
||||
if (g_WindowsEnableMessageLoop) {
|
||||
while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) {
|
||||
@@ -1343,12 +1484,22 @@ WIN_PumpEvents(_THIS)
|
||||
g_WindowsMessageHook(g_WindowsMessageHookData, msg.hwnd, msg.message, msg.wParam, msg.lParam);
|
||||
}
|
||||
|
||||
/* Don't dispatch any mouse motion queued prior to or including the last mouse warp */
|
||||
if (msg.message == WM_MOUSEMOVE && SDL_last_warp_time) {
|
||||
if (!SDL_TICKS_PASSED(msg.time, (SDL_last_warp_time + 1))) {
|
||||
continue;
|
||||
}
|
||||
|
||||
/* This mouse message happened after the warp */
|
||||
SDL_last_warp_time = 0;
|
||||
}
|
||||
|
||||
/* 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)) {
|
||||
if (SDL_TICKS_PASSED(msg.time, end_ticks)) {
|
||||
/* We might get a few new messages generated by the Steam overlay or other application hooks
|
||||
In this case those messages will be processed before any pending input, so we want to continue after those messages.
|
||||
(thanks to Peter Deayton for his investigation here)
|
||||
@@ -1373,54 +1524,27 @@ WIN_PumpEvents(_THIS)
|
||||
if ((keystate[SDL_SCANCODE_RSHIFT] == SDL_PRESSED) && !(GetKeyState(VK_RSHIFT) & 0x8000)) {
|
||||
SDL_SendKeyboardKey(SDL_RELEASED, SDL_SCANCODE_RSHIFT);
|
||||
}
|
||||
/* The Windows key state gets lost when using Windows+Space or Windows+G shortcuts */
|
||||
if ((keystate[SDL_SCANCODE_LGUI] == SDL_PRESSED) && !(GetKeyState(VK_LWIN) & 0x8000)) {
|
||||
SDL_SendKeyboardKey(SDL_RELEASED, SDL_SCANCODE_LGUI);
|
||||
}
|
||||
if ((keystate[SDL_SCANCODE_RGUI] == SDL_PRESSED) && !(GetKeyState(VK_RWIN) & 0x8000)) {
|
||||
SDL_SendKeyboardKey(SDL_RELEASED, SDL_SCANCODE_RGUI);
|
||||
|
||||
/* The Windows key state gets lost when using Windows+Space or Windows+G shortcuts and
|
||||
not grabbing the keyboard. Note: If we *are* grabbing the keyboard, GetKeyState()
|
||||
will return inaccurate results for VK_LWIN and VK_RWIN but we don't need it anyway. */
|
||||
focusWindow = SDL_GetKeyboardFocus();
|
||||
if (!focusWindow || !(focusWindow->flags & SDL_WINDOW_KEYBOARD_GRABBED)) {
|
||||
if ((keystate[SDL_SCANCODE_LGUI] == SDL_PRESSED) && !(GetKeyState(VK_LWIN) & 0x8000)) {
|
||||
SDL_SendKeyboardKey(SDL_RELEASED, SDL_SCANCODE_LGUI);
|
||||
}
|
||||
if ((keystate[SDL_SCANCODE_RGUI] == SDL_PRESSED) && !(GetKeyState(VK_RWIN) & 0x8000)) {
|
||||
SDL_SendKeyboardKey(SDL_RELEASED, SDL_SCANCODE_RGUI);
|
||||
}
|
||||
}
|
||||
|
||||
/* Update the clipping rect in case someone else has stolen it */
|
||||
WIN_UpdateClipCursorForWindows();
|
||||
|
||||
/* Update mouse capture */
|
||||
WIN_UpdateMouseCapture();
|
||||
}
|
||||
|
||||
/* to work around #3931, a bug introduced in Win10 Fall Creators Update (build nr. 16299)
|
||||
we need to detect the windows version. this struct and the function below does that.
|
||||
usually this struct and the corresponding function (RtlGetVersion) are in <Ntddk.h>
|
||||
but here we just load it dynamically */
|
||||
struct SDL_WIN_OSVERSIONINFOW {
|
||||
ULONG dwOSVersionInfoSize;
|
||||
ULONG dwMajorVersion;
|
||||
ULONG dwMinorVersion;
|
||||
ULONG dwBuildNumber;
|
||||
ULONG dwPlatformId;
|
||||
WCHAR szCSDVersion[128];
|
||||
};
|
||||
|
||||
static SDL_bool
|
||||
IsWin10FCUorNewer(void)
|
||||
{
|
||||
HMODULE handle = GetModuleHandle(TEXT("ntdll.dll"));
|
||||
if (handle) {
|
||||
typedef LONG(WINAPI* RtlGetVersionPtr)(struct SDL_WIN_OSVERSIONINFOW*);
|
||||
RtlGetVersionPtr getVersionPtr = (RtlGetVersionPtr)GetProcAddress(handle, "RtlGetVersion");
|
||||
if (getVersionPtr != NULL) {
|
||||
struct SDL_WIN_OSVERSIONINFOW info;
|
||||
SDL_zero(info);
|
||||
info.dwOSVersionInfoSize = sizeof(info);
|
||||
if (getVersionPtr(&info) == 0) { /* STATUS_SUCCESS == 0 */
|
||||
if ((info.dwMajorVersion == 10 && info.dwMinorVersion == 0 && info.dwBuildNumber >= 16299) ||
|
||||
(info.dwMajorVersion == 10 && info.dwMinorVersion > 0) ||
|
||||
(info.dwMajorVersion > 10))
|
||||
{
|
||||
return SDL_TRUE;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return SDL_FALSE;
|
||||
}
|
||||
|
||||
static int app_registered = 0;
|
||||
LPTSTR SDL_Appname = NULL;
|
||||
@@ -1429,7 +1553,7 @@ HINSTANCE SDL_Instance = NULL;
|
||||
|
||||
/* Register the class for this application */
|
||||
int
|
||||
SDL_RegisterApp(char *name, Uint32 style, void *hInst)
|
||||
SDL_RegisterApp(const char *name, Uint32 style, void *hInst)
|
||||
{
|
||||
const char *hint;
|
||||
WNDCLASSEX wcex;
|
||||
@@ -1486,8 +1610,6 @@ SDL_RegisterApp(char *name, Uint32 style, void *hInst)
|
||||
return SDL_SetError("Couldn't register application class");
|
||||
}
|
||||
|
||||
isWin10FCUorNewer = IsWin10FCUorNewer();
|
||||
|
||||
app_registered = 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
+38
-7
@@ -23,6 +23,7 @@
|
||||
#if SDL_VIDEO_DRIVER_WINDOWS
|
||||
|
||||
#include "SDL_windowsvideo.h"
|
||||
#include "SDL_hints.h"
|
||||
|
||||
#include "../../events/SDL_keyboard_c.h"
|
||||
#include "../../events/scancodes_windows.h"
|
||||
@@ -106,6 +107,7 @@ WIN_InitKeyboard(_THIS)
|
||||
/* Are system caps/num/scroll lock active? Set our state to match. */
|
||||
SDL_ToggleModState(KMOD_CAPS, (GetKeyState(VK_CAPITAL) & 0x0001) != 0);
|
||||
SDL_ToggleModState(KMOD_NUM, (GetKeyState(VK_NUMLOCK) & 0x0001) != 0);
|
||||
SDL_ToggleModState(KMOD_SCROLL, (GetKeyState(VK_SCROLL) & 0x0001) != 0);
|
||||
}
|
||||
|
||||
void
|
||||
@@ -244,15 +246,38 @@ WIN_SetTextInputRect(_THIS, SDL_Rect *rect)
|
||||
himc = ImmGetContext(videodata->ime_hwnd_current);
|
||||
if (himc)
|
||||
{
|
||||
COMPOSITIONFORM cf;
|
||||
cf.ptCurrentPos.x = videodata->ime_rect.x;
|
||||
cf.ptCurrentPos.y = videodata->ime_rect.y;
|
||||
cf.dwStyle = CFS_FORCE_POSITION;
|
||||
ImmSetCompositionWindow(himc, &cf);
|
||||
COMPOSITIONFORM cof;
|
||||
CANDIDATEFORM caf;
|
||||
|
||||
cof.dwStyle = CFS_RECT;
|
||||
cof.ptCurrentPos.x = videodata->ime_rect.x;
|
||||
cof.ptCurrentPos.y = videodata->ime_rect.y;
|
||||
cof.rcArea.left = videodata->ime_rect.x;
|
||||
cof.rcArea.right = videodata->ime_rect.x + videodata->ime_rect.w;
|
||||
cof.rcArea.top = videodata->ime_rect.y;
|
||||
cof.rcArea.bottom = videodata->ime_rect.y + videodata->ime_rect.h;
|
||||
ImmSetCompositionWindow(himc, &cof);
|
||||
|
||||
caf.dwIndex = 0;
|
||||
caf.dwStyle = CFS_EXCLUDE;
|
||||
caf.ptCurrentPos.x = videodata->ime_rect.x;
|
||||
caf.ptCurrentPos.y = videodata->ime_rect.y;
|
||||
caf.rcArea.left = videodata->ime_rect.x;
|
||||
caf.rcArea.right = videodata->ime_rect.x + videodata->ime_rect.w;
|
||||
caf.rcArea.top = videodata->ime_rect.y;
|
||||
caf.rcArea.bottom = videodata->ime_rect.y + videodata->ime_rect.h;
|
||||
ImmSetCandidateWindow(himc, &caf);
|
||||
|
||||
ImmReleaseContext(videodata->ime_hwnd_current, himc);
|
||||
}
|
||||
}
|
||||
|
||||
static SDL_bool
|
||||
WIN_ShouldShowNativeUI()
|
||||
{
|
||||
return SDL_GetHintBoolean(SDL_HINT_IME_SHOW_UI, SDL_FALSE);
|
||||
}
|
||||
|
||||
#ifdef SDL_DISABLE_WINDOWS_IME
|
||||
|
||||
|
||||
@@ -370,7 +395,10 @@ IME_Init(SDL_VideoData *videodata, HWND hwnd)
|
||||
videodata->ime_available = SDL_TRUE;
|
||||
IME_UpdateInputLocale(videodata);
|
||||
IME_SetupAPI(videodata);
|
||||
videodata->ime_uiless = UILess_SetupSinks(videodata);
|
||||
if (WIN_ShouldShowNativeUI())
|
||||
videodata->ime_uiless = SDL_FALSE;
|
||||
else
|
||||
videodata->ime_uiless = UILess_SetupSinks(videodata);
|
||||
IME_UpdateInputLocale(videodata);
|
||||
IME_Disable(videodata, hwnd);
|
||||
}
|
||||
@@ -735,13 +763,16 @@ IME_GetCompositionString(SDL_VideoData *videodata, HIMC himc, DWORD string)
|
||||
|
||||
length /= sizeof(videodata->ime_composition[0]);
|
||||
videodata->ime_cursor = LOWORD(ImmGetCompositionStringW(himc, GCS_CURSORPOS, 0, 0));
|
||||
if (videodata->ime_cursor < SDL_arraysize(videodata->ime_composition) && videodata->ime_composition[videodata->ime_cursor] == 0x3000) {
|
||||
if (videodata->ime_cursor > 0 &&
|
||||
videodata->ime_cursor < SDL_arraysize(videodata->ime_composition) &&
|
||||
videodata->ime_composition[videodata->ime_cursor] == 0x3000) {
|
||||
int i;
|
||||
for (i = videodata->ime_cursor + 1; i < length; ++i)
|
||||
videodata->ime_composition[i - 1] = videodata->ime_composition[i];
|
||||
|
||||
--length;
|
||||
}
|
||||
|
||||
videodata->ime_composition[length] = 0;
|
||||
}
|
||||
|
||||
|
||||
+61
-4
@@ -23,6 +23,7 @@
|
||||
#if SDL_VIDEO_DRIVER_WINDOWS
|
||||
|
||||
#include "SDL_windowsvideo.h"
|
||||
#include "../../events/SDL_displayevents_c.h"
|
||||
|
||||
/* Windows CE compatibility */
|
||||
#ifndef CDS_FULLSCREEN
|
||||
@@ -108,8 +109,50 @@ WIN_UpdateDisplayMode(_THIS, LPCWSTR deviceName, DWORD index, SDL_DisplayMode *
|
||||
}
|
||||
}
|
||||
|
||||
static SDL_DisplayOrientation
|
||||
WIN_GetDisplayOrientation(DEVMODE *mode)
|
||||
{
|
||||
int width = mode->dmPelsWidth;
|
||||
int height = mode->dmPelsHeight;
|
||||
|
||||
/* Use unrotated width/height to guess orientation */
|
||||
if (mode->dmDisplayOrientation == DMDO_90 || mode->dmDisplayOrientation == DMDO_270) {
|
||||
int temp = width;
|
||||
width = height;
|
||||
height = temp;
|
||||
}
|
||||
|
||||
if (width >= height) {
|
||||
switch (mode->dmDisplayOrientation) {
|
||||
case DMDO_DEFAULT:
|
||||
return SDL_ORIENTATION_LANDSCAPE;
|
||||
case DMDO_90:
|
||||
return SDL_ORIENTATION_PORTRAIT;
|
||||
case DMDO_180:
|
||||
return SDL_ORIENTATION_LANDSCAPE_FLIPPED;
|
||||
case DMDO_270:
|
||||
return SDL_ORIENTATION_PORTRAIT_FLIPPED;
|
||||
default:
|
||||
return SDL_ORIENTATION_UNKNOWN;
|
||||
}
|
||||
} else {
|
||||
switch (mode->dmDisplayOrientation) {
|
||||
case DMDO_DEFAULT:
|
||||
return SDL_ORIENTATION_PORTRAIT;
|
||||
case DMDO_90:
|
||||
return SDL_ORIENTATION_LANDSCAPE_FLIPPED;
|
||||
case DMDO_180:
|
||||
return SDL_ORIENTATION_PORTRAIT_FLIPPED;
|
||||
case DMDO_270:
|
||||
return SDL_ORIENTATION_LANDSCAPE;
|
||||
default:
|
||||
return SDL_ORIENTATION_UNKNOWN;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static SDL_bool
|
||||
WIN_GetDisplayMode(_THIS, LPCWSTR deviceName, DWORD index, SDL_DisplayMode * mode)
|
||||
WIN_GetDisplayMode(_THIS, LPCWSTR deviceName, DWORD index, SDL_DisplayMode * mode, SDL_DisplayOrientation *orientation)
|
||||
{
|
||||
SDL_DisplayModeData *data;
|
||||
DEVMODE devmode;
|
||||
@@ -135,6 +178,11 @@ WIN_GetDisplayMode(_THIS, LPCWSTR deviceName, DWORD index, SDL_DisplayMode * mod
|
||||
|
||||
/* Fill in the mode information */
|
||||
WIN_UpdateDisplayMode(_this, deviceName, index, mode);
|
||||
|
||||
if (orientation) {
|
||||
*orientation = WIN_GetDisplayOrientation(&devmode);
|
||||
}
|
||||
|
||||
return SDL_TRUE;
|
||||
}
|
||||
|
||||
@@ -145,13 +193,14 @@ WIN_AddDisplay(_THIS, HMONITOR hMonitor, const MONITORINFOEXW *info, SDL_bool se
|
||||
SDL_VideoDisplay display;
|
||||
SDL_DisplayData *displaydata;
|
||||
SDL_DisplayMode mode;
|
||||
SDL_DisplayOrientation orientation;
|
||||
DISPLAY_DEVICEW device;
|
||||
|
||||
#ifdef DEBUG_MODES
|
||||
SDL_Log("Display: %s\n", WIN_StringToUTF8W(info->szDevice));
|
||||
#endif
|
||||
|
||||
if (!WIN_GetDisplayMode(_this, info->szDevice, ENUM_CURRENT_SETTINGS, &mode)) {
|
||||
if (!WIN_GetDisplayMode(_this, info->szDevice, ENUM_CURRENT_SETTINGS, &mode, &orientation)) {
|
||||
return SDL_FALSE;
|
||||
}
|
||||
|
||||
@@ -163,6 +212,13 @@ WIN_AddDisplay(_THIS, HMONITOR hMonitor, const MONITORINFOEXW *info, SDL_bool se
|
||||
if (SDL_wcscmp(driverdata->DeviceName, info->szDevice) == 0) {
|
||||
driverdata->MonitorHandle = hMonitor;
|
||||
driverdata->IsValid = SDL_TRUE;
|
||||
|
||||
if (!_this->setting_display_mode) {
|
||||
SDL_ResetDisplayModes(i);
|
||||
SDL_SetCurrentDisplayMode(&_this->displays[i], &mode);
|
||||
SDL_SetDesktopDisplayMode(&_this->displays[i], &mode);
|
||||
SDL_SendDisplayEvent(&_this->displays[i], SDL_DISPLAYEVENT_ORIENTATION, orientation);
|
||||
}
|
||||
return SDL_FALSE;
|
||||
}
|
||||
}
|
||||
@@ -183,6 +239,7 @@ WIN_AddDisplay(_THIS, HMONITOR hMonitor, const MONITORINFOEXW *info, SDL_bool se
|
||||
}
|
||||
display.desktop_mode = mode;
|
||||
display.current_mode = mode;
|
||||
display.orientation = orientation;
|
||||
display.driverdata = displaydata;
|
||||
SDL_AddVideoDisplay(&display, send_event);
|
||||
SDL_free(display.name);
|
||||
@@ -356,8 +413,8 @@ WIN_GetDisplayModes(_THIS, SDL_VideoDisplay * display)
|
||||
DWORD i;
|
||||
SDL_DisplayMode mode;
|
||||
|
||||
for (i = 0;; ++i) {
|
||||
if (!WIN_GetDisplayMode(_this, data->DeviceName, i, &mode)) {
|
||||
for (i = 0; ; ++i) {
|
||||
if (!WIN_GetDisplayMode(_this, data->DeviceName, i, &mode, NULL)) {
|
||||
break;
|
||||
}
|
||||
if (SDL_ISPIXELFORMAT_INDEXED(mode.format)) {
|
||||
|
||||
+66
-12
@@ -27,7 +27,9 @@
|
||||
#include "../../events/SDL_mouse_c.h"
|
||||
|
||||
|
||||
DWORD SDL_last_warp_time = 0;
|
||||
HCURSOR SDL_cursor = NULL;
|
||||
static SDL_Cursor *SDL_blank_cursor = NULL;
|
||||
|
||||
static int rawInputEnableCount = 0;
|
||||
|
||||
@@ -94,6 +96,7 @@ WIN_CreateCursor(SDL_Surface * surface, int hot_x, int hot_y)
|
||||
const size_t pad = (sizeof (size_t) * 8); /* 32 or 64, or whatever. */
|
||||
SDL_Cursor *cursor;
|
||||
HICON hicon;
|
||||
HICON hcursor;
|
||||
HDC hdc;
|
||||
BITMAPV4HEADER bmh;
|
||||
LPVOID pixels;
|
||||
@@ -148,17 +151,37 @@ WIN_CreateCursor(SDL_Surface * surface, int hot_x, int hot_y)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* The cursor returned by CreateIconIndirect does not respect system cursor size
|
||||
preference, use CopyImage to duplicate the cursor with desired sizes */
|
||||
hcursor = CopyImage(hicon, IMAGE_CURSOR, 0, 0, LR_DEFAULTSIZE);
|
||||
DestroyIcon(hicon);
|
||||
|
||||
if (!hcursor) {
|
||||
WIN_SetError("CopyImage()");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
cursor = SDL_calloc(1, sizeof(*cursor));
|
||||
if (cursor) {
|
||||
cursor->driverdata = hicon;
|
||||
cursor->driverdata = hcursor;
|
||||
} else {
|
||||
DestroyIcon(hicon);
|
||||
DestroyIcon(hcursor);
|
||||
SDL_OutOfMemory();
|
||||
}
|
||||
|
||||
return cursor;
|
||||
}
|
||||
|
||||
static SDL_Cursor *
|
||||
WIN_CreateBlankCursor()
|
||||
{
|
||||
SDL_Surface *surface = SDL_CreateRGBSurfaceWithFormat(0, 32, 32, 32, SDL_PIXELFORMAT_ARGB8888);
|
||||
if (surface) {
|
||||
return WIN_CreateCursor(surface, 0, 0);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static SDL_Cursor *
|
||||
WIN_CreateSystemCursor(SDL_SystemCursor id)
|
||||
{
|
||||
@@ -210,6 +233,9 @@ WIN_FreeCursor(SDL_Cursor * cursor)
|
||||
static int
|
||||
WIN_ShowCursor(SDL_Cursor * cursor)
|
||||
{
|
||||
if (!cursor) {
|
||||
cursor = SDL_blank_cursor;
|
||||
}
|
||||
if (cursor) {
|
||||
SDL_cursor = (HCURSOR)cursor->driverdata;
|
||||
} else {
|
||||
@@ -221,6 +247,21 @@ WIN_ShowCursor(SDL_Cursor * cursor)
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
WIN_SetCursorPos(int x, int y)
|
||||
{
|
||||
/* We need to jitter the value because otherwise Windows will occasionally inexplicably ignore the SetCursorPos() or SendInput() */
|
||||
SetCursorPos(x, y);
|
||||
SetCursorPos(x+1, y);
|
||||
SetCursorPos(x, y);
|
||||
|
||||
/* Flush any mouse motion prior to or associated with this warp */
|
||||
SDL_last_warp_time = GetTickCount();
|
||||
if (!SDL_last_warp_time) {
|
||||
SDL_last_warp_time = 1;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
WIN_WarpMouse(SDL_Window * window, int x, int y)
|
||||
{
|
||||
@@ -236,7 +277,10 @@ WIN_WarpMouse(SDL_Window * window, int x, int y)
|
||||
pt.x = x;
|
||||
pt.y = y;
|
||||
ClientToScreen(hwnd, &pt);
|
||||
SetCursorPos(pt.x, pt.y);
|
||||
WIN_SetCursorPos(pt.x, pt.y);
|
||||
|
||||
/* Send the exact mouse motion associated with this warp */
|
||||
SDL_SendMouseMotion(window, SDL_GetMouse()->mouseID, 0, x, y);
|
||||
}
|
||||
|
||||
static int
|
||||
@@ -259,18 +303,22 @@ WIN_SetRelativeMouseMode(SDL_bool enabled)
|
||||
static int
|
||||
WIN_CaptureMouse(SDL_Window *window)
|
||||
{
|
||||
if (!window) {
|
||||
SDL_Window *focusWin = SDL_GetKeyboardFocus();
|
||||
if (focusWin) {
|
||||
WIN_OnWindowEnter(SDL_GetVideoDevice(), focusWin); /* make sure WM_MOUSELEAVE messages are (re)enabled. */
|
||||
if (window) {
|
||||
SDL_WindowData *data = (SDL_WindowData *)window->driverdata;
|
||||
SetCapture(data->hwnd);
|
||||
} else {
|
||||
SDL_Window *focus_window = SDL_GetMouseFocus();
|
||||
|
||||
if (focus_window) {
|
||||
SDL_WindowData *data = (SDL_WindowData *)focus_window->driverdata;
|
||||
if (!data->mouse_tracked) {
|
||||
SDL_SetMouseFocus(NULL);
|
||||
}
|
||||
}
|
||||
ReleaseCapture();
|
||||
}
|
||||
|
||||
/* While we were thinking of SetCapture() when designing this API in SDL,
|
||||
we didn't count on the fact that SetCapture() only tracks while the
|
||||
left mouse button is held down! Instead, we listen for raw mouse input
|
||||
and manually query the mouse when it leaves the window. :/ */
|
||||
return ToggleRawInput(window != NULL);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static Uint32
|
||||
@@ -309,6 +357,8 @@ WIN_InitMouse(_THIS)
|
||||
mouse->GetGlobalMouseState = WIN_GetGlobalMouseState;
|
||||
|
||||
SDL_SetDefaultCursor(WIN_CreateDefaultCursor());
|
||||
|
||||
SDL_blank_cursor = WIN_CreateBlankCursor();
|
||||
}
|
||||
|
||||
void
|
||||
@@ -318,6 +368,10 @@ WIN_QuitMouse(_THIS)
|
||||
rawInputEnableCount = 1;
|
||||
ToggleRawInput(SDL_FALSE);
|
||||
}
|
||||
|
||||
if (SDL_blank_cursor) {
|
||||
SDL_FreeCursor(SDL_blank_cursor);
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* SDL_VIDEO_DRIVER_WINDOWS */
|
||||
|
||||
@@ -23,10 +23,12 @@
|
||||
#ifndef SDL_windowsmouse_h_
|
||||
#define SDL_windowsmouse_h_
|
||||
|
||||
extern DWORD SDL_last_warp_time;
|
||||
extern HCURSOR SDL_cursor;
|
||||
|
||||
extern void WIN_InitMouse(_THIS);
|
||||
extern void WIN_QuitMouse(_THIS);
|
||||
extern void WIN_SetCursorPos(int x, int y);
|
||||
|
||||
#endif /* SDL_windowsmouse_h_ */
|
||||
|
||||
|
||||
@@ -165,7 +165,9 @@ WIN_CreateDevice(int devindex)
|
||||
device->SetWindowAlwaysOnTop = WIN_SetWindowAlwaysOnTop;
|
||||
device->SetWindowFullscreen = WIN_SetWindowFullscreen;
|
||||
device->SetWindowGammaRamp = WIN_SetWindowGammaRamp;
|
||||
device->GetWindowICCProfile = WIN_GetWindowICCProfile;
|
||||
device->GetWindowGammaRamp = WIN_GetWindowGammaRamp;
|
||||
device->SetWindowMouseRect = WIN_SetWindowMouseRect;
|
||||
device->SetWindowMouseGrab = WIN_SetWindowMouseGrab;
|
||||
device->SetWindowKeyboardGrab = WIN_SetWindowKeyboardGrab;
|
||||
device->DestroyWindow = WIN_DestroyWindow;
|
||||
|
||||
+85
-29
@@ -186,6 +186,7 @@ SetupWindowData(_THIS, SDL_Window * window, HWND hwnd, HWND parent, SDL_bool cre
|
||||
data->hdc = GetDC(hwnd);
|
||||
data->hinstance = (HINSTANCE) GetWindowLongPtr(hwnd, GWLP_HINSTANCE);
|
||||
data->created = created;
|
||||
data->high_surrogate = 0;
|
||||
data->mouse_button_flags = 0;
|
||||
data->last_pointer_update = (LPARAM)-1;
|
||||
data->videodata = videodata;
|
||||
@@ -280,15 +281,8 @@ SetupWindowData(_THIS, SDL_Window * window, HWND hwnd, HWND parent, SDL_bool cre
|
||||
}
|
||||
if (GetFocus() == hwnd) {
|
||||
window->flags |= SDL_WINDOW_INPUT_FOCUS;
|
||||
SDL_SetKeyboardFocus(data->window);
|
||||
|
||||
if (window->flags & SDL_WINDOW_MOUSE_GRABBED) {
|
||||
RECT rect;
|
||||
GetClientRect(hwnd, &rect);
|
||||
ClientToScreen(hwnd, (LPPOINT) & rect);
|
||||
ClientToScreen(hwnd, (LPPOINT) & rect + 1);
|
||||
ClipCursor(&rect);
|
||||
}
|
||||
SDL_SetKeyboardFocus(window);
|
||||
WIN_UpdateClipCursor(window);
|
||||
}
|
||||
|
||||
/* Enable multi-touch */
|
||||
@@ -561,7 +555,7 @@ WIN_ShowWindow(_THIS, SDL_Window * window)
|
||||
int nCmdShow;
|
||||
|
||||
hwnd = ((SDL_WindowData *)window->driverdata)->hwnd;
|
||||
nCmdShow = SW_SHOW;
|
||||
nCmdShow = SDL_GetHintBoolean(SDL_HINT_WINDOW_NO_ACTIVATION_WHEN_SHOWN, SDL_FALSE) ? SW_SHOWNA : SW_SHOW;
|
||||
style = GetWindowLong(hwnd, GWL_EXSTYLE);
|
||||
if (style & WS_EX_NOACTIVATE) {
|
||||
nCmdShow = SW_SHOWNOACTIVATE;
|
||||
@@ -731,6 +725,32 @@ WIN_SetWindowGammaRamp(_THIS, SDL_Window * window, const Uint16 * ramp)
|
||||
return succeeded ? 0 : -1;
|
||||
}
|
||||
|
||||
void*
|
||||
WIN_GetWindowICCProfile(_THIS, SDL_Window * window, size_t * size)
|
||||
{
|
||||
SDL_VideoDisplay* display = SDL_GetDisplayForWindow(window);
|
||||
SDL_DisplayData* data = (SDL_DisplayData*)display->driverdata;
|
||||
HDC hdc;
|
||||
BOOL succeeded = FALSE;
|
||||
WCHAR filename[MAX_PATH];
|
||||
DWORD fileNameSize = MAX_PATH;
|
||||
void* iccProfileData = NULL;
|
||||
|
||||
hdc = CreateDCW(data->DeviceName, NULL, NULL, NULL);
|
||||
if (hdc) {
|
||||
succeeded = GetICMProfileW(hdc, &fileNameSize, filename);
|
||||
DeleteDC(hdc);
|
||||
}
|
||||
|
||||
if (succeeded) {
|
||||
iccProfileData = SDL_LoadFile(WIN_StringToUTF8(filename), size);
|
||||
if (!iccProfileData)
|
||||
SDL_SetError("Could not open ICC profile");
|
||||
}
|
||||
|
||||
return iccProfileData;
|
||||
}
|
||||
|
||||
int
|
||||
WIN_GetWindowGammaRamp(_THIS, SDL_Window * window, Uint16 * ramp)
|
||||
{
|
||||
@@ -794,6 +814,12 @@ void WIN_UngrabKeyboard(SDL_Window *window)
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
WIN_SetWindowMouseRect(_THIS, SDL_Window * window)
|
||||
{
|
||||
WIN_UpdateClipCursor(window);
|
||||
}
|
||||
|
||||
void
|
||||
WIN_SetWindowMouseGrab(_THIS, SDL_Window * window, SDL_bool grabbed)
|
||||
{
|
||||
@@ -959,18 +985,6 @@ void WIN_OnWindowEnter(_THIS, SDL_Window * window)
|
||||
if (window->flags & SDL_WINDOW_ALWAYS_ON_TOP) {
|
||||
WIN_SetWindowPositionInternal(_this, window, SWP_NOCOPYBITS | SWP_NOSIZE | SWP_NOACTIVATE);
|
||||
}
|
||||
|
||||
#ifdef WM_MOUSELEAVE
|
||||
{
|
||||
TRACKMOUSEEVENT trackMouseEvent;
|
||||
|
||||
trackMouseEvent.cbSize = sizeof(TRACKMOUSEEVENT);
|
||||
trackMouseEvent.dwFlags = TME_LEAVE;
|
||||
trackMouseEvent.hwndTrack = data->hwnd;
|
||||
|
||||
TrackMouseEvent(&trackMouseEvent);
|
||||
}
|
||||
#endif /* WM_MOUSELEAVE */
|
||||
}
|
||||
|
||||
void
|
||||
@@ -990,14 +1004,56 @@ WIN_UpdateClipCursor(SDL_Window *window)
|
||||
return;
|
||||
}
|
||||
|
||||
if ((mouse->relative_mode || (window->flags & SDL_WINDOW_MOUSE_GRABBED)) &&
|
||||
if ((mouse->relative_mode || (window->flags & SDL_WINDOW_MOUSE_GRABBED) ||
|
||||
(window->mouse_rect.w > 0 && window->mouse_rect.h > 0)) &&
|
||||
(window->flags & SDL_WINDOW_INPUT_FOCUS)) {
|
||||
if (GetClientRect(data->hwnd, &rect) && !IsRectEmpty(&rect)) {
|
||||
ClientToScreen(data->hwnd, (LPPOINT) & rect);
|
||||
ClientToScreen(data->hwnd, (LPPOINT) & rect + 1);
|
||||
if (SDL_memcmp(&rect, &clipped_rect, sizeof(rect)) != 0) {
|
||||
if (ClipCursor(&rect)) {
|
||||
data->cursor_clipped_rect = rect;
|
||||
if (mouse->relative_mode && !mouse->relative_mode_warp) {
|
||||
if (GetWindowRect(data->hwnd, &rect)) {
|
||||
LONG cx, cy;
|
||||
|
||||
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;
|
||||
|
||||
if (SDL_memcmp(&rect, &clipped_rect, sizeof(rect)) != 0) {
|
||||
if (ClipCursor(&rect)) {
|
||||
data->cursor_clipped_rect = rect;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (GetClientRect(data->hwnd, &rect)) {
|
||||
ClientToScreen(data->hwnd, (LPPOINT) & rect);
|
||||
ClientToScreen(data->hwnd, (LPPOINT) & rect + 1);
|
||||
if (window->mouse_rect.w > 0 && window->mouse_rect.h > 0) {
|
||||
RECT mouse_rect, intersection;
|
||||
|
||||
mouse_rect.left = rect.left + window->mouse_rect.x;
|
||||
mouse_rect.top = rect.top + window->mouse_rect.y;
|
||||
mouse_rect.right = mouse_rect.left + window->mouse_rect.w - 1;
|
||||
mouse_rect.bottom = mouse_rect.top + window->mouse_rect.h - 1;
|
||||
if (IntersectRect(&intersection, &rect, &mouse_rect)) {
|
||||
SDL_memcpy(&rect, &intersection, sizeof(rect));
|
||||
} else if ((window->flags & SDL_WINDOW_MOUSE_GRABBED) != 0) {
|
||||
/* Mouse rect was invalid, just do the normal grab */
|
||||
} else {
|
||||
SDL_zero(rect);
|
||||
}
|
||||
}
|
||||
if (SDL_memcmp(&rect, &clipped_rect, sizeof(rect)) != 0) {
|
||||
if (!IsRectEmpty(&rect)) {
|
||||
if (ClipCursor(&rect)) {
|
||||
data->cursor_clipped_rect = rect;
|
||||
}
|
||||
} else {
|
||||
ClipCursor(NULL);
|
||||
SDL_zero(data->cursor_clipped_rect);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -41,6 +41,7 @@ typedef struct
|
||||
SDL_bool created;
|
||||
WPARAM mouse_button_flags;
|
||||
LPARAM last_pointer_update;
|
||||
WCHAR high_surrogate;
|
||||
SDL_bool initializing;
|
||||
SDL_bool expected_resize;
|
||||
SDL_bool in_border_change;
|
||||
@@ -51,6 +52,8 @@ typedef struct
|
||||
SDL_bool windowed_mode_was_maximized;
|
||||
SDL_bool in_window_deactivation;
|
||||
RECT cursor_clipped_rect;
|
||||
SDL_Point last_raw_mouse_position;
|
||||
SDL_bool mouse_tracked;
|
||||
struct SDL_VideoData *videodata;
|
||||
#if SDL_VIDEO_OPENGL_EGL
|
||||
EGLSurface egl_surface;
|
||||
@@ -76,7 +79,9 @@ extern void WIN_SetWindowResizable(_THIS, SDL_Window * window, SDL_bool resizabl
|
||||
extern void WIN_SetWindowAlwaysOnTop(_THIS, SDL_Window * window, SDL_bool on_top);
|
||||
extern void WIN_SetWindowFullscreen(_THIS, SDL_Window * window, SDL_VideoDisplay * display, SDL_bool fullscreen);
|
||||
extern int WIN_SetWindowGammaRamp(_THIS, SDL_Window * window, const Uint16 * ramp);
|
||||
extern void* WIN_GetWindowICCProfile(_THIS, SDL_Window * window, size_t * size);
|
||||
extern int WIN_GetWindowGammaRamp(_THIS, SDL_Window * window, Uint16 * ramp);
|
||||
extern void WIN_SetWindowMouseRect(_THIS, SDL_Window * window);
|
||||
extern void WIN_SetWindowMouseGrab(_THIS, SDL_Window * window, SDL_bool grabbed);
|
||||
extern void WIN_SetWindowKeyboardGrab(_THIS, SDL_Window * window, SDL_bool grabbed);
|
||||
extern void WIN_DestroyWindow(_THIS, SDL_Window * window);
|
||||
|
||||
Reference in New Issue
Block a user