mirror of
https://github.com/libretro/RetroArch.git
synced 2026-11-08 08:10:30 -10:00
win32: one window procedure for every video and input driver
gfx/common/win32_common.c exported twelve window procedures: one for each video family - Direct3D, WGL, Vulkan, GDI - times each kind of input driver - DirectInput, raw input, any other. Each video driver chose its three by comparing the input driver's name. Underneath were three procedures that were the same long switch, copied, with a few cases different in each. There is one procedure now, win32_window_proc(). - What it does with a message is decided in one place, gfx/common/win32_msg_route.h: for a message and the kind of input driver in use, the steps to take - an IME step, a key step, the cursor clip, an offer to the input driver, the window's own business, a display change - which the procedure carries out in that order. The three switches are gone; what each did is the route for its kind. - A video family differs from another only in what creating the window sets up, and GDI in painting from the procedure. A video driver says which family its window is with win32_window_proc_setup() before creating it. - The kind of input driver is read from the setting in that one function, at the moment each video driver used to read it. Nine video drivers and contexts lose their comparison of the input driver's name. Behaviour is meant to be unchanged, message for message. The header takes no Windows types, and samples/gfx/win32_msg_route holds it to the three switches, which are written out in the test as they stood, case list for case list and #if for #if: for every message, with and without the hotplug timer's id in wparam, on the desktop and on the Xbox, with and without threads, the route is the steps the old switch took. The message numbers the header spells out are checked against the SDK's when win32_common.c is compiled. One oddity is kept on purpose, so that the comparison is exact: with an input driver, the hotplug timer's id is looked for under the timer message and also under the eight messages the switches happened to list before it. Compiled for Windows with mingw: win32_common.c with and without the two input drivers and with every family, the Vulkan and WGL contexts, and the GDI, Direct3D 8, 9 (HLSL) and 10 drivers. The Direct3D 11 and 12 drivers do not build against this mingw's headers for reasons that have nothing to do with this change, and the Cg driver needs Cg; their edit is the same three lines. Not run on Windows. win32_common.c goes from 2904 lines to 2602.
This commit is contained in:
1 parent
34af7cf2d5
commit
3a45e31811
16 files changed
+952
-691
No files matched your search
@@ -615,6 +615,29 @@ jobs:
|
||||
make clean all SANITIZER=thread
|
||||
TSAN_OPTIONS=halt_on_error=1 timeout 120 ./gfx_widgets_task_gate_test
|
||||
echo "[pass] gfx_widgets_task_gate_test (TSan)"
|
||||
- name: Build and run win32_msg_route_test (ASan + UBSan)
|
||||
shell: bash
|
||||
working-directory: samples/gfx/win32_msg_route
|
||||
run: |
|
||||
set -eu
|
||||
# What the Win32 window procedure does with a message.
|
||||
# gfx/common/win32_common.c had twelve window procedures, one
|
||||
# for each video family times each kind of input driver,
|
||||
# built on three copies of one long switch. They are one
|
||||
# procedure now, which asks win32_msg_route() what to do with
|
||||
# a message. The three switches are written out in the test
|
||||
# as they stood, and for every message - with and without the
|
||||
# hotplug timer's id, on the desktop and on the Xbox, with
|
||||
# and without threads - the route must be the steps the
|
||||
# switch for that kind of input driver took. Raw input's
|
||||
# keys made into keyboard events a second time, which is
|
||||
# what routing them like another driver's would do, is put
|
||||
# back and asserted to be caught.
|
||||
make clean all SANITIZER=address,undefined
|
||||
ASAN_OPTIONS=detect_leaks=1 UBSAN_OPTIONS=print_stacktrace=1:halt_on_error=1 \
|
||||
timeout 120 ./win32_msg_route_test
|
||||
make clean
|
||||
echo "[pass] win32_msg_route_test (ASan)"
|
||||
- name: Build and run display_servers_test (ASan + UBSan)
|
||||
shell: bash
|
||||
working-directory: samples/gfx/display_servers
|
||||
|
||||
+272
-574
@@ -119,6 +119,7 @@ typedef char win32_dwm_timing_info_size_check[
|
||||
#endif
|
||||
|
||||
#include "win32_common.h"
|
||||
#include "win32_msg_route.h"
|
||||
|
||||
|
||||
#ifdef HAVE_GDI
|
||||
@@ -1106,252 +1107,91 @@ static LRESULT CALLBACK wnd_proc_common(
|
||||
return 0;
|
||||
}
|
||||
|
||||
static LRESULT CALLBACK wnd_proc_common_internal(HWND hwnd,
|
||||
UINT message, WPARAM wparam, LPARAM lparam)
|
||||
{
|
||||
LRESULT ret;
|
||||
bool keydown = true;
|
||||
bool quit = false;
|
||||
win32_common_state_t *g_win32 = (win32_common_state_t*)&win32_st;
|
||||
/* The kind of input driver the window's messages are routed for, and
|
||||
* the video family the window belongs to. Both are set by
|
||||
* win32_window_proc_setup() before the window is created. */
|
||||
static enum win32_input_kind win32_wnd_input = WIN32_INPUT_OTHER;
|
||||
static enum win32_window_family win32_wnd_family = WIN32_WINDOW_D3D;
|
||||
|
||||
#ifdef HAVE_TASKBAR
|
||||
if ( !(g_win32_flags & WIN32_CMN_FLAG_TASKBAR_CREATED)
|
||||
&& g_win32->taskbar_message
|
||||
&& message == g_win32->taskbar_message)
|
||||
g_win32_flags |= WIN32_CMN_FLAG_TASKBAR_CREATED;
|
||||
#endif
|
||||
|
||||
switch (message)
|
||||
{
|
||||
case WM_KEYUP: /* Key released */
|
||||
case WM_SYSKEYUP: /* Key released */
|
||||
keydown = false;
|
||||
/* fall-through */
|
||||
case WM_KEYDOWN: /* Key pressed */
|
||||
case WM_SYSKEYDOWN: /* Key pressed */
|
||||
quit = true;
|
||||
{
|
||||
uint16_t mod = 0;
|
||||
unsigned keycode = 0;
|
||||
unsigned keysym = (lparam >> 16) & 0xff;
|
||||
bool extended = (lparam >> 24) & 0x1;
|
||||
|
||||
/* NumLock vs Pause correction */
|
||||
if (keysym == 0x45 && (wparam == VK_NUMLOCK || wparam == VK_PAUSE))
|
||||
extended = !extended;
|
||||
|
||||
/* extended keys will map to dinput if the high bit is set */
|
||||
if (extended)
|
||||
keysym |= 0x80;
|
||||
|
||||
keycode = input_keymaps_translate_keysym_to_rk(keysym);
|
||||
|
||||
mod = win32_update_keyboard_mods();
|
||||
|
||||
input_keyboard_event(keydown, keycode,
|
||||
0, mod, RETRO_DEVICE_KEYBOARD);
|
||||
|
||||
if (message != WM_SYSKEYDOWN)
|
||||
return 0;
|
||||
|
||||
if (
|
||||
wparam == VK_F10
|
||||
|| wparam == VK_MENU
|
||||
|| wparam == VK_RSHIFT
|
||||
)
|
||||
return 0;
|
||||
}
|
||||
break;
|
||||
case WM_MOUSEMOVE:
|
||||
case WM_POINTERDOWN:
|
||||
case WM_POINTERUP:
|
||||
case WM_POINTERUPDATE:
|
||||
case WM_DEVICECHANGE:
|
||||
case WM_MOUSEWHEEL:
|
||||
case WM_MOUSEHWHEEL:
|
||||
case WM_NCLBUTTONDBLCLK:
|
||||
break;
|
||||
case WM_DROPFILES:
|
||||
case WM_SYSCOMMAND:
|
||||
case WM_CHAR:
|
||||
case WM_CLOSE:
|
||||
case WM_DESTROY:
|
||||
case WM_QUIT:
|
||||
case WM_MOVE:
|
||||
case WM_SIZE:
|
||||
#if !defined(_XBOX)
|
||||
case WM_ENTERSIZEMOVE:
|
||||
case WM_EXITSIZEMOVE:
|
||||
case WM_ENTERMENULOOP:
|
||||
case WM_EXITMENULOOP:
|
||||
case WM_TIMER:
|
||||
case WM_POWERBROADCAST:
|
||||
#endif
|
||||
case WM_GETMINMAXINFO:
|
||||
case WM_COMMAND:
|
||||
/* win32_msg_route.h spells out Windows' message numbers so that it can
|
||||
* be built without the SDK. They are the SDK's. */
|
||||
typedef char win32_msg_route_numbers_check[
|
||||
( WIN32_MSG_DESTROY == WM_DESTROY
|
||||
&& WIN32_MSG_MOVE == WM_MOVE
|
||||
&& WIN32_MSG_SIZE == WM_SIZE
|
||||
&& WIN32_MSG_SETFOCUS == WM_SETFOCUS
|
||||
&& WIN32_MSG_KILLFOCUS == WM_KILLFOCUS
|
||||
&& WIN32_MSG_CLOSE == WM_CLOSE
|
||||
&& WIN32_MSG_QUIT == WM_QUIT
|
||||
&& WIN32_MSG_GETMINMAXINFO == WM_GETMINMAXINFO
|
||||
&& WIN32_MSG_DISPLAYCHANGE == WM_DISPLAYCHANGE
|
||||
&& WIN32_MSG_NCLBUTTONDBLCLK == WM_NCLBUTTONDBLCLK
|
||||
&& WIN32_MSG_KEYDOWN == WM_KEYDOWN
|
||||
&& WIN32_MSG_KEYUP == WM_KEYUP
|
||||
&& WIN32_MSG_CHAR == WM_CHAR
|
||||
&& WIN32_MSG_SYSKEYDOWN == WM_SYSKEYDOWN
|
||||
&& WIN32_MSG_SYSKEYUP == WM_SYSKEYUP
|
||||
&& WIN32_MSG_IME_ENDCOMPOSITION == WM_IME_ENDCOMPOSITION
|
||||
&& WIN32_MSG_IME_COMPOSITION == WM_IME_COMPOSITION
|
||||
&& WIN32_MSG_COMMAND == WM_COMMAND
|
||||
&& WIN32_MSG_SYSCOMMAND == WM_SYSCOMMAND
|
||||
&& WIN32_MSG_TIMER == WM_TIMER
|
||||
&& WIN32_MSG_MOUSEMOVE == WM_MOUSEMOVE
|
||||
&& WIN32_MSG_MOUSEWHEEL == WM_MOUSEWHEEL
|
||||
&& WIN32_MSG_MOUSEHWHEEL == WM_MOUSEHWHEEL
|
||||
&& WIN32_MSG_ENTERMENULOOP == WM_ENTERMENULOOP
|
||||
&& WIN32_MSG_EXITMENULOOP == WM_EXITMENULOOP
|
||||
&& WIN32_MSG_POWERBROADCAST == WM_POWERBROADCAST
|
||||
&& WIN32_MSG_DEVICECHANGE == WM_DEVICECHANGE
|
||||
&& WIN32_MSG_ENTERSIZEMOVE == WM_ENTERSIZEMOVE
|
||||
&& WIN32_MSG_EXITSIZEMOVE == WM_EXITSIZEMOVE
|
||||
&& WIN32_MSG_DROPFILES == WM_DROPFILES
|
||||
&& WIN32_MSG_POINTERUPDATE == WM_POINTERUPDATE
|
||||
&& WIN32_MSG_POINTERDOWN == WM_POINTERDOWN
|
||||
&& WIN32_MSG_POINTERUP == WM_POINTERUP
|
||||
#ifdef HAVE_THREADS
|
||||
case WM_BROWSER_OPEN_RESULT:
|
||||
case WM_BROWSER_CANCELLED:
|
||||
#endif
|
||||
ret = wnd_proc_common(&quit, hwnd, message, wparam, lparam);
|
||||
if (quit)
|
||||
return ret;
|
||||
break;
|
||||
case WM_SETFOCUS:
|
||||
#ifdef HAVE_CLIP_WINDOW
|
||||
if (input_state_get_ptr()->flags & INP_FLAG_GRAB_MOUSE_STATE)
|
||||
win32_clip_window(true);
|
||||
#endif
|
||||
break;
|
||||
case WM_KILLFOCUS:
|
||||
#ifdef HAVE_CLIP_WINDOW
|
||||
if (input_state_get_ptr()->flags & INP_FLAG_GRAB_MOUSE_STATE)
|
||||
win32_clip_window(false);
|
||||
#endif
|
||||
break;
|
||||
case WM_DISPLAYCHANGE: /* Fix size after display mode switch when using SR */
|
||||
{
|
||||
HMONITOR mon = MonitorFromWindow(hwnd, MONITOR_DEFAULTTONEAREST);
|
||||
if (mon)
|
||||
win32_resize_after_display_change(hwnd, mon);
|
||||
}
|
||||
video_driver_window_output_changed();
|
||||
break;
|
||||
}
|
||||
|
||||
return DefWindowProc(hwnd, message, wparam, lparam);
|
||||
}
|
||||
|
||||
#ifdef HAVE_WINRAWINPUT
|
||||
static LRESULT CALLBACK wnd_proc_winraw_common_internal(HWND hwnd,
|
||||
UINT message, WPARAM wparam, LPARAM lparam)
|
||||
{
|
||||
LRESULT ret;
|
||||
bool quit = false;
|
||||
win32_common_state_t *g_win32 = (win32_common_state_t*)&win32_st;
|
||||
|
||||
#ifdef HAVE_TASKBAR
|
||||
if ( !(g_win32_flags & WIN32_CMN_FLAG_TASKBAR_CREATED)
|
||||
&& g_win32->taskbar_message
|
||||
&& message == g_win32->taskbar_message)
|
||||
g_win32_flags |= WIN32_CMN_FLAG_TASKBAR_CREATED;
|
||||
#endif
|
||||
|
||||
switch (message)
|
||||
{
|
||||
case WM_KEYUP: /* Key released */
|
||||
case WM_SYSKEYUP: /* Key released */
|
||||
/* fall-through */
|
||||
case WM_KEYDOWN: /* Key pressed */
|
||||
case WM_SYSKEYDOWN: /* Key pressed */
|
||||
quit = true;
|
||||
if (message != WM_SYSKEYDOWN)
|
||||
return 0;
|
||||
|
||||
/* keyboard_event in winraw_callback */
|
||||
|
||||
if (
|
||||
wparam == VK_F10
|
||||
|| wparam == VK_MENU
|
||||
|| wparam == VK_RSHIFT
|
||||
)
|
||||
return 0;
|
||||
break;
|
||||
case WM_MOUSEMOVE:
|
||||
case WM_POINTERDOWN:
|
||||
case WM_POINTERUP:
|
||||
case WM_POINTERUPDATE:
|
||||
case WM_MOUSEWHEEL:
|
||||
case WM_MOUSEHWHEEL:
|
||||
case WM_NCLBUTTONDBLCLK:
|
||||
break;
|
||||
case WM_DROPFILES:
|
||||
case WM_SYSCOMMAND:
|
||||
case WM_CHAR:
|
||||
case WM_CLOSE:
|
||||
case WM_DESTROY:
|
||||
case WM_QUIT:
|
||||
case WM_MOVE:
|
||||
case WM_SIZE:
|
||||
#if !defined(_XBOX)
|
||||
case WM_TIMER:
|
||||
if ( wparam == WIN32_HOTPLUG_TIMER_ID
|
||||
&& winraw_handle_message(message, wparam, lparam))
|
||||
return 0;
|
||||
ret = wnd_proc_common(&quit, hwnd, message, wparam, lparam);
|
||||
if (quit)
|
||||
return ret;
|
||||
break;
|
||||
#endif
|
||||
#if !defined(_XBOX)
|
||||
case WM_ENTERSIZEMOVE:
|
||||
case WM_EXITSIZEMOVE:
|
||||
case WM_ENTERMENULOOP:
|
||||
case WM_EXITMENULOOP:
|
||||
case WM_POWERBROADCAST:
|
||||
#endif
|
||||
case WM_GETMINMAXINFO:
|
||||
case WM_COMMAND:
|
||||
#ifdef HAVE_THREADS
|
||||
case WM_BROWSER_OPEN_RESULT:
|
||||
case WM_BROWSER_CANCELLED:
|
||||
#endif
|
||||
ret = wnd_proc_common(&quit, hwnd, message, wparam, lparam);
|
||||
if (quit)
|
||||
return ret;
|
||||
break;
|
||||
case WM_SETFOCUS:
|
||||
#ifdef HAVE_CLIP_WINDOW
|
||||
if (input_state_get_ptr()->flags & INP_FLAG_GRAB_MOUSE_STATE)
|
||||
win32_clip_window(true);
|
||||
#endif
|
||||
#if !defined(_XBOX)
|
||||
if (winraw_handle_message(message, wparam, lparam))
|
||||
return 0;
|
||||
#endif
|
||||
break;
|
||||
case WM_KILLFOCUS:
|
||||
#ifdef HAVE_CLIP_WINDOW
|
||||
if (input_state_get_ptr()->flags & INP_FLAG_GRAB_MOUSE_STATE)
|
||||
win32_clip_window(false);
|
||||
#endif
|
||||
#if !defined(_XBOX)
|
||||
if (winraw_handle_message(message, wparam, lparam))
|
||||
return 0;
|
||||
#endif
|
||||
break;
|
||||
case WM_DISPLAYCHANGE: /* Fix size after display mode switch when using SR */
|
||||
{
|
||||
HMONITOR mon = MonitorFromWindow(hwnd, MONITOR_DEFAULTTONEAREST);
|
||||
if (mon)
|
||||
win32_resize_after_display_change(hwnd, mon);
|
||||
}
|
||||
video_driver_window_output_changed();
|
||||
break;
|
||||
case WM_DEVICECHANGE:
|
||||
#if !defined(_XBOX)
|
||||
if (winraw_handle_message(message, wparam, lparam))
|
||||
return 0;
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
|
||||
return DefWindowProc(hwnd, message, wparam, lparam);
|
||||
}
|
||||
&& WIN32_MSG_BROWSER_OPEN_RESULT == WM_BROWSER_OPEN_RESULT
|
||||
&& WIN32_MSG_BROWSER_CANCELLED == WM_BROWSER_CANCELLED
|
||||
#endif
|
||||
&& WIN32_MSG_HOTPLUG_TIMER_ID == WIN32_HOTPLUG_TIMER_ID) ? 1 : -1];
|
||||
|
||||
#if defined(_MSC_VER) && !defined(_XBOX)
|
||||
#pragma comment(lib, "Imm32")
|
||||
#endif
|
||||
|
||||
/* Offer a message to the input driver. True if the driver took it. */
|
||||
static bool win32_wnd_input_message(UINT message,
|
||||
WPARAM wparam, LPARAM lparam)
|
||||
{
|
||||
switch (win32_wnd_input)
|
||||
{
|
||||
#ifdef HAVE_DINPUT
|
||||
static LRESULT CALLBACK wnd_proc_common_dinput_internal(HWND hwnd,
|
||||
case WIN32_INPUT_DINPUT:
|
||||
{
|
||||
void *input_data = (void*)(LONG_PTR)GetWindowLongPtr(
|
||||
main_window.hwnd, GWLP_USERDATA);
|
||||
return input_data && dinput_handle_message(input_data,
|
||||
message, wparam, lparam);
|
||||
}
|
||||
#endif
|
||||
#if defined(HAVE_WINRAWINPUT) && !defined(_XBOX)
|
||||
case WIN32_INPUT_WINRAW:
|
||||
return winraw_handle_message(message, wparam, lparam);
|
||||
#endif
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/* The window procedure, past the window's creation. What it does with
|
||||
* a message is win32_msg_route()'s answer for the kind of input driver
|
||||
* in use; the steps are taken here, in order. */
|
||||
static LRESULT win32_wnd_proc_route(HWND hwnd,
|
||||
UINT message, WPARAM wparam, LPARAM lparam)
|
||||
{
|
||||
LRESULT ret;
|
||||
bool keydown = true;
|
||||
bool quit = false;
|
||||
win32_common_state_t *g_win32 = (win32_common_state_t*)&win32_st;
|
||||
unsigned route;
|
||||
|
||||
#ifdef HAVE_TASKBAR
|
||||
if ( !(g_win32_flags & WIN32_CMN_FLAG_TASKBAR_CREATED)
|
||||
@@ -1360,272 +1200,161 @@ static LRESULT CALLBACK wnd_proc_common_dinput_internal(HWND hwnd,
|
||||
g_win32_flags |= WIN32_CMN_FLAG_TASKBAR_CREATED;
|
||||
#endif
|
||||
|
||||
switch (message)
|
||||
route = win32_msg_route(win32_wnd_input,
|
||||
#if defined(_XBOX)
|
||||
false,
|
||||
#else
|
||||
true,
|
||||
#endif
|
||||
#ifdef HAVE_THREADS
|
||||
true,
|
||||
#else
|
||||
false,
|
||||
#endif
|
||||
(unsigned)message, wparam == WIN32_HOTPLUG_TIMER_ID);
|
||||
|
||||
if (!route)
|
||||
return DefWindowProc(hwnd, message, wparam, lparam);
|
||||
|
||||
#ifdef HAVE_DINPUT
|
||||
if (route & WIN32_ROUTE_IME_END)
|
||||
input_keyboard_event(true, 1, 0x80000000, 0, RETRO_DEVICE_KEYBOARD);
|
||||
|
||||
if (route & WIN32_ROUTE_IME_TEXT)
|
||||
{
|
||||
case WM_IME_ENDCOMPOSITION:
|
||||
input_keyboard_event(true, 1, 0x80000000, 0, RETRO_DEVICE_KEYBOARD);
|
||||
break;
|
||||
case WM_IME_COMPOSITION:
|
||||
HIMC hIMC = ImmGetContext(hwnd);
|
||||
/* Process composition and result strings separately;
|
||||
* ImmGetCompositionStringW expects a single flag per call. */
|
||||
unsigned gcs_flags[2] = { GCS_RESULTSTR, GCS_COMPSTR };
|
||||
int f;
|
||||
for (f = 0; f < 2; f++)
|
||||
{
|
||||
unsigned gcs_flag = gcs_flags[f];
|
||||
if (!(lparam & gcs_flag))
|
||||
continue;
|
||||
{
|
||||
HIMC hIMC = ImmGetContext(hwnd);
|
||||
/* Process composition and result strings separately;
|
||||
* ImmGetCompositionStringW expects a single flag per call. */
|
||||
unsigned gcs_flags[2] = { GCS_RESULTSTR, GCS_COMPSTR };
|
||||
int f;
|
||||
for (f = 0; f < 2; f++)
|
||||
int i;
|
||||
/* Request up to 2 wide chars (4 bytes). Return value is in bytes. */
|
||||
wchar_t wstr[3] = {0, 0, 0};
|
||||
LONG byte_len = ImmGetCompositionStringW(
|
||||
hIMC, gcs_flag, wstr, 2 * sizeof(wchar_t));
|
||||
int char_count;
|
||||
|
||||
if (byte_len <= 0 || byte_len > (LONG)(2 * sizeof(wchar_t)))
|
||||
continue;
|
||||
|
||||
char_count = byte_len / (int)sizeof(wchar_t);
|
||||
|
||||
for (i = 0; i < char_count; i++)
|
||||
{
|
||||
unsigned gcs_flag = gcs_flags[f];
|
||||
if (!(lparam & gcs_flag))
|
||||
wchar_t single[2];
|
||||
char *utf8;
|
||||
size_t utf8_len;
|
||||
uint32_t packed = 0;
|
||||
|
||||
single[0] = wstr[i];
|
||||
single[1] = 0;
|
||||
|
||||
utf8 = utf16_to_utf8_string_alloc(single);
|
||||
if (!utf8)
|
||||
continue;
|
||||
|
||||
utf8_len = strlen(utf8);
|
||||
|
||||
/* Pack up to 3 UTF-8 bytes into the low 24 bits and
|
||||
* the composition/result flag into the high byte.
|
||||
* This matches what the receiver expects as a uint32. */
|
||||
if (utf8_len >= 1 && utf8_len <= 3)
|
||||
{
|
||||
int i;
|
||||
/* Request up to 2 wide chars (4 bytes). Return value is in bytes. */
|
||||
wchar_t wstr[3] = {0, 0, 0};
|
||||
LONG byte_len = ImmGetCompositionStringW(
|
||||
hIMC, gcs_flag, wstr, 2 * sizeof(wchar_t));
|
||||
int char_count;
|
||||
|
||||
if (byte_len <= 0 || byte_len > (LONG)(2 * sizeof(wchar_t)))
|
||||
continue;
|
||||
|
||||
char_count = byte_len / (int)sizeof(wchar_t);
|
||||
|
||||
for (i = 0; i < char_count; i++)
|
||||
{
|
||||
wchar_t single[2];
|
||||
char *utf8;
|
||||
size_t utf8_len;
|
||||
uint32_t packed = 0;
|
||||
|
||||
single[0] = wstr[i];
|
||||
single[1] = 0;
|
||||
|
||||
utf8 = utf16_to_utf8_string_alloc(single);
|
||||
if (!utf8)
|
||||
continue;
|
||||
|
||||
utf8_len = strlen(utf8);
|
||||
|
||||
/* Pack up to 3 UTF-8 bytes into the low 24 bits and
|
||||
* the composition/result flag into the high byte.
|
||||
* This matches what the receiver expects as a uint32. */
|
||||
if (utf8_len >= 1 && utf8_len <= 3)
|
||||
{
|
||||
memcpy(&packed, utf8, utf8_len);
|
||||
if (utf8_len >= 2)
|
||||
((unsigned char*)&packed)[3] =
|
||||
(unsigned char)((gcs_flag) | (gcs_flag >> 4));
|
||||
input_keyboard_event(true, 1, (uint32_t)packed, 0,
|
||||
RETRO_DEVICE_KEYBOARD);
|
||||
}
|
||||
free(utf8);
|
||||
}
|
||||
memcpy(&packed, utf8, utf8_len);
|
||||
if (utf8_len >= 2)
|
||||
((unsigned char*)&packed)[3] =
|
||||
(unsigned char)((gcs_flag) | (gcs_flag >> 4));
|
||||
input_keyboard_event(true, 1, (uint32_t)packed, 0,
|
||||
RETRO_DEVICE_KEYBOARD);
|
||||
}
|
||||
free(utf8);
|
||||
}
|
||||
ImmReleaseContext(hwnd, hIMC);
|
||||
return 0;
|
||||
}
|
||||
break;
|
||||
case WM_KEYUP: /* Key released */
|
||||
case WM_SYSKEYUP: /* Key released */
|
||||
keydown = false;
|
||||
/* fall-through */
|
||||
case WM_KEYDOWN: /* Key pressed */
|
||||
case WM_SYSKEYDOWN: /* Key pressed */
|
||||
quit = true;
|
||||
{
|
||||
uint16_t mod = 0;
|
||||
unsigned keycode = 0;
|
||||
unsigned keysym = (lparam >> 16) & 0xff;
|
||||
bool extended = (lparam >> 24) & 0x1;
|
||||
}
|
||||
ImmReleaseContext(hwnd, hIMC);
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* NumLock vs Pause correction */
|
||||
if (keysym == 0x45 && (wparam == VK_NUMLOCK || wparam == VK_PAUSE))
|
||||
extended = !extended;
|
||||
if (route & WIN32_ROUTE_KEY)
|
||||
{
|
||||
if (route & (WIN32_ROUTE_KEY_MODS | WIN32_ROUTE_KEY_EVENT))
|
||||
{
|
||||
bool keydown = !(message == WM_KEYUP || message == WM_SYSKEYUP);
|
||||
unsigned keysym = (lparam >> 16) & 0xff;
|
||||
bool extended = (lparam >> 24) & 0x1;
|
||||
|
||||
/* extended keys will map to dinput if the high bit is set */
|
||||
if (extended)
|
||||
keysym |= 0x80;
|
||||
/* NumLock vs Pause correction */
|
||||
if (keysym == 0x45 && (wparam == VK_NUMLOCK || wparam == VK_PAUSE))
|
||||
extended = !extended;
|
||||
|
||||
/* tell the driver about shift and alt key events */
|
||||
if ( keysym == 0x2A/*DIK_LSHIFT*/
|
||||
/* extended keys will map to dinput if the high bit is set */
|
||||
if (extended)
|
||||
keysym |= 0x80;
|
||||
|
||||
/* tell the driver about shift and alt key events */
|
||||
if ( (route & WIN32_ROUTE_KEY_MODS)
|
||||
&& ( keysym == 0x2A/*DIK_LSHIFT*/
|
||||
|| keysym == 0x36/*DIK_RSHIFT*/
|
||||
|| keysym == 0x38/*DIK_LMENU*/
|
||||
|| keysym == 0xB8/*DIK_RMENU*/)
|
||||
{
|
||||
void* input_data = (void*)(LONG_PTR)GetWindowLongPtr(main_window.hwnd, GWLP_USERDATA);
|
||||
if (input_data && dinput_handle_message(input_data,
|
||||
message, wparam, lparam))
|
||||
return 0; /* key up already handled by the driver */
|
||||
}
|
||||
&& win32_wnd_input_message(message, wparam, lparam))
|
||||
return 0; /* key up already handled by the driver */
|
||||
|
||||
keycode = input_keymaps_translate_keysym_to_rk(keysym);
|
||||
|
||||
mod = win32_update_keyboard_mods();
|
||||
if (route & WIN32_ROUTE_KEY_EVENT)
|
||||
{
|
||||
unsigned keycode = input_keymaps_translate_keysym_to_rk(keysym);
|
||||
uint16_t mod = win32_update_keyboard_mods();
|
||||
|
||||
input_keyboard_event(keydown, keycode,
|
||||
0, mod, RETRO_DEVICE_KEYBOARD);
|
||||
}
|
||||
}
|
||||
|
||||
if (message != WM_SYSKEYDOWN)
|
||||
return 0;
|
||||
if (message != WM_SYSKEYDOWN)
|
||||
return 0;
|
||||
|
||||
if ( wparam == VK_F10
|
||||
|| wparam == VK_MENU
|
||||
|| wparam == VK_RSHIFT)
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (
|
||||
wparam == VK_F10
|
||||
|| wparam == VK_MENU
|
||||
|| wparam == VK_RSHIFT
|
||||
)
|
||||
return 0;
|
||||
}
|
||||
break;
|
||||
case WM_MOUSEMOVE:
|
||||
case WM_POINTERDOWN:
|
||||
case WM_POINTERUP:
|
||||
case WM_POINTERUPDATE:
|
||||
case WM_DEVICECHANGE:
|
||||
case WM_MOUSEWHEEL:
|
||||
case WM_MOUSEHWHEEL:
|
||||
case WM_NCLBUTTONDBLCLK:
|
||||
#if !defined(_XBOX)
|
||||
{
|
||||
void* input_data = (void*)(LONG_PTR)GetWindowLongPtr(main_window.hwnd, GWLP_USERDATA);
|
||||
if (input_data && dinput_handle_message(input_data,
|
||||
message, wparam, lparam))
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
break;
|
||||
case WM_DROPFILES:
|
||||
case WM_SYSCOMMAND:
|
||||
case WM_CHAR:
|
||||
case WM_CLOSE:
|
||||
case WM_DESTROY:
|
||||
case WM_QUIT:
|
||||
case WM_MOVE:
|
||||
case WM_SIZE:
|
||||
#if !defined(_XBOX)
|
||||
case WM_TIMER:
|
||||
if (wparam == WIN32_HOTPLUG_TIMER_ID)
|
||||
{
|
||||
void* input_data = (void*)(LONG_PTR)GetWindowLongPtr(main_window.hwnd, GWLP_USERDATA);
|
||||
if (input_data && dinput_handle_message(input_data,
|
||||
message, wparam, lparam))
|
||||
return 0;
|
||||
}
|
||||
ret = wnd_proc_common(&quit, hwnd, message, wparam, lparam);
|
||||
if (quit)
|
||||
return ret;
|
||||
break;
|
||||
#endif
|
||||
#if !defined(_XBOX)
|
||||
case WM_ENTERSIZEMOVE:
|
||||
case WM_EXITSIZEMOVE:
|
||||
case WM_ENTERMENULOOP:
|
||||
case WM_EXITMENULOOP:
|
||||
case WM_POWERBROADCAST:
|
||||
#endif
|
||||
case WM_GETMINMAXINFO:
|
||||
case WM_COMMAND:
|
||||
#ifdef HAVE_THREADS
|
||||
case WM_BROWSER_OPEN_RESULT:
|
||||
case WM_BROWSER_CANCELLED:
|
||||
#endif
|
||||
ret = wnd_proc_common(&quit, hwnd, message, wparam, lparam);
|
||||
if (quit)
|
||||
return ret;
|
||||
break;
|
||||
case WM_SETFOCUS:
|
||||
#ifdef HAVE_CLIP_WINDOW
|
||||
if (input_state_get_ptr()->flags & INP_FLAG_GRAB_MOUSE_STATE)
|
||||
win32_clip_window(true);
|
||||
if ( (route & (WIN32_ROUTE_CLIP_ON | WIN32_ROUTE_CLIP_OFF))
|
||||
&& (input_state_get_ptr()->flags & INP_FLAG_GRAB_MOUSE_STATE))
|
||||
win32_clip_window((route & WIN32_ROUTE_CLIP_ON) != 0);
|
||||
#endif
|
||||
#if !defined(_XBOX)
|
||||
{
|
||||
void* input_data = (void*)(LONG_PTR)GetWindowLongPtr(main_window.hwnd, GWLP_USERDATA);
|
||||
if (input_data && dinput_handle_message(input_data,
|
||||
message, wparam, lparam))
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
break;
|
||||
case WM_KILLFOCUS:
|
||||
#ifdef HAVE_CLIP_WINDOW
|
||||
if (input_state_get_ptr()->flags & INP_FLAG_GRAB_MOUSE_STATE)
|
||||
win32_clip_window(false);
|
||||
#endif
|
||||
#if !defined(_XBOX)
|
||||
{
|
||||
void* input_data = (void*)(LONG_PTR)GetWindowLongPtr(main_window.hwnd, GWLP_USERDATA);
|
||||
if (input_data && dinput_handle_message(input_data,
|
||||
message, wparam, lparam))
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
break;
|
||||
case WM_DISPLAYCHANGE: /* Fix size after display mode switch when using SR */
|
||||
{
|
||||
HMONITOR mon = MonitorFromWindow(hwnd, MONITOR_DEFAULTTONEAREST);
|
||||
if (mon)
|
||||
win32_resize_after_display_change(hwnd, mon);
|
||||
}
|
||||
video_driver_window_output_changed();
|
||||
break;
|
||||
|
||||
if ( (route & WIN32_ROUTE_INPUT)
|
||||
&& win32_wnd_input_message(message, wparam, lparam))
|
||||
return 0;
|
||||
|
||||
if (route & WIN32_ROUTE_COMMON)
|
||||
{
|
||||
bool quit = false;
|
||||
LRESULT ret = wnd_proc_common(&quit, hwnd, message, wparam, lparam);
|
||||
if (quit)
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (route & WIN32_ROUTE_DISPLAY)
|
||||
{
|
||||
/* Fix size after display mode switch when using SR */
|
||||
HMONITOR mon = MonitorFromWindow(hwnd, MONITOR_DEFAULTTONEAREST);
|
||||
if (mon)
|
||||
win32_resize_after_display_change(hwnd, mon);
|
||||
video_driver_window_output_changed();
|
||||
}
|
||||
|
||||
return DefWindowProc(hwnd, message, wparam, lparam);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(HAVE_D3D) || defined(HAVE_D3D8) || defined(HAVE_D3D9) || defined (HAVE_D3D10) || defined (HAVE_D3D11) || defined (HAVE_D3D12)
|
||||
LRESULT CALLBACK wnd_proc_d3d_common(HWND hwnd, UINT message,
|
||||
WPARAM wparam, LPARAM lparam)
|
||||
{
|
||||
if (message == WM_CREATE)
|
||||
{
|
||||
if (DragAcceptFiles_func)
|
||||
DragAcceptFiles_func(hwnd, true);
|
||||
|
||||
g_win32_flags |= WIN32_CMN_FLAG_INITED;
|
||||
return 0;
|
||||
}
|
||||
|
||||
return wnd_proc_common_internal(hwnd, message, wparam, lparam);
|
||||
}
|
||||
|
||||
#ifdef HAVE_WINRAWINPUT
|
||||
LRESULT CALLBACK wnd_proc_d3d_winraw(HWND hwnd, UINT message,
|
||||
WPARAM wparam, LPARAM lparam)
|
||||
{
|
||||
if (message == WM_CREATE)
|
||||
{
|
||||
if (DragAcceptFiles_func)
|
||||
DragAcceptFiles_func(hwnd, true);
|
||||
|
||||
g_win32_flags |= WIN32_CMN_FLAG_INITED;
|
||||
return 0;
|
||||
}
|
||||
|
||||
return wnd_proc_winraw_common_internal(hwnd, message, wparam, lparam);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_DINPUT
|
||||
LRESULT CALLBACK wnd_proc_d3d_dinput(HWND hwnd, UINT message,
|
||||
WPARAM wparam, LPARAM lparam)
|
||||
{
|
||||
if (message == WM_CREATE)
|
||||
{
|
||||
if (DragAcceptFiles_func)
|
||||
DragAcceptFiles_func(hwnd, true);
|
||||
|
||||
g_win32_flags |= WIN32_CMN_FLAG_INITED;
|
||||
return 0;
|
||||
}
|
||||
|
||||
return wnd_proc_common_dinput_internal(hwnd, message, wparam, lparam);
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
#if defined(HAVE_OPENGL) || defined(HAVE_OPENGL1) || defined(HAVE_OPENGL_CORE)
|
||||
extern void create_gl_context(HWND hwnd, bool *quit);
|
||||
@@ -1661,33 +1390,6 @@ static LRESULT wnd_proc_wgl_wm_create(HWND hwnd)
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef HAVE_DINPUT
|
||||
LRESULT CALLBACK wnd_proc_wgl_dinput(HWND hwnd, UINT message,
|
||||
WPARAM wparam, LPARAM lparam)
|
||||
{
|
||||
if (message == WM_CREATE)
|
||||
return wnd_proc_wgl_wm_create(hwnd);
|
||||
return wnd_proc_common_dinput_internal(hwnd, message, wparam, lparam);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_WINRAWINPUT
|
||||
LRESULT CALLBACK wnd_proc_wgl_winraw(HWND hwnd, UINT message,
|
||||
WPARAM wparam, LPARAM lparam)
|
||||
{
|
||||
if (message == WM_CREATE)
|
||||
return wnd_proc_wgl_wm_create(hwnd);
|
||||
return wnd_proc_winraw_common_internal(hwnd, message, wparam, lparam);
|
||||
}
|
||||
#endif
|
||||
|
||||
LRESULT CALLBACK wnd_proc_wgl_common(HWND hwnd, UINT message,
|
||||
WPARAM wparam, LPARAM lparam)
|
||||
{
|
||||
if (message == WM_CREATE)
|
||||
return wnd_proc_wgl_wm_create(hwnd);
|
||||
return wnd_proc_common_internal(hwnd, message, wparam, lparam);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_VULKAN
|
||||
@@ -1718,33 +1420,6 @@ static LRESULT wnd_proc_wm_vk_create(HWND hwnd)
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef HAVE_DINPUT
|
||||
LRESULT CALLBACK wnd_proc_vk_dinput(HWND hwnd, UINT message,
|
||||
WPARAM wparam, LPARAM lparam)
|
||||
{
|
||||
if (message == WM_CREATE)
|
||||
return wnd_proc_wm_vk_create(hwnd);
|
||||
return wnd_proc_common_dinput_internal(hwnd, message, wparam, lparam);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_WINRAWINPUT
|
||||
LRESULT CALLBACK wnd_proc_vk_winraw(HWND hwnd, UINT message,
|
||||
WPARAM wparam, LPARAM lparam)
|
||||
{
|
||||
if (message == WM_CREATE)
|
||||
return wnd_proc_wm_vk_create(hwnd);
|
||||
return wnd_proc_winraw_common_internal(hwnd, message, wparam, lparam);
|
||||
}
|
||||
#endif
|
||||
|
||||
LRESULT CALLBACK wnd_proc_vk_common(HWND hwnd, UINT message,
|
||||
WPARAM wparam, LPARAM lparam)
|
||||
{
|
||||
if (message == WM_CREATE)
|
||||
return wnd_proc_wm_vk_create(hwnd);
|
||||
return wnd_proc_common_internal(hwnd, message, wparam, lparam);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_GDI
|
||||
@@ -1759,8 +1434,7 @@ static LRESULT wnd_proc_wm_gdi_create(HWND hwnd)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Shared WM_PAINT body for all three GDI window procs (dinput,
|
||||
* winraw, common). Presents gdi->bmp scaled into the
|
||||
/* The WM_PAINT body for a GDI window. Presents gdi->bmp scaled into the
|
||||
* aspect-ratio-aware viewport rect (gdi->vp), filling the area
|
||||
* outside the rect with black to produce letterbox / pillarbox
|
||||
* bars. Reads bmp_dims for the source rect (the DDB's actual
|
||||
@@ -1829,55 +1503,79 @@ static void wnd_proc_gdi_paint(gdi_t *gdi)
|
||||
SelectObject(gdi->memDC, gdi->bmp_old);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
/* The window procedure: one, for every video driver and every input
|
||||
* driver.
|
||||
*
|
||||
* A video family differs from another in what creating the window
|
||||
* sets up - a GL context, a Vulkan surface, a device context - and GDI
|
||||
* also paints from here. Everything else is win32_wnd_proc_route(). */
|
||||
LRESULT CALLBACK win32_window_proc(HWND hwnd, UINT message,
|
||||
WPARAM wparam, LPARAM lparam)
|
||||
{
|
||||
if (message == WM_CREATE)
|
||||
{
|
||||
switch (win32_wnd_family)
|
||||
{
|
||||
#if defined(HAVE_OPENGL) || defined(HAVE_OPENGL1) || defined(HAVE_OPENGL_CORE)
|
||||
case WIN32_WINDOW_WGL:
|
||||
return wnd_proc_wgl_wm_create(hwnd);
|
||||
#endif
|
||||
#ifdef HAVE_VULKAN
|
||||
case WIN32_WINDOW_VULKAN:
|
||||
return wnd_proc_wm_vk_create(hwnd);
|
||||
#endif
|
||||
#ifdef HAVE_GDI
|
||||
case WIN32_WINDOW_GDI:
|
||||
return wnd_proc_wm_gdi_create(hwnd);
|
||||
#endif
|
||||
case WIN32_WINDOW_D3D:
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (DragAcceptFiles_func)
|
||||
DragAcceptFiles_func(hwnd, true);
|
||||
|
||||
g_win32_flags |= WIN32_CMN_FLAG_INITED;
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef HAVE_GDI
|
||||
if (message == WM_PAINT && win32_wnd_family == WIN32_WINDOW_GDI)
|
||||
{
|
||||
gdi_t *gdi = (gdi_t*)video_driver_get_ptr();
|
||||
if (gdi && gdi->memDC)
|
||||
wnd_proc_gdi_paint(gdi);
|
||||
}
|
||||
#endif
|
||||
|
||||
return win32_wnd_proc_route(hwnd, message, wparam, lparam);
|
||||
}
|
||||
|
||||
/* Called by a video driver before it creates its window: which family
|
||||
* the window is, so that its creation sets up the right thing.
|
||||
*
|
||||
* The kind of input driver is read from the setting here, once, the
|
||||
* way each video driver used to read it to choose among its three
|
||||
* procedures. */
|
||||
void win32_window_proc_setup(enum win32_window_family family)
|
||||
{
|
||||
settings_t *settings = config_get_ptr();
|
||||
|
||||
win32_wnd_family = family;
|
||||
win32_wnd_input = WIN32_INPUT_OTHER;
|
||||
#ifdef HAVE_DINPUT
|
||||
LRESULT CALLBACK wnd_proc_gdi_dinput(HWND hwnd, UINT message,
|
||||
WPARAM wparam, LPARAM lparam)
|
||||
{
|
||||
if (message == WM_CREATE)
|
||||
return wnd_proc_wm_gdi_create(hwnd);
|
||||
else if (message == WM_PAINT)
|
||||
{
|
||||
gdi_t *gdi = (gdi_t*)video_driver_get_ptr();
|
||||
if (gdi && gdi->memDC)
|
||||
wnd_proc_gdi_paint(gdi);
|
||||
}
|
||||
|
||||
return wnd_proc_common_dinput_internal(hwnd, message, wparam, lparam);
|
||||
}
|
||||
if (string_is_equal(settings->arrays.input_driver, "dinput"))
|
||||
win32_wnd_input = WIN32_INPUT_DINPUT;
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_WINRAWINPUT
|
||||
LRESULT CALLBACK wnd_proc_gdi_winraw(HWND hwnd, UINT message,
|
||||
WPARAM wparam, LPARAM lparam)
|
||||
{
|
||||
if (message == WM_CREATE)
|
||||
return wnd_proc_wm_gdi_create(hwnd);
|
||||
else if (message == WM_PAINT)
|
||||
{
|
||||
gdi_t *gdi = (gdi_t*)video_driver_get_ptr();
|
||||
if (gdi && gdi->memDC)
|
||||
wnd_proc_gdi_paint(gdi);
|
||||
}
|
||||
|
||||
return wnd_proc_winraw_common_internal(hwnd, message, wparam, lparam);
|
||||
}
|
||||
if (string_is_equal(settings->arrays.input_driver, "raw"))
|
||||
win32_wnd_input = WIN32_INPUT_WINRAW;
|
||||
#endif
|
||||
|
||||
LRESULT CALLBACK wnd_proc_gdi_common(HWND hwnd, UINT message,
|
||||
WPARAM wparam, LPARAM lparam)
|
||||
{
|
||||
if (message == WM_CREATE)
|
||||
return wnd_proc_wm_gdi_create(hwnd);
|
||||
else if (message == WM_PAINT)
|
||||
{
|
||||
gdi_t *gdi = (gdi_t*)video_driver_get_ptr();
|
||||
if (gdi && gdi->memDC)
|
||||
wnd_proc_gdi_paint(gdi);
|
||||
}
|
||||
|
||||
return wnd_proc_common_internal(hwnd, message, wparam, lparam);
|
||||
(void)settings;
|
||||
}
|
||||
#endif
|
||||
|
||||
static bool win32_window_create(void *data, unsigned style,
|
||||
RECT *mon_rect, unsigned width,
|
||||
|
||||
+13
-24
@@ -177,32 +177,21 @@ uint16_t win32_update_keyboard_mods(void);
|
||||
* Safe from any thread. */
|
||||
uint16_t win32_get_keyboard_mods(void);
|
||||
|
||||
#if defined(HAVE_D3D8) || defined(HAVE_D3D9) || defined (HAVE_D3D10) || defined (HAVE_D3D11) || defined (HAVE_D3D12)
|
||||
LRESULT CALLBACK wnd_proc_d3d_dinput(HWND hwnd, UINT message,
|
||||
WPARAM wparam, LPARAM lparam);
|
||||
LRESULT CALLBACK wnd_proc_d3d_winraw(HWND hwnd, UINT message,
|
||||
WPARAM wparam, LPARAM lparam);
|
||||
LRESULT CALLBACK wnd_proc_d3d_common(HWND hwnd, UINT message,
|
||||
WPARAM wparam, LPARAM lparam);
|
||||
#endif
|
||||
/* The video family a window belongs to: what creating it sets up. */
|
||||
enum win32_window_family
|
||||
{
|
||||
WIN32_WINDOW_D3D = 0,
|
||||
WIN32_WINDOW_WGL,
|
||||
WIN32_WINDOW_VULKAN,
|
||||
WIN32_WINDOW_GDI
|
||||
};
|
||||
|
||||
#if defined(HAVE_VULKAN)
|
||||
LRESULT CALLBACK wnd_proc_vk_dinput(HWND hwnd, UINT message,
|
||||
/* The window procedure, for every video driver. A driver registers it
|
||||
* for its window class and says which family the window is before
|
||||
* creating it. */
|
||||
LRESULT CALLBACK win32_window_proc(HWND hwnd, UINT message,
|
||||
WPARAM wparam, LPARAM lparam);
|
||||
LRESULT CALLBACK wnd_proc_vk_winraw(HWND hwnd, UINT message,
|
||||
WPARAM wparam, LPARAM lparam);
|
||||
LRESULT CALLBACK wnd_proc_vk_common(HWND hwnd, UINT message,
|
||||
WPARAM wparam, LPARAM lparam);
|
||||
#endif
|
||||
|
||||
#if defined(HAVE_GDI)
|
||||
LRESULT CALLBACK wnd_proc_gdi_dinput(HWND hwnd, UINT message,
|
||||
WPARAM wparam, LPARAM lparam);
|
||||
LRESULT CALLBACK wnd_proc_gdi_winraw(HWND hwnd, UINT message,
|
||||
WPARAM wparam, LPARAM lparam);
|
||||
LRESULT CALLBACK wnd_proc_gdi_common(HWND hwnd, UINT message,
|
||||
WPARAM wparam, LPARAM lparam);
|
||||
#endif
|
||||
void win32_window_proc_setup(enum win32_window_family family);
|
||||
|
||||
#ifdef _XBOX
|
||||
BOOL IsIconic(HWND hwnd);
|
||||
|
||||
@@ -0,0 +1,220 @@
|
||||
/* RetroArch - A frontend for libretro.
|
||||
*
|
||||
* RetroArch is free software: you can redistribute it and/or modify it under the terms
|
||||
* of the GNU General Public License as published by the Free Software Found-
|
||||
* ation, either version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* RetroArch is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
|
||||
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
||||
* PURPOSE. See the GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with RetroArch.
|
||||
* If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef _WIN32_MSG_ROUTE_H
|
||||
#define _WIN32_MSG_ROUTE_H
|
||||
|
||||
#include <boolean.h>
|
||||
#include <retro_inline.h>
|
||||
|
||||
/* What the Win32 window procedure does with a message.
|
||||
*
|
||||
* There used to be twelve window procedures: one for each video family
|
||||
* (Direct3D, WGL, Vulkan, GDI) times each kind of input driver
|
||||
* (DirectInput, raw input, any other), built on three copies of one
|
||||
* long switch that differed in a few cases each. A video driver chose
|
||||
* its procedure by comparing the input driver's name.
|
||||
*
|
||||
* There is one procedure now, and this says what it does. For a
|
||||
* message and the kind of input driver in use, win32_msg_route()
|
||||
* answers with the steps to take, which the procedure carries out in
|
||||
* a fixed order:
|
||||
*
|
||||
* IME, key, clip, input, common, display - then DefWindowProc.
|
||||
*
|
||||
* Any step may answer the message and end it there, as marked below.
|
||||
* The three switches are gone; what each did is the route for its
|
||||
* kind, and samples/gfx/win32_msg_route holds the routes to the
|
||||
* switches they replace, message by message.
|
||||
*
|
||||
* No Windows types, so that the sample can build it on a host. The
|
||||
* message numbers are Windows' own, spelled out; win32_common.c checks
|
||||
* them against the SDK's at compile time. */
|
||||
|
||||
enum win32_input_kind
|
||||
{
|
||||
WIN32_INPUT_OTHER = 0, /* neither of the two below */
|
||||
WIN32_INPUT_DINPUT, /* the "dinput" input driver */
|
||||
WIN32_INPUT_WINRAW /* the "raw" input driver */
|
||||
};
|
||||
|
||||
/* The steps, in the order they are taken. */
|
||||
|
||||
/* An IME composition ended: a keyboard event says so. */
|
||||
#define WIN32_ROUTE_IME_END (1 << 0)
|
||||
/* IME composition text: a keyboard event per character. Answers 0. */
|
||||
#define WIN32_ROUTE_IME_TEXT (1 << 1)
|
||||
/* A key message. Answers 0 unless it is a system key press other than
|
||||
* F10, Alt and right Shift, which goes on to the default. */
|
||||
#define WIN32_ROUTE_KEY (1 << 2)
|
||||
/* ...whose Shift and Alt keys are offered to the input driver first;
|
||||
* answers 0 if the driver takes one. */
|
||||
#define WIN32_ROUTE_KEY_MODS (1 << 3)
|
||||
/* ...and which is turned into a keyboard event here. (The raw input
|
||||
* driver makes its own from WM_INPUT.) */
|
||||
#define WIN32_ROUTE_KEY_EVENT (1 << 4)
|
||||
/* Focus gained or lost: confine the cursor, or let it go, if the
|
||||
* mouse is grabbed. */
|
||||
#define WIN32_ROUTE_CLIP_ON (1 << 5)
|
||||
#define WIN32_ROUTE_CLIP_OFF (1 << 6)
|
||||
/* Offered to the input driver. Answers 0 if the driver takes it. */
|
||||
#define WIN32_ROUTE_INPUT (1 << 7)
|
||||
/* wnd_proc_common(): the window's own business. Answers with its
|
||||
* result if it says the message is done. */
|
||||
#define WIN32_ROUTE_COMMON (1 << 8)
|
||||
/* The display mode changed. */
|
||||
#define WIN32_ROUTE_DISPLAY (1 << 9)
|
||||
|
||||
/* Windows' message numbers. */
|
||||
#define WIN32_MSG_DESTROY 0x0002
|
||||
#define WIN32_MSG_MOVE 0x0003
|
||||
#define WIN32_MSG_SIZE 0x0005
|
||||
#define WIN32_MSG_SETFOCUS 0x0007
|
||||
#define WIN32_MSG_KILLFOCUS 0x0008
|
||||
#define WIN32_MSG_CLOSE 0x0010
|
||||
#define WIN32_MSG_QUIT 0x0012
|
||||
#define WIN32_MSG_GETMINMAXINFO 0x0024
|
||||
#define WIN32_MSG_DISPLAYCHANGE 0x007E
|
||||
#define WIN32_MSG_NCLBUTTONDBLCLK 0x00A3
|
||||
#define WIN32_MSG_KEYDOWN 0x0100
|
||||
#define WIN32_MSG_KEYUP 0x0101
|
||||
#define WIN32_MSG_CHAR 0x0102
|
||||
#define WIN32_MSG_SYSKEYDOWN 0x0104
|
||||
#define WIN32_MSG_SYSKEYUP 0x0105
|
||||
#define WIN32_MSG_IME_ENDCOMPOSITION 0x010E
|
||||
#define WIN32_MSG_IME_COMPOSITION 0x010F
|
||||
#define WIN32_MSG_COMMAND 0x0111
|
||||
#define WIN32_MSG_SYSCOMMAND 0x0112
|
||||
#define WIN32_MSG_TIMER 0x0113
|
||||
#define WIN32_MSG_MOUSEMOVE 0x0200
|
||||
#define WIN32_MSG_MOUSEWHEEL 0x020A
|
||||
#define WIN32_MSG_MOUSEHWHEEL 0x020E
|
||||
#define WIN32_MSG_ENTERMENULOOP 0x0211
|
||||
#define WIN32_MSG_EXITMENULOOP 0x0212
|
||||
#define WIN32_MSG_POWERBROADCAST 0x0218
|
||||
#define WIN32_MSG_DEVICECHANGE 0x0219
|
||||
#define WIN32_MSG_ENTERSIZEMOVE 0x0231
|
||||
#define WIN32_MSG_EXITSIZEMOVE 0x0232
|
||||
#define WIN32_MSG_DROPFILES 0x0233
|
||||
#define WIN32_MSG_POINTERUPDATE 0x0245
|
||||
#define WIN32_MSG_POINTERDOWN 0x0246
|
||||
#define WIN32_MSG_POINTERUP 0x0247
|
||||
/* WM_USER + 0 and + 1: the file browser thread's answers */
|
||||
#define WIN32_MSG_BROWSER_OPEN_RESULT 0x0400
|
||||
#define WIN32_MSG_BROWSER_CANCELLED 0x0401
|
||||
|
||||
/* The timer that re-checks controllers after a device change; its id
|
||||
* arrives as a timer message's wparam. */
|
||||
#define WIN32_MSG_HOTPLUG_TIMER_ID 0x5242
|
||||
|
||||
/* @desktop is false on the Xbox, where the window has no move or menu
|
||||
* loops, timers or power messages and the input drivers are not
|
||||
* offered anything. @threads says whether the file browser's messages
|
||||
* exist. @wparam_is_hotplug_timer is (wparam == WIN32_MSG_HOTPLUG_TIMER_ID). */
|
||||
static INLINE unsigned win32_msg_route(enum win32_input_kind input,
|
||||
bool desktop, bool threads, unsigned message,
|
||||
bool wparam_is_hotplug_timer)
|
||||
{
|
||||
bool driver = (input != WIN32_INPUT_OTHER);
|
||||
|
||||
switch (message)
|
||||
{
|
||||
case WIN32_MSG_IME_ENDCOMPOSITION:
|
||||
return (input == WIN32_INPUT_DINPUT) ? WIN32_ROUTE_IME_END : 0;
|
||||
case WIN32_MSG_IME_COMPOSITION:
|
||||
return (input == WIN32_INPUT_DINPUT) ? WIN32_ROUTE_IME_TEXT : 0;
|
||||
|
||||
case WIN32_MSG_KEYDOWN:
|
||||
case WIN32_MSG_KEYUP:
|
||||
case WIN32_MSG_SYSKEYDOWN:
|
||||
case WIN32_MSG_SYSKEYUP:
|
||||
switch (input)
|
||||
{
|
||||
case WIN32_INPUT_DINPUT:
|
||||
return WIN32_ROUTE_KEY | WIN32_ROUTE_KEY_MODS
|
||||
| WIN32_ROUTE_KEY_EVENT;
|
||||
case WIN32_INPUT_WINRAW:
|
||||
return WIN32_ROUTE_KEY;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return WIN32_ROUTE_KEY | WIN32_ROUTE_KEY_EVENT;
|
||||
|
||||
/* the mouse and the pen: DirectInput reads them from here */
|
||||
case WIN32_MSG_MOUSEMOVE:
|
||||
case WIN32_MSG_POINTERDOWN:
|
||||
case WIN32_MSG_POINTERUP:
|
||||
case WIN32_MSG_POINTERUPDATE:
|
||||
case WIN32_MSG_MOUSEWHEEL:
|
||||
case WIN32_MSG_MOUSEHWHEEL:
|
||||
case WIN32_MSG_NCLBUTTONDBLCLK:
|
||||
return (desktop && input == WIN32_INPUT_DINPUT)
|
||||
? WIN32_ROUTE_INPUT : 0;
|
||||
|
||||
case WIN32_MSG_DEVICECHANGE:
|
||||
return (desktop && driver) ? WIN32_ROUTE_INPUT : 0;
|
||||
|
||||
/* The window's own business. With an input driver these are
|
||||
* also where the hotplug timer is looked for - under the timer
|
||||
* message, and under the rest of this group by the id alone,
|
||||
* which is how the switches had it. */
|
||||
case WIN32_MSG_DROPFILES:
|
||||
case WIN32_MSG_SYSCOMMAND:
|
||||
case WIN32_MSG_CHAR:
|
||||
case WIN32_MSG_CLOSE:
|
||||
case WIN32_MSG_DESTROY:
|
||||
case WIN32_MSG_QUIT:
|
||||
case WIN32_MSG_MOVE:
|
||||
case WIN32_MSG_SIZE:
|
||||
return WIN32_ROUTE_COMMON
|
||||
| ((desktop && driver && wparam_is_hotplug_timer)
|
||||
? WIN32_ROUTE_INPUT : 0);
|
||||
case WIN32_MSG_TIMER:
|
||||
if (!desktop)
|
||||
return 0;
|
||||
return WIN32_ROUTE_COMMON
|
||||
| ((driver && wparam_is_hotplug_timer) ? WIN32_ROUTE_INPUT : 0);
|
||||
|
||||
case WIN32_MSG_ENTERSIZEMOVE:
|
||||
case WIN32_MSG_EXITSIZEMOVE:
|
||||
case WIN32_MSG_ENTERMENULOOP:
|
||||
case WIN32_MSG_EXITMENULOOP:
|
||||
case WIN32_MSG_POWERBROADCAST:
|
||||
return desktop ? WIN32_ROUTE_COMMON : 0;
|
||||
|
||||
case WIN32_MSG_GETMINMAXINFO:
|
||||
case WIN32_MSG_COMMAND:
|
||||
return WIN32_ROUTE_COMMON;
|
||||
case WIN32_MSG_BROWSER_OPEN_RESULT:
|
||||
case WIN32_MSG_BROWSER_CANCELLED:
|
||||
return threads ? WIN32_ROUTE_COMMON : 0;
|
||||
|
||||
case WIN32_MSG_SETFOCUS:
|
||||
return WIN32_ROUTE_CLIP_ON
|
||||
| ((desktop && driver) ? WIN32_ROUTE_INPUT : 0);
|
||||
case WIN32_MSG_KILLFOCUS:
|
||||
return WIN32_ROUTE_CLIP_OFF
|
||||
| ((desktop && driver) ? WIN32_ROUTE_INPUT : 0);
|
||||
|
||||
case WIN32_MSG_DISPLAYCHANGE:
|
||||
return WIN32_ROUTE_DISPLAY;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif
|
||||
+4
-9
@@ -2270,15 +2270,10 @@ static void *d3d10_gfx_init(const video_info_t* video,
|
||||
#endif
|
||||
#ifdef HAVE_MONITOR
|
||||
win32_monitor_init();
|
||||
wndclass.lpfnWndProc = wnd_proc_d3d_common;
|
||||
#ifdef HAVE_DINPUT
|
||||
if (string_is_equal(settings->arrays.input_driver, "dinput"))
|
||||
wndclass.lpfnWndProc = wnd_proc_d3d_dinput;
|
||||
#endif
|
||||
#ifdef HAVE_WINRAWINPUT
|
||||
if (string_is_equal(settings->arrays.input_driver, "raw"))
|
||||
wndclass.lpfnWndProc = wnd_proc_d3d_winraw;
|
||||
#endif
|
||||
/* one window procedure for every video and input driver; the
|
||||
* family says what creating the window sets up */
|
||||
wndclass.lpfnWndProc = win32_window_proc;
|
||||
win32_window_proc_setup(WIN32_WINDOW_D3D);
|
||||
#ifdef HAVE_WINDOW
|
||||
win32_window_init(&wndclass, true, NULL);
|
||||
#endif
|
||||
|
||||
+4
-9
@@ -3558,15 +3558,10 @@ static void *d3d11_gfx_init(const video_info_t* video,
|
||||
#endif
|
||||
#ifdef HAVE_MONITOR
|
||||
win32_monitor_init();
|
||||
wndclass.lpfnWndProc = wnd_proc_d3d_common;
|
||||
#ifdef HAVE_DINPUT
|
||||
if (string_is_equal(settings->arrays.input_driver, "dinput"))
|
||||
wndclass.lpfnWndProc = wnd_proc_d3d_dinput;
|
||||
#endif
|
||||
#ifdef HAVE_WINRAWINPUT
|
||||
if (string_is_equal(settings->arrays.input_driver, "raw"))
|
||||
wndclass.lpfnWndProc = wnd_proc_d3d_winraw;
|
||||
#endif
|
||||
/* one window procedure for every video and input driver; the
|
||||
* family says what creating the window sets up */
|
||||
wndclass.lpfnWndProc = win32_window_proc;
|
||||
win32_window_proc_setup(WIN32_WINDOW_D3D);
|
||||
#ifdef HAVE_WINDOW
|
||||
win32_window_init(&wndclass, true, NULL);
|
||||
#endif
|
||||
|
||||
+4
-9
@@ -4972,15 +4972,10 @@ static void *d3d12_gfx_init(const video_info_t* video,
|
||||
#endif
|
||||
#ifdef HAVE_MONITOR
|
||||
win32_monitor_init();
|
||||
wndclass.lpfnWndProc = wnd_proc_d3d_common;
|
||||
#ifdef HAVE_DINPUT
|
||||
if (string_is_equal(settings->arrays.input_driver, "dinput"))
|
||||
wndclass.lpfnWndProc = wnd_proc_d3d_dinput;
|
||||
#endif
|
||||
#ifdef HAVE_WINRAWINPUT
|
||||
if (string_is_equal(settings->arrays.input_driver, "raw"))
|
||||
wndclass.lpfnWndProc = wnd_proc_d3d_winraw;
|
||||
#endif
|
||||
/* one window procedure for every video and input driver; the
|
||||
* family says what creating the window sets up */
|
||||
wndclass.lpfnWndProc = win32_window_proc;
|
||||
win32_window_proc_setup(WIN32_WINDOW_D3D);
|
||||
#ifdef HAVE_WINDOW
|
||||
win32_window_init(&wndclass, true, NULL);
|
||||
#endif
|
||||
|
||||
+4
-9
@@ -2405,15 +2405,10 @@ static bool d3d8_init_internal(d3d8_video_t *d3d,
|
||||
|
||||
#ifdef HAVE_WINDOW
|
||||
memset(&d3d->windowClass, 0, sizeof(d3d->windowClass));
|
||||
d3d->windowClass.lpfnWndProc = wnd_proc_d3d_common;
|
||||
#ifdef HAVE_DINPUT
|
||||
if (string_is_equal(settings->arrays.input_driver, "dinput"))
|
||||
d3d->windowClass.lpfnWndProc = wnd_proc_d3d_dinput;
|
||||
#endif
|
||||
#ifdef HAVE_WINRAWINPUT
|
||||
if (string_is_equal(settings->arrays.input_driver, "raw"))
|
||||
d3d->windowClass.lpfnWndProc = wnd_proc_d3d_winraw;
|
||||
#endif
|
||||
/* one window procedure for every video and input driver; the
|
||||
* family says what creating the window sets up */
|
||||
d3d->windowClass.lpfnWndProc = win32_window_proc;
|
||||
win32_window_proc_setup(WIN32_WINDOW_D3D);
|
||||
win32_window_init(&d3d->windowClass, true, NULL);
|
||||
#endif
|
||||
|
||||
|
||||
@@ -3785,15 +3785,10 @@ static bool d3d9_cg_init_internal(d3d9_video_t *d3d,
|
||||
|
||||
#ifdef HAVE_WINDOW
|
||||
memset(&d3d->windowClass, 0, sizeof(d3d->windowClass));
|
||||
d3d->windowClass.lpfnWndProc = wnd_proc_d3d_common;
|
||||
#ifdef HAVE_DINPUT
|
||||
if (string_is_equal(settings->arrays.input_driver, "dinput"))
|
||||
d3d->windowClass.lpfnWndProc = wnd_proc_d3d_dinput;
|
||||
#endif
|
||||
#ifdef HAVE_WINRAWINPUT
|
||||
if (string_is_equal(settings->arrays.input_driver, "raw"))
|
||||
d3d->windowClass.lpfnWndProc = wnd_proc_d3d_winraw;
|
||||
#endif
|
||||
/* one window procedure for every video and input driver; the
|
||||
* family says what creating the window sets up */
|
||||
d3d->windowClass.lpfnWndProc = win32_window_proc;
|
||||
win32_window_proc_setup(WIN32_WINDOW_D3D);
|
||||
win32_window_init(&d3d->windowClass, true, NULL);
|
||||
#endif
|
||||
|
||||
|
||||
@@ -7140,15 +7140,10 @@ static bool d3d9_hlsl_init_internal(d3d9_video_t *d3d,
|
||||
|
||||
#ifdef HAVE_WINDOW
|
||||
memset(&d3d->windowClass, 0, sizeof(d3d->windowClass));
|
||||
d3d->windowClass.lpfnWndProc = wnd_proc_d3d_common;
|
||||
#ifdef HAVE_DINPUT
|
||||
if (string_is_equal(settings->arrays.input_driver, "dinput"))
|
||||
d3d->windowClass.lpfnWndProc = wnd_proc_d3d_dinput;
|
||||
#endif
|
||||
#ifdef HAVE_WINRAWINPUT
|
||||
if (string_is_equal(settings->arrays.input_driver, "raw"))
|
||||
d3d->windowClass.lpfnWndProc = wnd_proc_d3d_winraw;
|
||||
#endif
|
||||
/* one window procedure for every video and input driver; the
|
||||
* family says what creating the window sets up */
|
||||
d3d->windowClass.lpfnWndProc = win32_window_proc;
|
||||
win32_window_proc_setup(WIN32_WINDOW_D3D);
|
||||
win32_window_init(&d3d->windowClass, true, NULL);
|
||||
#endif
|
||||
|
||||
|
||||
@@ -2319,15 +2319,10 @@ static bool gfx_ctx_gdi_init(void)
|
||||
win32_window_reset();
|
||||
win32_monitor_init();
|
||||
|
||||
wndclass.lpfnWndProc = wnd_proc_gdi_common;
|
||||
#ifdef HAVE_DINPUT
|
||||
if (string_is_equal(settings->arrays.input_driver, "dinput"))
|
||||
wndclass.lpfnWndProc = wnd_proc_gdi_dinput;
|
||||
#endif
|
||||
#ifdef HAVE_WINRAWINPUT
|
||||
if (string_is_equal(settings->arrays.input_driver, "raw"))
|
||||
wndclass.lpfnWndProc = wnd_proc_gdi_winraw;
|
||||
#endif
|
||||
/* one window procedure for every video and input driver; the
|
||||
* family says what creating the window sets up */
|
||||
wndclass.lpfnWndProc = win32_window_proc;
|
||||
win32_window_proc_setup(WIN32_WINDOW_GDI);
|
||||
if (!win32_window_init(&wndclass, true, NULL))
|
||||
return false;
|
||||
return true;
|
||||
|
||||
@@ -365,7 +365,7 @@ static void *sdl2_gfx_init(const video_info_t *video,
|
||||
*
|
||||
* Unlike the d3d8 / d3d9 / d3d11 / d3d12 drivers - which create
|
||||
* their main window with a winraw-aware WndProc
|
||||
* (wnd_proc_d3d_winraw, see gfx/common/win32_common.c) - the SDL2
|
||||
* (win32_window_proc, see gfx/common/win32_common.c) - the SDL2
|
||||
* window's WndProc is owned by SDL and we cannot replace it.
|
||||
*
|
||||
* Warn loudly so users hitting silent broken-input understand
|
||||
|
||||
@@ -196,18 +196,10 @@ static void *gfx_ctx_w_vk_init(void *video_driver)
|
||||
win32_window_reset();
|
||||
win32_monitor_init();
|
||||
|
||||
{
|
||||
settings_t *settings = config_get_ptr();
|
||||
wndclass.lpfnWndProc = wnd_proc_vk_common;
|
||||
#ifdef HAVE_DINPUT
|
||||
if (string_is_equal(settings->arrays.input_driver, "dinput"))
|
||||
wndclass.lpfnWndProc = wnd_proc_vk_dinput;
|
||||
#endif
|
||||
#ifdef HAVE_WINRAWINPUT
|
||||
if (string_is_equal(settings->arrays.input_driver, "raw"))
|
||||
wndclass.lpfnWndProc = wnd_proc_vk_winraw;
|
||||
#endif
|
||||
}
|
||||
/* one window procedure for every video and input driver; the
|
||||
* family says what creating the window sets up */
|
||||
wndclass.lpfnWndProc = win32_window_proc;
|
||||
win32_window_proc_setup(WIN32_WINDOW_VULKAN);
|
||||
if (!win32_window_init(&wndclass, true, NULL))
|
||||
goto error;
|
||||
|
||||
|
||||
@@ -135,14 +135,6 @@ WINGDIAPI BOOL WINAPI wglSwapBuffers(HDC);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/* Forward declarations */
|
||||
LRESULT CALLBACK wnd_proc_wgl_common(HWND hwnd, UINT message,
|
||||
WPARAM wparam, LPARAM lparam);
|
||||
LRESULT CALLBACK wnd_proc_wgl_dinput(HWND hwnd, UINT message,
|
||||
WPARAM wparam, LPARAM lparam);
|
||||
LRESULT CALLBACK wnd_proc_wgl_winraw(HWND hwnd, UINT message,
|
||||
WPARAM wparam, LPARAM lparam);
|
||||
|
||||
static BOOL (APIENTRY *p_swap_interval)(int);
|
||||
|
||||
enum wgl_flags
|
||||
@@ -662,15 +654,10 @@ static void *gfx_ctx_wgl_init(void *video_driver)
|
||||
win32_monitor_init();
|
||||
|
||||
|
||||
wndclass.lpfnWndProc = wnd_proc_wgl_common;
|
||||
#ifdef HAVE_DINPUT
|
||||
if (string_is_equal(settings->arrays.input_driver, "dinput"))
|
||||
wndclass.lpfnWndProc = wnd_proc_wgl_dinput;
|
||||
#endif
|
||||
#ifdef HAVE_WINRAWINPUT
|
||||
if (string_is_equal(settings->arrays.input_driver, "raw"))
|
||||
wndclass.lpfnWndProc = wnd_proc_wgl_winraw;
|
||||
#endif
|
||||
/* one window procedure for every video and input driver; the
|
||||
* family says what creating the window sets up */
|
||||
wndclass.lpfnWndProc = win32_window_proc;
|
||||
win32_window_proc_setup(WIN32_WINDOW_WGL);
|
||||
|
||||
if (!win32_window_init(&wndclass, true, NULL))
|
||||
{
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
TARGET := win32_msg_route_test
|
||||
|
||||
LIBRETRO_COMM_DIR := ../../../libretro-common
|
||||
COMMON_DIR := ../../../gfx/common
|
||||
|
||||
# The routing is the window procedure's own (win32_msg_route.h, which
|
||||
# takes no Windows types); the three switches it replaced are written
|
||||
# out in the test, as they stood, to hold it to them.
|
||||
SOURCES := win32_msg_route_test.c
|
||||
|
||||
OBJS := $(SOURCES:.c=.o)
|
||||
|
||||
CFLAGS += -Wall -Wextra -std=c89 -pedantic -g -O1 \
|
||||
-I$(LIBRETRO_COMM_DIR)/include -I$(COMMON_DIR)
|
||||
|
||||
ifneq ($(SANITIZER),)
|
||||
CFLAGS := -fsanitize=$(SANITIZER) -fno-omit-frame-pointer $(CFLAGS)
|
||||
LDFLAGS := -fsanitize=$(SANITIZER) $(LDFLAGS)
|
||||
endif
|
||||
|
||||
all: $(TARGET)
|
||||
|
||||
$(TARGET): $(OBJS)
|
||||
$(CC) -o $@ $(OBJS) $(LDFLAGS)
|
||||
|
||||
win32_msg_route_test.o: $(COMMON_DIR)/win32_msg_route.h
|
||||
|
||||
check: all
|
||||
./$(TARGET)
|
||||
|
||||
clean:
|
||||
rm -f $(OBJS) $(TARGET)
|
||||
|
||||
.PHONY: all check clean
|
||||
@@ -0,0 +1,353 @@
|
||||
/* win32_msg_route_test.c -- what the Win32 window procedure does with
|
||||
* a message, held to the three switches it replaced.
|
||||
*
|
||||
* gfx/common/win32_common.c had three window procedures that were one
|
||||
* long switch each - for the DirectInput driver, the raw input driver,
|
||||
* and any other - and twelve exported ones built on them. They are one
|
||||
* procedure now, which asks win32_msg_route() what to do with a
|
||||
* message.
|
||||
*
|
||||
* The three switches are written out below as they stood, case list
|
||||
* for case list and #if for #if, each returning the steps its case
|
||||
* took. The claim:
|
||||
*
|
||||
* For every message, with and without the hotplug timer's id in
|
||||
* wparam, on the desktop and on the Xbox, with and without threads,
|
||||
* win32_msg_route() gives the steps the old switch for that kind of
|
||||
* input driver took.
|
||||
*
|
||||
* A sabotage mode routes one message the way another kind's switch did
|
||||
* - raw input's keys made into keyboard events here, which would give
|
||||
* every key press twice - and is asserted to be caught. */
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include <boolean.h>
|
||||
|
||||
#include "win32_msg_route.h"
|
||||
|
||||
/* winuser.h, as far as the switches use it */
|
||||
#define WM_DESTROY 0x0002
|
||||
#define WM_MOVE 0x0003
|
||||
#define WM_SIZE 0x0005
|
||||
#define WM_SETFOCUS 0x0007
|
||||
#define WM_KILLFOCUS 0x0008
|
||||
#define WM_CLOSE 0x0010
|
||||
#define WM_QUIT 0x0012
|
||||
#define WM_GETMINMAXINFO 0x0024
|
||||
#define WM_DISPLAYCHANGE 0x007E
|
||||
#define WM_NCLBUTTONDBLCLK 0x00A3
|
||||
#define WM_KEYDOWN 0x0100
|
||||
#define WM_KEYUP 0x0101
|
||||
#define WM_CHAR 0x0102
|
||||
#define WM_SYSKEYDOWN 0x0104
|
||||
#define WM_SYSKEYUP 0x0105
|
||||
#define WM_IME_ENDCOMPOSITION 0x010E
|
||||
#define WM_IME_COMPOSITION 0x010F
|
||||
#define WM_COMMAND 0x0111
|
||||
#define WM_SYSCOMMAND 0x0112
|
||||
#define WM_TIMER 0x0113
|
||||
#define WM_MOUSEMOVE 0x0200
|
||||
#define WM_MOUSEWHEEL 0x020A
|
||||
#define WM_MOUSEHWHEEL 0x020E
|
||||
#define WM_ENTERMENULOOP 0x0211
|
||||
#define WM_EXITMENULOOP 0x0212
|
||||
#define WM_POWERBROADCAST 0x0218
|
||||
#define WM_DEVICECHANGE 0x0219
|
||||
#define WM_ENTERSIZEMOVE 0x0231
|
||||
#define WM_EXITSIZEMOVE 0x0232
|
||||
#define WM_DROPFILES 0x0233
|
||||
#define WM_POINTERUPDATE 0x0245
|
||||
#define WM_POINTERDOWN 0x0246
|
||||
#define WM_POINTERUP 0x0247
|
||||
#define WM_USER 0x0400
|
||||
#define WM_BROWSER_OPEN_RESULT (WM_USER + 0)
|
||||
#define WM_BROWSER_CANCELLED (WM_USER + 1)
|
||||
|
||||
static unsigned failures = 0;
|
||||
static bool quiet = false;
|
||||
|
||||
/* The steps a case took, in the new names. */
|
||||
#define IME_END WIN32_ROUTE_IME_END
|
||||
#define IME_TEXT WIN32_ROUTE_IME_TEXT
|
||||
#define KEY WIN32_ROUTE_KEY
|
||||
#define KEY_MODS WIN32_ROUTE_KEY_MODS
|
||||
#define KEY_EVENT WIN32_ROUTE_KEY_EVENT
|
||||
#define CLIP_ON WIN32_ROUTE_CLIP_ON
|
||||
#define CLIP_OFF WIN32_ROUTE_CLIP_OFF
|
||||
#define INPUT WIN32_ROUTE_INPUT
|
||||
#define COMMON WIN32_ROUTE_COMMON
|
||||
#define DISPLAY WIN32_ROUTE_DISPLAY
|
||||
|
||||
/* wnd_proc_common_internal(), as it stood. `xbox` stands for
|
||||
* defined(_XBOX) and `threads` for defined(HAVE_THREADS). */
|
||||
static unsigned old_common(unsigned message, bool hotplug, bool xbox, bool threads)
|
||||
{
|
||||
(void)hotplug;
|
||||
switch (message)
|
||||
{
|
||||
case WM_KEYUP:
|
||||
case WM_SYSKEYUP:
|
||||
case WM_KEYDOWN:
|
||||
case WM_SYSKEYDOWN:
|
||||
return KEY | KEY_EVENT;
|
||||
case WM_MOUSEMOVE:
|
||||
case WM_POINTERDOWN:
|
||||
case WM_POINTERUP:
|
||||
case WM_POINTERUPDATE:
|
||||
case WM_DEVICECHANGE:
|
||||
case WM_MOUSEWHEEL:
|
||||
case WM_MOUSEHWHEEL:
|
||||
case WM_NCLBUTTONDBLCLK:
|
||||
return 0;
|
||||
case WM_DROPFILES:
|
||||
case WM_SYSCOMMAND:
|
||||
case WM_CHAR:
|
||||
case WM_CLOSE:
|
||||
case WM_DESTROY:
|
||||
case WM_QUIT:
|
||||
case WM_MOVE:
|
||||
case WM_SIZE:
|
||||
return COMMON;
|
||||
/* #if !defined(_XBOX) */
|
||||
case WM_ENTERSIZEMOVE:
|
||||
case WM_EXITSIZEMOVE:
|
||||
case WM_ENTERMENULOOP:
|
||||
case WM_EXITMENULOOP:
|
||||
case WM_TIMER:
|
||||
case WM_POWERBROADCAST:
|
||||
return xbox ? 0 : COMMON;
|
||||
/* #endif */
|
||||
case WM_GETMINMAXINFO:
|
||||
case WM_COMMAND:
|
||||
return COMMON;
|
||||
/* #ifdef HAVE_THREADS */
|
||||
case WM_BROWSER_OPEN_RESULT:
|
||||
case WM_BROWSER_CANCELLED:
|
||||
return threads ? COMMON : 0;
|
||||
/* #endif */
|
||||
case WM_SETFOCUS:
|
||||
return CLIP_ON;
|
||||
case WM_KILLFOCUS:
|
||||
return CLIP_OFF;
|
||||
case WM_DISPLAYCHANGE:
|
||||
return DISPLAY;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* wnd_proc_winraw_common_internal(), as it stood. */
|
||||
static unsigned old_winraw(unsigned message, bool hotplug, bool xbox, bool threads)
|
||||
{
|
||||
switch (message)
|
||||
{
|
||||
case WM_KEYUP:
|
||||
case WM_SYSKEYUP:
|
||||
case WM_KEYDOWN:
|
||||
case WM_SYSKEYDOWN:
|
||||
/* keyboard_event in winraw_callback */
|
||||
return KEY;
|
||||
case WM_MOUSEMOVE:
|
||||
case WM_POINTERDOWN:
|
||||
case WM_POINTERUP:
|
||||
case WM_POINTERUPDATE:
|
||||
case WM_MOUSEWHEEL:
|
||||
case WM_MOUSEHWHEEL:
|
||||
case WM_NCLBUTTONDBLCLK:
|
||||
return 0;
|
||||
case WM_DROPFILES:
|
||||
case WM_SYSCOMMAND:
|
||||
case WM_CHAR:
|
||||
case WM_CLOSE:
|
||||
case WM_DESTROY:
|
||||
case WM_QUIT:
|
||||
case WM_MOVE:
|
||||
case WM_SIZE:
|
||||
/* On the Xbox the timer block below is compiled out and these
|
||||
* fall through to the group that only calls wnd_proc_common. */
|
||||
if (xbox)
|
||||
return COMMON;
|
||||
/* fall-through */
|
||||
case WM_TIMER:
|
||||
if (xbox)
|
||||
return 0; /* not a case there */
|
||||
/* if (wparam == WIN32_HOTPLUG_TIMER_ID
|
||||
* && winraw_handle_message(...)) return 0; */
|
||||
return (hotplug ? INPUT : 0) | COMMON;
|
||||
case WM_ENTERSIZEMOVE:
|
||||
case WM_EXITSIZEMOVE:
|
||||
case WM_ENTERMENULOOP:
|
||||
case WM_EXITMENULOOP:
|
||||
case WM_POWERBROADCAST:
|
||||
return xbox ? 0 : COMMON;
|
||||
case WM_GETMINMAXINFO:
|
||||
case WM_COMMAND:
|
||||
return COMMON;
|
||||
case WM_BROWSER_OPEN_RESULT:
|
||||
case WM_BROWSER_CANCELLED:
|
||||
return threads ? COMMON : 0;
|
||||
case WM_SETFOCUS:
|
||||
return CLIP_ON | (xbox ? 0 : INPUT);
|
||||
case WM_KILLFOCUS:
|
||||
return CLIP_OFF | (xbox ? 0 : INPUT);
|
||||
case WM_DISPLAYCHANGE:
|
||||
return DISPLAY;
|
||||
case WM_DEVICECHANGE:
|
||||
return xbox ? 0 : INPUT;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* wnd_proc_common_dinput_internal(), as it stood. */
|
||||
static unsigned old_dinput(unsigned message, bool hotplug, bool xbox, bool threads)
|
||||
{
|
||||
switch (message)
|
||||
{
|
||||
case WM_IME_ENDCOMPOSITION:
|
||||
return IME_END;
|
||||
case WM_IME_COMPOSITION:
|
||||
return IME_TEXT;
|
||||
case WM_KEYUP:
|
||||
case WM_SYSKEYUP:
|
||||
case WM_KEYDOWN:
|
||||
case WM_SYSKEYDOWN:
|
||||
/* tell the driver about shift and alt key events */
|
||||
return KEY | KEY_MODS | KEY_EVENT;
|
||||
case WM_MOUSEMOVE:
|
||||
case WM_POINTERDOWN:
|
||||
case WM_POINTERUP:
|
||||
case WM_POINTERUPDATE:
|
||||
case WM_DEVICECHANGE:
|
||||
case WM_MOUSEWHEEL:
|
||||
case WM_MOUSEHWHEEL:
|
||||
case WM_NCLBUTTONDBLCLK:
|
||||
return xbox ? 0 : INPUT;
|
||||
case WM_DROPFILES:
|
||||
case WM_SYSCOMMAND:
|
||||
case WM_CHAR:
|
||||
case WM_CLOSE:
|
||||
case WM_DESTROY:
|
||||
case WM_QUIT:
|
||||
case WM_MOVE:
|
||||
case WM_SIZE:
|
||||
if (xbox)
|
||||
return COMMON;
|
||||
/* fall-through */
|
||||
case WM_TIMER:
|
||||
if (xbox)
|
||||
return 0;
|
||||
/* if (wparam == WIN32_HOTPLUG_TIMER_ID) { ...
|
||||
* dinput_handle_message(...) -> return 0 } */
|
||||
return (hotplug ? INPUT : 0) | COMMON;
|
||||
case WM_ENTERSIZEMOVE:
|
||||
case WM_EXITSIZEMOVE:
|
||||
case WM_ENTERMENULOOP:
|
||||
case WM_EXITMENULOOP:
|
||||
case WM_POWERBROADCAST:
|
||||
return xbox ? 0 : COMMON;
|
||||
case WM_GETMINMAXINFO:
|
||||
case WM_COMMAND:
|
||||
return COMMON;
|
||||
case WM_BROWSER_OPEN_RESULT:
|
||||
case WM_BROWSER_CANCELLED:
|
||||
return threads ? COMMON : 0;
|
||||
case WM_SETFOCUS:
|
||||
return CLIP_ON | (xbox ? 0 : INPUT);
|
||||
case WM_KILLFOCUS:
|
||||
return CLIP_OFF | (xbox ? 0 : INPUT);
|
||||
case WM_DISPLAYCHANGE:
|
||||
return DISPLAY;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* raw input's keys routed the way the other switches route theirs */
|
||||
static bool sabotage_winraw_keys = false;
|
||||
|
||||
static unsigned route(enum win32_input_kind kind, bool desktop,
|
||||
bool threads, unsigned message, bool hotplug)
|
||||
{
|
||||
if ( sabotage_winraw_keys
|
||||
&& kind == WIN32_INPUT_WINRAW
|
||||
&& message == WM_KEYDOWN)
|
||||
kind = WIN32_INPUT_OTHER;
|
||||
return win32_msg_route(kind, desktop, threads, message, hotplug);
|
||||
}
|
||||
|
||||
static void lane_all_messages(void)
|
||||
{
|
||||
static const char *const kind_name[3] = { "other", "dinput", "raw" };
|
||||
unsigned kind, xbox, threads, hotplug, message;
|
||||
unsigned long compared = 0, wrong = 0;
|
||||
|
||||
for (kind = 0; kind < 3; kind++)
|
||||
for (xbox = 0; xbox < 2; xbox++)
|
||||
for (threads = 0; threads < 2; threads++)
|
||||
for (hotplug = 0; hotplug < 2; hotplug++)
|
||||
for (message = 0; message <= 0xffff; message++)
|
||||
{
|
||||
unsigned was, is;
|
||||
|
||||
switch (kind)
|
||||
{
|
||||
case WIN32_INPUT_DINPUT:
|
||||
was = old_dinput(message, hotplug != 0, xbox != 0, threads != 0);
|
||||
break;
|
||||
case WIN32_INPUT_WINRAW:
|
||||
was = old_winraw(message, hotplug != 0, xbox != 0, threads != 0);
|
||||
break;
|
||||
default:
|
||||
was = old_common(message, hotplug != 0, xbox != 0, threads != 0);
|
||||
break;
|
||||
}
|
||||
is = route((enum win32_input_kind)kind, !xbox,
|
||||
threads != 0, message, hotplug != 0);
|
||||
compared++;
|
||||
if (was != is)
|
||||
{
|
||||
if (!wrong && !quiet)
|
||||
fprintf(stderr, "FAIL: message 0x%04x, %s input,"
|
||||
" %s%s%s: the switch took steps 0x%03x,"
|
||||
" the route says 0x%03x\n",
|
||||
message, kind_name[kind],
|
||||
xbox ? "Xbox" : "desktop",
|
||||
threads ? ", threads" : "",
|
||||
hotplug ? ", hotplug timer id" : "",
|
||||
was, is);
|
||||
wrong++;
|
||||
}
|
||||
}
|
||||
|
||||
if (wrong)
|
||||
failures += (unsigned)wrong;
|
||||
else if (!quiet)
|
||||
fprintf(stderr, "[pass] %lu message routes are what the three"
|
||||
" switches did\n", compared);
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
lane_all_messages();
|
||||
if (failures)
|
||||
{
|
||||
fprintf(stderr, "FAIL win32_msg_route_test: %u routes differ\n", failures);
|
||||
return 1;
|
||||
}
|
||||
|
||||
quiet = true;
|
||||
sabotage_winraw_keys = true;
|
||||
lane_all_messages();
|
||||
quiet = false;
|
||||
sabotage_winraw_keys = false;
|
||||
|
||||
if (!failures)
|
||||
{
|
||||
fprintf(stderr, "FAIL win32_msg_route_test: raw input's keys made"
|
||||
" into keyboard events a second time went unnoticed\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
fprintf(stderr, "PASS win32_msg_route_test (sabotage caught by %u"
|
||||
" checks)\n", failures);
|
||||
return 0;
|
||||
}
|
||||
Reference in new issue
Block a user