early-access version 2281

This commit is contained in:
pineappleEA
2021-12-07 02:20:09 +01:00
parent c2ae6d480a
commit c4fa174d53
591 changed files with 36978 additions and 18653 deletions
+318 -196
View File
@@ -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, &center_x, &center_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
View File
@@ -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
View File
@@ -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
View File
@@ -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 */
+2
View File
@@ -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_ */
+2
View File
@@ -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
View File
@@ -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);
}
}
}
}
+5
View File
@@ -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);