RetroArch/deps/switchres/resync_windows.cpp

172 lines
4.9 KiB
C++

/**************************************************************
resync_windows.cpp - Windows device change notifying helper
---------------------------------------------------------
Switchres Modeline generation engine for emulation
License GPL-2.0+
Copyright 2010-2021 Chris Kennedy, Antonio Giner,
Alexandre Wodarczyk, Gil Delescluse
**************************************************************/
#include <functional>
#include "resync_windows.h"
#include "log.h"
GUID GUID_DEVINTERFACE_MONITOR = { 0xe6f07b5f, 0xee97, 0x4a90, 0xb0, 0x76, 0x33, 0xf5, 0x7b, 0xf4, 0xea, 0xa7 };
//============================================================
// resync_handler::resync_handler
//============================================================
resync_handler::resync_handler()
{
m_event = CreateEvent(NULL, FALSE, FALSE, NULL);
CreateThread(NULL, 0, handler_thread, (LPVOID)this, 0, &my_thread);
}
//============================================================
// resync_handler::~resync_handler
//============================================================
resync_handler::~resync_handler()
{
SendMessage(m_hwnd, WM_CLOSE, 0, 0);
if (m_event) CloseHandle(m_event);
}
//============================================================
// resync_handler::handler_thread
//============================================================
DWORD WINAPI resync_handler::handler_thread(LPVOID lpParameter)
{
return ((resync_handler *)lpParameter)->handler_thread_wt();
}
DWORD resync_handler::handler_thread_wt()
{
WNDCLASSEX wc;
MSG msg;
HINSTANCE hinst = GetModuleHandle(NULL);
wc.cbSize = sizeof(wc);
wc.lpfnWndProc = this->resync_wnd_proc;
wc.style = CS_HREDRAW | CS_VREDRAW;
wc.cbWndExtra = 0;
wc.cbClsExtra = 0;
wc.hInstance = hinst;
wc.hbrBackground = 0;
wc.lpszMenuName = NULL;
wc.lpszClassName = "resync_handler";
wc.hIcon = NULL;
wc.hIconSm = wc.hIcon;
wc.hCursor = LoadCursor(NULL, IDC_HAND);
RegisterClassEx(&wc);
m_hwnd = CreateWindowEx(0, "resync_handler", NULL, WS_POPUP, CW_USEDEFAULT, CW_USEDEFAULT, 640, 480, NULL, NULL, hinst, NULL);
SetWindowLongPtr(m_hwnd, GWLP_USERDATA, (LONG_PTR)this);
// Register notifications of display monitor events
DEV_BROADCAST_DEVICEINTERFACE filter;
ZeroMemory(&filter, sizeof(filter));
filter.dbcc_size = sizeof(DEV_BROADCAST_DEVICEINTERFACE);
filter.dbcc_devicetype = DBT_DEVTYP_DEVICEINTERFACE;
filter.dbcc_classguid = GUID_DEVINTERFACE_MONITOR;
HDEVNOTIFY hDeviceNotify = RegisterDeviceNotification(m_hwnd, &filter, DEVICE_NOTIFY_WINDOW_HANDLE);
if (hDeviceNotify == NULL)
log_error("Error registering notification\n");
while (GetMessage(&msg, NULL, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return -1;
}
//============================================================
// resync_handler::wait
//============================================================
void resync_handler::wait()
{
m_is_notified_1 = false;
m_is_notified_2 = false;
auto start = std::chrono::steady_clock::now();
while (!m_is_notified_1 || !m_is_notified_2)
WaitForSingleObject(m_event, 10);
auto end = std::chrono::steady_clock::now();
log_verbose("resync time elapsed %I64d ms\n", std::chrono::duration_cast<std::chrono::milliseconds>(end-start).count());
}
//============================================================
// resync_handler::resync_wnd_proc
//============================================================
LRESULT CALLBACK resync_handler::resync_wnd_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
{
resync_handler *me = reinterpret_cast<resync_handler*>(GetWindowLongPtr(hwnd, GWLP_USERDATA));
if (me) return me->my_wnd_proc(hwnd, msg, wparam, lparam);
return DefWindowProc(hwnd, msg, wparam, lparam);
}
LRESULT CALLBACK resync_handler::my_wnd_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
{
switch (msg)
{
case WM_DEVICECHANGE:
{
switch (wparam)
{
case DBT_DEVICEARRIVAL:
{
log_verbose("Message: DBT_DEVICEARRIVAL\n");
PDEV_BROADCAST_DEVICEINTERFACE db = (PDEV_BROADCAST_DEVICEINTERFACE) lparam;
if (db != nullptr)
{
if (db->dbcc_classguid == GUID_DEVINTERFACE_MONITOR)
{
m_is_notified_1 = true;
SetEvent(m_event);
}
}
break;
}
case DBT_DEVICEREMOVECOMPLETE:
log_verbose("Message: DBT_DEVICEREMOVECOMPLETE\n");
break;
case DBT_DEVNODES_CHANGED:
log_verbose("Message: DBT_DEVNODES_CHANGED\n");
m_is_notified_2 = true;
SetEvent(m_event);
break;
default:
log_verbose("Message: WM_DEVICECHANGE message received, value %x unhandled.\n", (int)wparam);
break;
}
return 0;
}
break;
case WM_CLOSE:
{
PostQuitMessage(0);
return 0;
}
default:
return DefWindowProc(hwnd, msg, wparam, lparam);
}
return 0;
}