#pragma once #include "rawaccel-io-def.h" #include "rawaccel-version.h" #include "rawaccel-error.hpp" #include "rawaccel.hpp" #include namespace rawaccel { inline void io_control(DWORD code, void* in, DWORD in_size, void* out, DWORD out_size) { HANDLE ra_handle = INVALID_HANDLE_VALUE; ra_handle = CreateFileW(L"\\\\.\\rawaccel", 0, 0, 0, OPEN_EXISTING, 0, 0); if (ra_handle == INVALID_HANDLE_VALUE) { throw install_error(); } DWORD dummy; BOOL success = DeviceIoControl( ra_handle, code, in, in_size, out, out_size, &dummy, // bytes returned NULL // overlapped structure ); CloseHandle(ra_handle); if (!success) { throw sys_error("DeviceIoControl failed"); } } inline std::unique_ptr read() { io_base base_data; io_control(READ, NULL, 0, &base_data, sizeof(io_base)); size_t size = sizeof(base_data); if (base_data.modifier_data_size == 0) { // driver has no data, but it's more useful to return something, // so return a default modifier_settings object along with base data size += sizeof(modifier_settings); base_data.modifier_data_size = 1; auto bytes = std::make_unique(size); *reinterpret_cast(bytes.get()) = base_data; *reinterpret_cast(bytes.get() + sizeof(io_base)) = {}; return bytes; } else { size += sizeof(modifier_settings) * base_data.modifier_data_size; size += sizeof(device_settings) * base_data.device_data_size; auto bytes = std::make_unique(size); io_control(READ, NULL, 0, bytes.get(), DWORD(size)); return bytes; } } // buffer must point to at least sizeof(io_base) bytes inline void write(const void* buffer) { if (buffer == nullptr) throw io_error("write buffer is null"); auto* base_ptr = static_cast(buffer); auto size = sizeof(io_base); size += base_ptr->modifier_data_size * sizeof(modifier_settings); size += base_ptr->device_data_size * sizeof(device_settings); if (size > DWORD(-1)) throw io_error("write buffer is too large"); io_control(WRITE, const_cast(buffer), DWORD(size), NULL, 0); } inline void reset() { io_base base_data{}; // all modifier/device data is cleared when a default io_base is passed io_control(WRITE, &base_data, sizeof(io_base), NULL, 0); } inline version_t get_version() { version_t v; try { io_control(GET_VERSION, NULL, 0, &v, sizeof(version_t)); } catch (const sys_error&) { // assume request is not implemented (< 1.3) v = { 0 }; } return v; } inline version_t valid_version_or_throw() { auto v = get_version(); if (v < min_driver_version) { throw error("reinstallation required"); } if (version < v) { throw error("newer driver is installed"); } return v; } }