misc: various performance clean up (#844)

## Link to GitHub Issue or related Pull Request, if one exists
n/a

## Description of change

- Replace unnecessary precision timers with standard sleeps to reduce
wakeups and background CPU usage.
- Reuse buffers in raw input, touchscreen, and HID output paths to
eliminate steady-state allocations.
- Pre-index HID button groups and correctly process batched HID reports.

No functional changes.

## Testing
This commit is contained in:
bicarus
2026-07-28 21:05:32 -07:00
committed by GitHub
parent 7ccd938f9b
commit 5cabd026ae
10 changed files with 139 additions and 106 deletions
+4 -4
View File
@@ -1,13 +1,14 @@
#include "keypads.h" #include "keypads.h"
#include <chrono>
#include <functional> #include <functional>
#include <thread>
#include <windows.h> #include <windows.h>
#include "avs/game.h" #include "avs/game.h"
#include "external/rapidjson/document.h" #include "external/rapidjson/document.h"
#include "misc/eamuse.h" #include "misc/eamuse.h"
#include "util/precise_timer.h"
using namespace std::placeholders; using namespace std::placeholders;
using namespace rapidjson; using namespace rapidjson;
@@ -59,7 +60,6 @@ namespace api::modules {
// get params // get params
auto keypad = req.params[0].GetUint(); auto keypad = req.params[0].GetUint();
auto input = std::string(req.params[1].GetString()); auto input = std::string(req.params[1].GetString());
timeutils::PreciseSleepTimer timer;
// process all chars // process all chars
for (auto c : input) { for (auto c : input) {
@@ -93,11 +93,11 @@ namespace api::modules {
// set // set
eamuse_set_keypad_overrides(keypad, state); eamuse_set_keypad_overrides(keypad, state);
timer.sleep(sleep_time); std::this_thread::sleep_for(std::chrono::milliseconds(sleep_time));
// unset // unset
eamuse_set_keypad_overrides(keypad, 0); eamuse_set_keypad_overrides(keypad, 0);
timer.sleep(sleep_time); std::this_thread::sleep_for(std::chrono::milliseconds(sleep_time));
} }
} }
+3 -3
View File
@@ -1,11 +1,12 @@
#include "controller.h" #include "controller.h"
#include "serial.h" #include "serial.h"
#include <chrono>
#include <string> #include <string>
#include <thread>
#include <utility> #include <utility>
#include "util/logging.h" #include "util/logging.h"
#include "util/precise_timer.h"
#include "util/utils.h" #include "util/utils.h"
@@ -17,7 +18,6 @@ namespace api {
controller->init_state(this->state); controller->init_state(this->state);
this->thread = new std::thread([this] () { this->thread = new std::thread([this] () {
log_warning("api::serial", "listening on {} (baud: {})", this->port, this->baud); log_warning("api::serial", "listening on {} (baud: {})", this->port, this->baud);
timeutils::PreciseSleepTimer timer;
// read buffer // read buffer
uint8_t read_buffer[16*1024]; uint8_t read_buffer[16*1024];
@@ -162,7 +162,7 @@ namespace api {
// slow down on reconnect // slow down on reconnect
if (this->running) { if (this->running) {
timer.sleep(retry_time); std::this_thread::sleep_for(std::chrono::milliseconds(retry_time));
} }
} }
}); });
+2 -4
View File
@@ -1,5 +1,6 @@
#include "poke.h" #include "poke.h"
#include <chrono>
#include <thread> #include <thread>
#include "windows.h" #include "windows.h"
@@ -11,7 +12,6 @@
#include "touch/native/inject.h" #include "touch/native/inject.h"
#include "touch/touch.h" #include "touch/touch.h"
#include "util/logging.h" #include "util/logging.h"
#include "util/precise_timer.h"
namespace games::iidx::poke { namespace games::iidx::poke {
@@ -125,8 +125,6 @@ namespace games::iidx::poke {
// create new thread // create new thread
THREAD_RUNNING = true; THREAD_RUNNING = true;
THREAD = new std::thread([] { THREAD = new std::thread([] {
timeutils::PreciseSleepTimer timer;
// log // log
log_info("poke", "enabled"); log_info("poke", "enabled");
@@ -198,7 +196,7 @@ namespace games::iidx::poke {
} }
// slow down // slow down
timer.sleep(50); std::this_thread::sleep_for(std::chrono::milliseconds(50));
} }
if (!touch_points.empty()) { if (!touch_points.empty()) {
+2 -4
View File
@@ -1,6 +1,7 @@
#include "poke.h" #include "poke.h"
#include <atomic> #include <atomic>
#include <chrono>
#include <optional> #include <optional>
#include <thread> #include <thread>
@@ -11,7 +12,6 @@
#include "touch/native/inject.h" #include "touch/native/inject.h"
#include "touch/native/nativetouchhook.h" #include "touch/native/nativetouchhook.h"
#include "util/logging.h" #include "util/logging.h"
#include "util/precise_timer.h"
namespace games::nost::poke { namespace games::nost::poke {
@@ -68,8 +68,6 @@ namespace games::nost::poke {
// create new thread // create new thread
THREAD_RUNNING = true; THREAD_RUNNING = true;
THREAD = new std::thread([] { THREAD = new std::thread([] {
timeutils::PreciseSleepTimer timer;
const int swipe_anim_total_frames = 6; const int swipe_anim_total_frames = 6;
const int swipe_anim_y = 300; const int swipe_anim_y = 300;
@@ -194,7 +192,7 @@ namespace games::nost::poke {
} }
// slow down // slow down
timer.sleep(30); std::this_thread::sleep_for(std::chrono::milliseconds(30));
} }
if (contact_active) { if (contact_active) {
@@ -2,10 +2,10 @@
#include <algorithm> #include <algorithm>
#include <chrono> #include <chrono>
#include <thread>
#include "hooks/audio/util.h" #include "hooks/audio/util.h"
#include "util/logging.h" #include "util/logging.h"
#include "util/precise_timer.h"
NullDiscardBackend::~NullDiscardBackend() { NullDiscardBackend::~NullDiscardBackend() {
this->running = false; this->running = false;
@@ -125,8 +125,6 @@ HRESULT NullDiscardBackend::on_release_buffer(uint32_t, DWORD) {
void NullDiscardBackend::pace_loop() { void NullDiscardBackend::pace_loop() {
using namespace std::chrono; using namespace std::chrono;
timeutils::PreciseSleepTimer timer;
// audio is discarded, so timing precision and drift do not matter; just wake the // audio is discarded, so timing precision and drift do not matter; just wake the
// game once per buffer period to keep its render thread from blocking on the event. // game once per buffer period to keep its render thread from blocking on the event.
const auto period = duration_cast<steady_clock::duration>( const auto period = duration_cast<steady_clock::duration>(
@@ -136,6 +134,6 @@ void NullDiscardBackend::pace_loop() {
if (this->relay_handle) { if (this->relay_handle) {
SetEvent(this->relay_handle); SetEvent(this->relay_handle);
} }
timer.sleep(period); std::this_thread::sleep_for(period);
} }
} }
+7 -9
View File
@@ -1,6 +1,7 @@
#include "eamuse.h" #include "eamuse.h"
#include <atomic> #include <atomic>
#include <chrono>
#include <fstream> #include <fstream>
#include <thread> #include <thread>
@@ -10,7 +11,6 @@
#include "rawinput/rawinput.h" #include "rawinput/rawinput.h"
#include "games/sdvx/sdvx.h" #include "games/sdvx/sdvx.h"
#include "util/logging.h" #include "util/logging.h"
#include "util/precise_timer.h"
#include "util/time.h" #include "util/time.h"
#include "util/utils.h" #include "util/utils.h"
#include "overlay/overlay.h" #include "overlay/overlay.h"
@@ -335,7 +335,6 @@ void eamuse_coin_start_thread() {
COIN_INPUT_THREAD = new std::thread([]() { COIN_INPUT_THREAD = new std::thread([]() {
auto overlay_buttons = games::get_buttons_overlay(eamuse_get_game()); auto overlay_buttons = games::get_buttons_overlay(eamuse_get_game());
static bool COIN_INPUT_KEY_STATE = false; static bool COIN_INPUT_KEY_STATE = false;
timeutils::PreciseSleepTimer timer;
while (COIN_INPUT_THREAD_ACTIVE) { while (COIN_INPUT_THREAD_ACTIVE) {
// check input key // check input key
@@ -355,7 +354,7 @@ void eamuse_coin_start_thread() {
} }
// once every two frames // once every two frames
timer.sleep(1000 / 30); std::this_thread::sleep_for(std::chrono::milliseconds(1000 / 30));
} }
}); });
} }
@@ -409,7 +408,6 @@ void eamuse_pin_macro_start_thread() {
size_t pin_index[2] = {PIN_MACRO_VALUES[0].length(), PIN_MACRO_VALUES[1].length()}; size_t pin_index[2] = {PIN_MACRO_VALUES[0].length(), PIN_MACRO_VALUES[1].length()};
std::optional<uint8_t> active_unit = std::nullopt; std::optional<uint8_t> active_unit = std::nullopt;
timeutils::PreciseSleepTimer timer;
while (PIN_MACRO_THREAD_ACTIVE) { while (PIN_MACRO_THREAD_ACTIVE) {
// wait for key press or auto-trigger // wait for key press or auto-trigger
@@ -438,7 +436,7 @@ void eamuse_pin_macro_start_thread() {
} }
if (!active_unit.has_value()) { if (!active_unit.has_value()) {
timer.sleep(20); std::this_thread::sleep_for(std::chrono::milliseconds(20));
continue; continue;
} }
} }
@@ -454,22 +452,22 @@ void eamuse_pin_macro_start_thread() {
eamuse_set_keypad_overrides(unit, keypad_overrides[char_index]); eamuse_set_keypad_overrides(unit, keypad_overrides[char_index]);
} }
pin_index[unit]++; pin_index[unit]++;
timer.sleep(100); std::this_thread::sleep_for(std::chrono::milliseconds(100));
// clear // clear
eamuse_set_keypad_overrides(unit, 0); eamuse_set_keypad_overrides(unit, 0);
timer.sleep(50); std::this_thread::sleep_for(std::chrono::milliseconds(50));
// end of PIN // end of PIN
if (pin_index[unit] == PIN_MACRO_VALUES[unit].length()) { if (pin_index[unit] == PIN_MACRO_VALUES[unit].length()) {
active_unit = std::nullopt; active_unit = std::nullopt;
timer.sleep(120); std::this_thread::sleep_for(std::chrono::milliseconds(120));
} }
continue; continue;
} }
timer.sleep(200); std::this_thread::sleep_for(std::chrono::milliseconds(200));
} }
}); });
} }
+12 -5
View File
@@ -4,7 +4,6 @@
#include <thread> #include <thread>
#include <mutex> #include <mutex>
#include <vector> #include <vector>
#include <map>
#include <windows.h> #include <windows.h>
@@ -103,6 +102,13 @@ namespace rawinput {
std::vector<HIDTouchPoint> touch_points; std::vector<HIDTouchPoint> touch_points;
}; };
struct HIDButtonInputGroup {
USAGE usage_page;
USHORT link_collection;
std::vector<size_t> cap_indices;
std::vector<USAGE> usages;
};
struct DeviceHIDInfo { struct DeviceHIDInfo {
HANDLE handle; HANDLE handle;
_HIDP_CAPS caps; _HIDP_CAPS caps;
@@ -125,11 +131,12 @@ namespace rawinput {
std::vector<std::vector<bool>> button_states; std::vector<std::vector<bool>> button_states;
std::vector<std::vector<double>> button_up, button_down; std::vector<std::vector<double>> button_up, button_down;
std::vector<std::vector<uint8_t>> button_report_states;
std::vector<std::vector<bool>> button_output_states; std::vector<std::vector<bool>> button_output_states;
std::vector<HIDButtonInputGroup> button_input_groups;
// key: usage page, link collection std::vector<CHAR> output_report;
// value: number of buttons for that key (combine ranges and nonranges) std::vector<USAGE> button_output_usages;
std::map<std::pair<USAGE, ULONG>, ULONG> button_usage_pages; std::vector<USAGE> button_output_usages_off;
std::vector<float> value_states; std::vector<float> value_states;
std::vector<LONG> value_states_raw; std::vector<LONG> value_states_raw;
+86 -57
View File
@@ -1,6 +1,10 @@
#include "rawinput.h" #include "rawinput.h"
#include <algorithm>
#include <chrono>
#include <cstdarg> #include <cstdarg>
#include <map>
#include <thread>
#include <utility> #include <utility>
#include <vector> #include <vector>
@@ -9,7 +13,6 @@
#include "util/logging.h" #include "util/logging.h"
#include "external/robin_hood.h" #include "external/robin_hood.h"
#include "util/precise_timer.h"
#include "util/time.h" #include "util/time.h"
#include "util/utils.h" #include "util/utils.h"
@@ -169,9 +172,8 @@ void rawinput::RawInputManager::input_hwnd_create() {
}); });
// wait for window creation being done // wait for window creation being done
timeutils::PreciseSleepTimer timer;
while (!this->input_hwnd) { while (!this->input_hwnd) {
timer.sleep(1); std::this_thread::sleep_for(std::chrono::milliseconds(1));
} }
} }
@@ -439,7 +441,9 @@ void rawinput::RawInputManager::devices_scan_rawinput(RAWINPUTDEVICELIST *device
std::vector<std::string> button_caps_names; std::vector<std::string> button_caps_names;
std::vector<std::vector<bool>> button_states; std::vector<std::vector<bool>> button_states;
std::vector<std::vector<double>> button_up, button_down; std::vector<std::vector<double>> button_up, button_down;
std::map<std::pair<USAGE, ULONG>, ULONG> button_usage_pages; std::vector<std::vector<uint8_t>> button_report_states;
std::vector<HIDButtonInputGroup> button_input_groups;
std::map<std::pair<USAGE, ULONG>, size_t> button_input_group_indices;
for (int button_cap_num = 0; button_cap_num < button_cap_length; button_cap_num++) { for (int button_cap_num = 0; button_cap_num < button_cap_length; button_cap_num++) {
auto &button_caps = button_cap_data[button_cap_num]; auto &button_caps = button_cap_data[button_cap_num];
@@ -458,7 +462,7 @@ void rawinput::RawInputManager::devices_scan_rawinput(RAWINPUTDEVICELIST *device
int button_count = button_caps.Range.UsageMax - button_caps.Range.UsageMin + 1; int button_count = button_caps.Range.UsageMax - button_caps.Range.UsageMin + 1;
// ignore bad ranges reported by bad devices // ignore bad ranges reported by bad devices
if (button_count >= 0xffff) { if (button_count <= 0 || button_count >= 0xffff) {
log_warning("rawinput", "skipping bad button cap range for device {}, range [{}, {}]", log_warning("rawinput", "skipping bad button cap range for device {}, range [{}, {}]",
device_name, device_name,
button_caps.Range.UsageMin, button_caps.Range.UsageMin,
@@ -467,11 +471,30 @@ void rawinput::RawInputManager::devices_scan_rawinput(RAWINPUTDEVICELIST *device
} }
// fill vectors // fill vectors
const size_t cap_index = button_caps_list.size();
button_caps_list.emplace_back(button_caps); button_caps_list.emplace_back(button_caps);
button_states.emplace_back(std::vector<bool>(static_cast<unsigned int>(button_count), false)); button_states.emplace_back(std::vector<bool>(static_cast<unsigned int>(button_count), false));
button_up.emplace_back(std::vector<double>(static_cast<unsigned int>(button_count), 0.0)); button_up.emplace_back(std::vector<double>(static_cast<unsigned int>(button_count), 0.0));
button_down.emplace_back(std::vector<double>(static_cast<unsigned int>(button_count), 0.0)); button_down.emplace_back(std::vector<double>(static_cast<unsigned int>(button_count), 0.0));
button_usage_pages[std::make_pair(button_caps.UsagePage, button_caps.LinkCollection)] += button_count; button_report_states.emplace_back(static_cast<size_t>(button_count), 0);
const auto group_key = std::make_pair(
button_caps.UsagePage,
static_cast<ULONG>(button_caps.LinkCollection));
auto [group_it, inserted] = button_input_group_indices.try_emplace(
group_key,
button_input_groups.size());
if (inserted) {
button_input_groups.emplace_back(HIDButtonInputGroup {
.usage_page = button_caps.UsagePage,
.link_collection = button_caps.LinkCollection,
.cap_indices = {},
.usages = {},
});
}
auto &input_group = button_input_groups[group_it->second];
input_group.cap_indices.push_back(cap_index);
input_group.usages.resize(input_group.usages.size() + button_count);
// names // names
for (USAGE usg = button_caps.Range.UsageMin; usg <= button_caps.Range.UsageMax; usg++) { for (USAGE usg = button_caps.Range.UsageMin; usg <= button_caps.Range.UsageMax; usg++) {
@@ -512,7 +535,7 @@ void rawinput::RawInputManager::devices_scan_rawinput(RAWINPUTDEVICELIST *device
int button_count = button_caps.Range.UsageMax - button_caps.Range.UsageMin + 1; int button_count = button_caps.Range.UsageMax - button_caps.Range.UsageMin + 1;
// ignore bad ranges reported by bad devices // ignore bad ranges reported by bad devices
if (button_count >= 0xffff) { if (button_count <= 0 || button_count >= 0xffff) {
log_warning("rawinput", "skipping bad button output cap range for device {}, range [{}, {}]", log_warning("rawinput", "skipping bad button output cap range for device {}, range [{}, {}]",
device_name, device_name,
button_caps.Range.UsageMin, button_caps.Range.UsageMin,
@@ -800,8 +823,18 @@ void rawinput::RawInputManager::devices_scan_rawinput(RAWINPUTDEVICELIST *device
new_device.hidInfo->button_states = std::move(button_states); new_device.hidInfo->button_states = std::move(button_states);
new_device.hidInfo->button_up = std::move(button_up); new_device.hidInfo->button_up = std::move(button_up);
new_device.hidInfo->button_down = std::move(button_down); new_device.hidInfo->button_down = std::move(button_down);
new_device.hidInfo->button_report_states = std::move(button_report_states);
new_device.hidInfo->button_output_states = std::move(button_output_states); new_device.hidInfo->button_output_states = std::move(button_output_states);
new_device.hidInfo->button_usage_pages = std::move(button_usage_pages); new_device.hidInfo->button_input_groups = std::move(button_input_groups);
new_device.hidInfo->output_report.resize(caps.OutputReportByteLength);
size_t max_button_output_count = 0;
for (const auto &button_output_state : new_device.hidInfo->button_output_states) {
if (button_output_state.size() > max_button_output_count) {
max_button_output_count = button_output_state.size();
}
}
new_device.hidInfo->button_output_usages.reserve(max_button_output_count);
new_device.hidInfo->button_output_usages_off.reserve(max_button_output_count);
new_device.hidInfo->value_states = std::move(value_states); new_device.hidInfo->value_states = std::move(value_states);
new_device.hidInfo->value_states_raw = std::move(value_states_raw); new_device.hidInfo->value_states_raw = std::move(value_states_raw);
new_device.hidInfo->value_output_states = std::move(value_output_states); new_device.hidInfo->value_output_states = std::move(value_output_states);
@@ -1573,11 +1606,17 @@ LRESULT CALLBACK rawinput::RawInputManager::input_wnd_proc(
if (!data_size) { if (!data_size) {
break; break;
} }
std::shared_ptr<RAWINPUT> data((RAWINPUT *) new char[data_size]{}); thread_local std::vector<RAWINPUT> data_buffer;
const size_t data_count =
(data_size + sizeof(RAWINPUT) - 1) / sizeof(RAWINPUT);
if (data_buffer.size() < data_count) {
data_buffer.resize(data_count);
}
auto data = data_buffer.data();
if (GetRawInputData( if (GetRawInputData(
(HRAWINPUT) lParam, (HRAWINPUT) lParam,
RID_INPUT, RID_INPUT,
data.get(), data,
&data_size, &data_size,
sizeof(RAWINPUTHEADER)) != data_size) { sizeof(RAWINPUTHEADER)) != data_size) {
break; break;
@@ -1791,17 +1830,13 @@ LRESULT CALLBACK rawinput::RawInputManager::input_wnd_proc(
+ (size_t) hid_report_index * data_hid.dwSizeHid; + (size_t) hid_report_index * data_hid.dwSizeHid;
// parse reports // parse reports
for (const auto &pair : device.hidInfo->button_usage_pages) { for (auto &input_group : device.hidInfo->button_input_groups) {
const auto usage_page = pair.first.first; auto &usages = input_group.usages;
const auto link_collection = pair.first.second; ULONG usages_length = static_cast<ULONG>(usages.size());
const auto button_count = pair.second;
ULONG usages_length = button_count;
std::vector<USAGE> usages(static_cast<size_t>(usages_length));
if (HidP_GetUsages( if (HidP_GetUsages(
HidP_Input, HidP_Input,
usage_page, input_group.usage_page,
link_collection, input_group.link_collection,
usages.data(), usages.data(),
&usages_length, &usages_length,
reinterpret_cast<PHIDP_PREPARSED_DATA>(device.hidInfo->preparsed_data.get()), reinterpret_cast<PHIDP_PREPARSED_DATA>(device.hidInfo->preparsed_data.get()),
@@ -1819,29 +1854,22 @@ LRESULT CALLBACK rawinput::RawInputManager::input_wnd_proc(
// log_info( // log_info(
// "rawinput", // "rawinput",
// "processing HID input for device {}, usage page {:x} and link collection {:x} with {} buttons, got {} reports", // "processing HID input for device {}, usage page {:x} and link collection {:x} with {} buttons, got {} reports",
// device.desc, // device.desc, input_group.usage_page,
// usage_page, link_collection, button_count, usages_length); // input_group.link_collection, usages.size(), usages_length);
// buttons // buttons
for (size_t cap_num = 0; cap_num < device.hidInfo->button_caps_list.size(); cap_num++) { for (const size_t cap_num : input_group.cap_indices) {
auto &button_caps = device.hidInfo->button_caps_list[cap_num]; auto &button_caps = device.hidInfo->button_caps_list[cap_num];
auto &button_states = device.hidInfo->button_states[cap_num]; auto &button_states = device.hidInfo->button_states[cap_num];
auto &button_down = device.hidInfo->button_down[cap_num]; auto &button_down = device.hidInfo->button_down[cap_num];
auto &button_up = device.hidInfo->button_up[cap_num]; auto &button_up = device.hidInfo->button_up[cap_num];
auto &new_states = device.hidInfo->button_report_states[cap_num];
// is this the right usage page and link collection?
if (button_caps.UsagePage != usage_page || button_caps.LinkCollection != link_collection) {
continue;
}
// get button count // get button count
int button_count = button_caps.Range.UsageMax - button_caps.Range.UsageMin + 1; int button_count = button_caps.Range.UsageMax - button_caps.Range.UsageMin + 1;
if (button_count <= 0) {
continue;
}
// update buttons // update buttons
std::vector<bool> new_states(button_count); std::fill(new_states.begin(), new_states.end(), 0);
for (ULONG usage_num = 0; usage_num < usages_length; usage_num++) { for (ULONG usage_num = 0; usage_num < usages_length; usage_num++) {
if (usages[usage_num] < button_caps.Range.UsageMin || if (usages[usage_num] < button_caps.Range.UsageMin ||
usages[usage_num] > button_caps.Range.UsageMax) { usages[usage_num] > button_caps.Range.UsageMax) {
@@ -1852,17 +1880,18 @@ LRESULT CALLBACK rawinput::RawInputManager::input_wnd_proc(
// guard against some buggy device sending an event for a usage below UsageMin // guard against some buggy device sending an event for a usage below UsageMin
if (usage < button_count) { if (usage < button_count) {
new_states[usage] = true; new_states[usage] = 1;
} }
} }
for (int button_num = 0; button_num < button_count; button_num++) { for (int button_num = 0; button_num < button_count; button_num++) {
if (!new_states[button_num] && button_states[button_num]) { const bool new_state = new_states[button_num] != 0;
if (!new_state && button_states[button_num]) {
device.updated = true; device.updated = true;
button_states[button_num] = new_states[button_num]; button_states[button_num] = new_state;
button_down[button_num] = input_time; button_down[button_num] = input_time;
} else if (new_states[button_num] && !button_states[button_num]) { } else if (new_state && !button_states[button_num]) {
device.updated = true; device.updated = true;
button_states[button_num] = new_states[button_num]; button_states[button_num] = new_state;
button_up[button_num] = input_time; button_up[button_num] = input_time;
} }
} }
@@ -2017,8 +2046,10 @@ void rawinput::RawInputManager::device_write_output(Device *device, bool only_up
switch (hid->driver) { switch (hid->driver) {
case HIDDriver::Default: { case HIDDriver::Default: {
// allocate report auto &report_data = hid->output_report;
CHAR *report_data = new CHAR[hid->caps.OutputReportByteLength] {}; auto &usage_list = hid->button_output_usages;
auto &usage_off_list = hid->button_output_usages_off;
std::fill(report_data.begin(), report_data.end(), 0);
// set buttons // set buttons
for (size_t cap_no = 0; cap_no < hid->button_output_caps_list.size(); cap_no++) { for (size_t cap_no = 0; cap_no < hid->button_output_caps_list.size(); cap_no++) {
@@ -2026,10 +2057,8 @@ void rawinput::RawInputManager::device_write_output(Device *device, bool only_up
auto &button_state_list = hid->button_output_states[cap_no]; auto &button_state_list = hid->button_output_states[cap_no];
// determine which buttons to turn on // determine which buttons to turn on
std::vector<USAGE> usage_list; usage_list.clear();
std::vector<USAGE> usage_off_list; usage_off_list.clear();
usage_list.reserve(button_state_list.size());
usage_off_list.reserve(button_state_list.size());
for (size_t state_no = 0; state_no < button_state_list.size(); state_no++) { for (size_t state_no = 0; state_no < button_state_list.size(); state_no++) {
if (button_state_list[state_no]) { if (button_state_list[state_no]) {
usage_list.push_back(button_cap.Range.UsageMin + (USAGE) state_no); usage_list.push_back(button_cap.Range.UsageMin + (USAGE) state_no);
@@ -2044,15 +2073,18 @@ void rawinput::RawInputManager::device_write_output(Device *device, bool only_up
HidP_Output, HidP_Output,
button_cap.UsagePage, button_cap.UsagePage,
button_cap.LinkCollection, button_cap.LinkCollection,
&usage_list[0], usage_list.data(),
&usage_list_length, &usage_list_length,
reinterpret_cast<PHIDP_PREPARSED_DATA>(hid->preparsed_data.get()), reinterpret_cast<PHIDP_PREPARSED_DATA>(hid->preparsed_data.get()),
report_data, report_data.data(),
hid->caps.OutputReportByteLength) == HIDP_STATUS_INCOMPATIBLE_REPORT_ID) { hid->caps.OutputReportByteLength) == HIDP_STATUS_INCOMPATIBLE_REPORT_ID) {
// flush report // flush report
HidD_SetOutputReport(hid->handle, report_data, hid->caps.OutputReportByteLength); HidD_SetOutputReport(
memset(report_data, 0, hid->caps.OutputReportByteLength); hid->handle,
report_data.data(),
hid->caps.OutputReportByteLength);
std::fill(report_data.begin(), report_data.end(), 0);
} }
// clear the buttons // clear the buttons
@@ -2061,22 +2093,22 @@ void rawinput::RawInputManager::device_write_output(Device *device, bool only_up
HidP_Output, HidP_Output,
button_cap.UsagePage, button_cap.UsagePage,
button_cap.LinkCollection, button_cap.LinkCollection,
&usage_off_list[0], usage_off_list.data(),
&usage_off_list_length, &usage_off_list_length,
reinterpret_cast<PHIDP_PREPARSED_DATA>(hid->preparsed_data.get()), reinterpret_cast<PHIDP_PREPARSED_DATA>(hid->preparsed_data.get()),
report_data, report_data.data(),
hid->caps.OutputReportByteLength) == HIDP_STATUS_INCOMPATIBLE_REPORT_ID) { hid->caps.OutputReportByteLength) == HIDP_STATUS_INCOMPATIBLE_REPORT_ID) {
// flush report // flush report
DWORD written_bytes = 0; DWORD written_bytes = 0;
WriteFile( WriteFile(
hid->handle, hid->handle,
reinterpret_cast<void *>(report_data), report_data.data(),
hid->caps.OutputReportByteLength, hid->caps.OutputReportByteLength,
&written_bytes, &written_bytes,
nullptr nullptr
); );
memset(report_data, 0, hid->caps.OutputReportByteLength); std::fill(report_data.begin(), report_data.end(), 0);
} }
} }
@@ -2105,19 +2137,19 @@ void rawinput::RawInputManager::device_write_output(Device *device, bool only_up
value_cap.NotRange.Usage, value_cap.NotRange.Usage,
static_cast<ULONG>(usage_value), static_cast<ULONG>(usage_value),
reinterpret_cast<PHIDP_PREPARSED_DATA>(hid->preparsed_data.get()), reinterpret_cast<PHIDP_PREPARSED_DATA>(hid->preparsed_data.get()),
report_data, report_data.data(),
hid->caps.OutputReportByteLength) == HIDP_STATUS_INCOMPATIBLE_REPORT_ID) { hid->caps.OutputReportByteLength) == HIDP_STATUS_INCOMPATIBLE_REPORT_ID) {
// flush report // flush report
DWORD written_bytes = 0; DWORD written_bytes = 0;
WriteFile( WriteFile(
hid->handle, hid->handle,
reinterpret_cast<void *>(report_data), report_data.data(),
hid->caps.OutputReportByteLength, hid->caps.OutputReportByteLength,
&written_bytes, &written_bytes,
nullptr nullptr
); );
memset(report_data, 0, hid->caps.OutputReportByteLength); std::fill(report_data.begin(), report_data.end(), 0);
} }
} }
@@ -2151,15 +2183,12 @@ void rawinput::RawInputManager::device_write_output(Device *device, bool only_up
DWORD written_bytes = 0; DWORD written_bytes = 0;
WriteFile( WriteFile(
hid->handle, hid->handle,
reinterpret_cast<void *>(report_data), report_data.data(),
hid->caps.OutputReportByteLength, hid->caps.OutputReportByteLength,
&written_bytes, &written_bytes,
nullptr nullptr
); );
// delete report
delete[] report_data;
break; break;
} }
case HIDDriver::PacDrive: { case HIDDriver::PacDrive: {
+14 -5
View File
@@ -319,7 +319,8 @@ namespace rawinput::touch {
} }
// iterate all input data and get touch points // iterate all input data and get touch points
std::vector<HIDTouchPoint> touch_points; thread_local std::vector<HIDTouchPoint> touch_points;
touch_points.clear();
touch_points.reserve(touch.elements_x.size()); touch_points.reserve(touch.elements_x.size());
for (size_t i = 0; i < touch.elements_x.size(); i++) { for (size_t i = 0; i < touch.elements_x.size(); i++) {
@@ -424,9 +425,15 @@ namespace rawinput::touch {
} }
// process touch points // process touch points
std::vector<DWORD> touch_removes; thread_local std::vector<DWORD> touch_removes;
std::vector<TouchPoint> touch_writes; thread_local std::vector<TouchPoint> touch_writes;
std::vector<DWORD> touch_modifications; thread_local std::vector<DWORD> touch_modifications;
touch_removes.clear();
touch_writes.clear();
touch_modifications.clear();
touch_removes.reserve(touch.touch_points.size() + touch_points.size());
touch_writes.reserve(touch_points.size());
touch_modifications.reserve(touch_points.size());
// drop every touch point with the given id (marking it as released) // drop every touch point with the given id (marking it as released)
auto remove_touch_point = [&] (DWORD id) { auto remove_touch_point = [&] (DWORD id) {
@@ -581,7 +588,9 @@ namespace rawinput::touch {
auto deadline = get_system_milliseconds() - 50; auto deadline = get_system_milliseconds() - 50;
// check touch points // check touch points
std::vector<DWORD> touch_removes; thread_local std::vector<DWORD> touch_removes;
touch_removes.clear();
touch_removes.reserve(touch.touch_points.size());
auto touch_it = touch.touch_points.begin(); auto touch_it = touch.touch_points.begin();
while (touch_it != touch.touch_points.end()) { while (touch_it != touch.touch_points.end()) {
auto &hid_tp = *touch_it; auto &hid_tp = *touch_it;
+7 -11
View File
@@ -1,13 +1,13 @@
#include "reader.h" #include "reader.h"
#include <chrono>
#include <cstring>
#include <filesystem> #include <filesystem>
#include <thread> #include <thread>
#include <cstring>
#include <vector> #include <vector>
#include "util/logging.h" #include "util/logging.h"
#include "misc/eamuse.h" #include "misc/eamuse.h"
#include "util/precise_timer.h"
#include "util/utils.h" #include "util/utils.h"
#include "structuredmessage.h" #include "structuredmessage.h"
@@ -218,8 +218,6 @@ bool Reader::set_comm_state(DWORD BaudRate) {
} }
bool Reader::wait_for_handshake() { bool Reader::wait_for_handshake() {
timeutils::PreciseSleepTimer timer;
// baud rates // baud rates
DWORD baud_rates[] = { CBR_57600, CBR_38400, CBR_19200, CBR_9600 }; DWORD baud_rates[] = { CBR_57600, CBR_38400, CBR_19200, CBR_9600 };
@@ -270,7 +268,7 @@ bool Reader::wait_for_handshake() {
} }
// sleep // sleep
timer.sleep(50); std::this_thread::sleep_for(std::chrono::milliseconds(50));
} }
log_warning("reader", "{}: no handshake received for {} baud", this->port, baud_rates[i]); log_warning("reader", "{}: no handshake received for {} baud", this->port, baud_rates[i]);
@@ -407,7 +405,6 @@ void start_reader_thread(const std::string &port, int id) {
READER_THREAD_RUNNING = true; READER_THREAD_RUNNING = true;
READER_THREADS.push_back(new std::thread([port, id]() { READER_THREADS.push_back(new std::thread([port, id]() {
log_info("reader", "{}: starting reader thread", port); log_info("reader", "{}: starting reader thread", port);
timeutils::PreciseSleepTimer timer;
while (READER_THREAD_RUNNING) { while (READER_THREAD_RUNNING) {
@@ -445,22 +442,21 @@ void start_reader_thread(const std::string &port, int id) {
} }
if (did_read_card) { if (did_read_card) {
timer.sleep(2500); std::this_thread::sleep_for(std::chrono::milliseconds(2500));
} }
timer.sleep(20); std::this_thread::sleep_for(std::chrono::milliseconds(20));
} }
} }
// sleep between reader connection retries // sleep between reader connection retries
if (READER_THREAD_RUNNING) if (READER_THREAD_RUNNING)
timer.sleep(5000); std::this_thread::sleep_for(std::chrono::milliseconds(5000));
} }
})); }));
// wait for thread to start // wait for thread to start
timeutils::PreciseSleepTimer timer; std::this_thread::sleep_for(std::chrono::milliseconds(10));
timer.sleep(10);
} }
void stop_reader_thread() { void stop_reader_thread() {