mirror of
https://github.com/libretro/RetroArch.git
synced 2024-11-24 08:30:16 +00:00
172 lines
4.9 KiB
C++
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;
|
||
|
}
|