.. _program_listing_file_include_input_windows_windows_input.cpp: Program Listing for File windows_input.cpp ========================================== |exhale_lsh| :ref:`Return to documentation for file ` (``include/input/windows/windows_input.cpp``) .. |exhale_lsh| unicode:: U+021B0 .. UPWARDS ARROW WITH TIP LEFTWARDS .. code-block:: cpp #include "windows_input.hpp" #include "PDJE_Input.hpp" #include "PDJE_LOG_SETTER.hpp" #include "dev_path_to_name.hpp" #include "windows_keyboard_fill.hpp" #include #include #include #include HWND OS_Input::init() { HINSTANCE hst = GetModuleHandleW(nullptr); WNDCLASSW wc{}; wc.lpfnWndProc = DefWindowProc; wc.hInstance = hst; wc.lpszClassName = Invisible_window_name.c_str(); RegisterClassW(&wc); return CreateWindowExW(0, wc.lpszClassName, L"", 0, 0, 0, 0, 0, HWND_MESSAGE, nullptr, hst, nullptr); } inline std::string wstring_to_utf8_nt(const std::wstring &w) { if (w.empty()) return {}; auto target = w; if (target.rfind(L"\\??\\", 0) == 0) { target.replace(0, 4, L"\\\\?\\"); } int required = WideCharToMultiByte(CP_UTF8, WC_ERR_INVALID_CHARS, target.c_str(), -1, nullptr, 0, nullptr, nullptr); if (required <= 0) { critlog( "pdje input module-Windows impl- WideCharToMultiByte size failed"); throw std::runtime_error("WideCharToMultiByte size failed"); } std::string out(required, '\0'); int written = WideCharToMultiByte(CP_UTF8, WC_ERR_INVALID_CHARS, target.c_str(), -1, out.data(), required, nullptr, nullptr); if (written <= 0) { critlog("pdje input module-Windows impl- WideCharToMultiByte convert " "failed"); throw std::runtime_error("WideCharToMultiByte convert failed"); } if (!out.empty() && out.back() == '\0') out.pop_back(); return out; } void OS_Input::run() { MSG msg; DWORD w; UINT size = 0; uint64_t now; PDJE_Dev_Type dtype; thread_local std::pmr::unsynchronized_pool_resource mono_arena; std::pmr::unsynchronized_pool_resource hid_arena; std::string handlestr; PDJE_Input_Event tempEv; handlestr.reserve(100); PDJE_HID_Event hidEv; std::bitset<101> isPressed; bool Writable = true; while (true) { w = MsgWaitForMultipleObjectsEx(0, nullptr, INFINITE, QS_RAWINPUT | QS_POSTMESSAGE, MWMO_INPUTAVAILABLE | MWMO_ALERTABLE); if (w == WAIT_OBJECT_0) { if (PeekMessageW(&msg, nullptr, WM_QUIT, WM_QUIT, PM_REMOVE)) { break; } while (PeekMessageW(&msg, nullptr, WM_INPUT, WM_INPUT, PM_REMOVE)) { Writable = true; now = timer.Get_MicroSecond(); if (GetRawInputData(reinterpret_cast(msg.lParam), RID_INPUT, nullptr, &size, sizeof(RAWINPUTHEADER)) != 0 || size == 0) { continue; } std::pmr::vector buf(&mono_arena); buf.reserve(size); if (GetRawInputData(reinterpret_cast(msg.lParam), RID_INPUT, buf.data(), &size, sizeof(RAWINPUTHEADER)) != size) { continue; } const RAWINPUT *ri = reinterpret_cast(buf.data()); switch (ri->header.dwType) { case RIM_TYPEMOUSE: dtype = PDJE_Dev_Type::MOUSE; PDJE_RAWINPUT::FillMouseInput(tempEv, ri); break; case RIM_TYPEKEYBOARD: dtype = PDJE_Dev_Type::KEYBOARD; PDJE_RAWINPUT::FillKeyboardInput(tempEv, ri); if (isPressed.test(tempEv.keyboard.k) && tempEv.keyboard.pressed) { Writable = false; } else { isPressed.set(tempEv.keyboard.k, tempEv.keyboard.pressed); } break; case RIM_TYPEHID: dtype = PDJE_Dev_Type::HID; hidEv.hid_buffer = PDJE_RAWINPUT::FillHIDInput( hid_arena, ri, hidEv.hid_byte_size); break; default: dtype = PDJE_Dev_Type::UNKNOWN; break; } handlestr = std::to_string( reinterpret_cast(ri->header.hDevice)); if (!unlisted_targets.empty()) { if (!id_name.contains(handlestr)) { if (GetRawInputDeviceInfoW(ri->header.hDevice, RIDI_DEVICENAME, nullptr, &size) == (UINT)-1 || size == 0) { } else { std::wstring path(size, L'\0'); if (GetRawInputDeviceInfoW(ri->header.hDevice, RIDI_DEVICENAME, path.data(), &size) == (UINT)-1) { } else { if (!path.empty() && path.back() == L'\0') path.pop_back(); std::string device_path = wstring_to_utf8_nt(path); if (unlisted_targets.contains(device_path)) { id_name[handlestr] = unlisted_targets[device_path]; unlisted_targets.erase(device_path); } } } } } if (Writable) { input_buffer.Write({ .type = dtype, .event = tempEv, .hid_event = hidEv, .id = handlestr, .microSecond = now }); } } while (PeekMessageW(&msg, nullptr, 0, WM_QUIT - 1, PM_REMOVE)) { } while ( PeekMessageW(&msg, nullptr, WM_QUIT + 1, 0xFFFF, PM_REMOVE)) { } } } } void OS_Input::work() { auto msgOnly = init(); if (!msgOnly) return; auto device_datas = config_data->get(); config_sync->arrive_and_wait(); if (device_datas.empty()) { return; } std::vector devTypes; bool hasKeyBoard = false; bool hasMouse = false; bool hasHID = false; for (const auto &dev : device_datas) { switch (dev.Type) { case PDJE_Dev_Type::MOUSE: hasMouse = true; break; case PDJE_Dev_Type::KEYBOARD: hasKeyBoard = true; break; case PDJE_Dev_Type::HID: hasHID = true; default: break; } unlisted_targets[dev.device_specific_id] = dev.Name; } if (hasKeyBoard) { auto temp = RAWINPUTDEVICE{ 0x01, 0x06, RIDEV_INPUTSINK | RIDEV_NOLEGACY, msgOnly }; devTypes.push_back(temp); } if (hasMouse) { auto temp = RAWINPUTDEVICE{ 0x01, 0x02, RIDEV_INPUTSINK | RIDEV_NOLEGACY, msgOnly }; devTypes.push_back(temp); } if (hasHID) { auto temp = RAWINPUTDEVICE{ 0x0C, 0x01, RIDEV_INPUTSINK | RIDEV_NOLEGACY, msgOnly }; devTypes.push_back(temp); } auto regres = RegisterRawInputDevices( devTypes.data(), devTypes.size(), sizeof(RAWINPUTDEVICE)); if (!regres) { critlog("failed to register rawinput devices. maybe configed invalid " "devices."); return; } HANDLE task = nullptr; DWORD idx = 0; task = AvSetMmThreadCharacteristicsW(L"Games", &idx); if (task) { AvSetMmThreadPriority(task, AVRT_PRIORITY_HIGH); } // stop power throttling #ifdef THREAD_POWER_THROTTLING_CURRENT_VERSION THREAD_POWER_THROTTLING_STATE s{}; s.Version = THREAD_POWER_THROTTLING_CURRENT_VERSION; s.ControlMask = THREAD_POWER_THROTTLING_EXECUTION_SPEED; s.StateMask = 0; // Disable throttling SetThreadInformation( GetCurrentThread(), ThreadPowerThrottling, &s, sizeof(s)); #endif ThreadID = GetCurrentThreadId(); bool ok = run_ok->get(); run_sync->arrive_and_wait(); if (!ok) { if (task) AvRevertMmThreadCharacteristics(task); return; } run(); if (task) AvRevertMmThreadCharacteristics(task); return; } std::vector OS_Input::getRawDeviceDatas() { UINT num = 0; if (GetRawInputDeviceList(nullptr, &num, sizeof(RAWINPUTDEVICELIST)) != 0 || num == 0) return {}; std::vector list(num); if (GetRawInputDeviceList(list.data(), &num, sizeof(RAWINPUTDEVICELIST)) == (UINT)-1) return {}; std::vector out; out.reserve(num); for (UINT i = 0; i < num; ++i) { RawDeviceData dev; auto h = list[i].hDevice; UINT cbSize = dev.info.cbSize = sizeof(RID_DEVICE_INFO); if (GetRawInputDeviceInfoW(h, RIDI_DEVICEINFO, &dev.info, &cbSize) == (UINT)-1) continue; UINT chars = 0; GetRawInputDeviceInfoW(h, RIDI_DEVICENAME, nullptr, &chars); if (chars > 0) { std::wstring path(chars, L'\0'); if (GetRawInputDeviceInfoW(h, RIDI_DEVICENAME, &path[0], &chars) != (UINT)-1) { if (!path.empty() && path.back() == L'\0') path.pop_back(); } dev.deviceHIDPath = path; } out.push_back(std::move(dev)); } return out; } #include #include std::string OS_Input::hid_label_from_path(const std::wstring &path) { auto name = GetFriendlyNameFromHidPath(path); return wstring_to_utf8_nt(name); } #include std::vector OS_Input::getDevices() { auto devs = getRawDeviceDatas(); std::vector out; out.reserve(devs.size()); for (auto &i : devs) { DeviceData tempdata; switch (i.info.dwType) { case RIM_TYPEMOUSE: tempdata.Type = PDJE_Dev_Type::MOUSE; break; case RIM_TYPEKEYBOARD: tempdata.Type = PDJE_Dev_Type::KEYBOARD; break; case RIM_TYPEHID: tempdata.Type = PDJE_Dev_Type::HID; break; default: tempdata.Type = PDJE_Dev_Type::UNKNOWN; break; } tempdata.Name = hid_label_from_path(i.deviceHIDPath); tempdata.device_specific_id = wstring_to_utf8_nt(i.deviceHIDPath); out.push_back(tempdata); } return out; } bool OS_Input::kill() { return PostThreadMessageW(ThreadID, WM_QUIT, 0, 0); } void OS_Input::TrigLoop() { worker.emplace(std::thread([this]() { this->work(); })); } void OS_Input::ResetLoop() { worker->join(); worker.reset(); } PDJE_INPUT_DATA_LINE OS_Input::PullOutDataLine() { PDJE_INPUT_DATA_LINE dline; dline.input_arena = &input_buffer; dline.id_name_conv = &id_name; return dline; }