mirror of
https://github.com/spice2x/spice2x.github.io.git
synced 2026-08-01 22:30:42 -07:00
rawinput: deal with high poll rate devices, use 3x3 for default for rb touch emu (#796)
## Link to GitHub Issue or related Pull Request, if one exists n/a ## Description of change Two changes: 1. Handle all HID events in `WM_INPUT` and not just the first one. This only really affects 4000Hz / 8000Hz HID devices. 2. Go back to `3x3` as the default for rb IR touch emulation and remove `1x1` as an option as it does not perform as well as I expected. ## Testing
This commit is contained in:
@@ -41,7 +41,7 @@ void games::rb::RBGame::attach() {
|
|||||||
Game::attach();
|
Game::attach();
|
||||||
|
|
||||||
if (1000 < games::rb::TOUCH_POLL_RATE) {
|
if (1000 < games::rb::TOUCH_POLL_RATE) {
|
||||||
log_fatal("rb", "-rbtouchsize is set too high; cannot exceed 1000");
|
log_fatal("rb", "-rbtouchhz is set too high; cannot exceed 1000");
|
||||||
}
|
}
|
||||||
|
|
||||||
// init stuff
|
// init stuff
|
||||||
@@ -60,7 +60,7 @@ void games::rb::RBGame::attach() {
|
|||||||
log_info("rb", "force increasing touch poll rate by hooking SleepEx ({}Hz)", TOUCH_POLL_RATE);
|
log_info("rb", "force increasing touch poll rate by hooking SleepEx ({}Hz)", TOUCH_POLL_RATE);
|
||||||
SleepEx_orig = detour::iat_try("SleepEx", SleepEx_hook, avs::game::DLL_INSTANCE);
|
SleepEx_orig = detour::iat_try("SleepEx", SleepEx_hook, avs::game::DLL_INSTANCE);
|
||||||
} else {
|
} else {
|
||||||
log_info("rb", "not changing touch poll rate (120Hz by default)");
|
log_info("rb", "not changing touch poll rate (~125Hz by default)");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -7,7 +7,6 @@
|
|||||||
namespace games::rb {
|
namespace games::rb {
|
||||||
|
|
||||||
extern uint16_t TOUCH_SCALING;
|
extern uint16_t TOUCH_SCALING;
|
||||||
extern uint8_t TOUCH_SIZE;
|
|
||||||
extern uint16_t TOUCH_POLL_RATE;
|
extern uint16_t TOUCH_POLL_RATE;
|
||||||
|
|
||||||
class RBGame : public games::Game {
|
class RBGame : public games::Game {
|
||||||
|
|||||||
@@ -14,7 +14,6 @@ static std::string WINDOW_TITLE = "REFLEC BEAT";
|
|||||||
|
|
||||||
namespace games::rb {
|
namespace games::rb {
|
||||||
uint16_t TOUCH_SCALING = 1000;
|
uint16_t TOUCH_SCALING = 1000;
|
||||||
uint8_t TOUCH_SIZE = 1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
games::rb::ReflecBeatTouchDeviceHandle::ReflecBeatTouchDeviceHandle(bool log_fps) {
|
games::rb::ReflecBeatTouchDeviceHandle::ReflecBeatTouchDeviceHandle(bool log_fps) {
|
||||||
@@ -50,6 +49,9 @@ bool games::rb::ReflecBeatTouchDeviceHandle::open(LPCWSTR lpFileName) {
|
|||||||
|
|
||||||
if (wnd != nullptr) {
|
if (wnd != nullptr) {
|
||||||
|
|
||||||
|
// cache the game window so read() can size against it regardless of focus
|
||||||
|
this->game_hwnd = wnd;
|
||||||
|
|
||||||
// reset window process to make the game not crash
|
// reset window process to make the game not crash
|
||||||
SetWindowLongPtr(wnd, GWLP_WNDPROC, reinterpret_cast<LONG_PTR>(DefWindowProc));
|
SetWindowLongPtr(wnd, GWLP_WNDPROC, reinterpret_cast<LONG_PTR>(DefWindowProc));
|
||||||
|
|
||||||
@@ -106,8 +108,9 @@ int games::rb::ReflecBeatTouchDeviceHandle::read(LPVOID lpBuffer, DWORD nNumberO
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// get window
|
// size against the game window cached in open() (not GetForegroundWindow), so
|
||||||
HWND window = GetForegroundWindow();
|
// touch stays correctly scaled and keeps working when the game loses focus
|
||||||
|
HWND window = this->game_hwnd;
|
||||||
if (window == nullptr) {
|
if (window == nullptr) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -166,20 +169,20 @@ int games::rb::ReflecBeatTouchDeviceHandle::read(LPVOID lpBuffer, DWORD nNumberO
|
|||||||
const auto point_x = (int) ((x - window_width / 2.0) * 48.0 / 54.0 + window_width / 2.0);
|
const auto point_x = (int) ((x - window_width / 2.0) * 48.0 / 54.0 + window_width / 2.0);
|
||||||
const auto point_y = (int) (y - window_height / 76);
|
const auto point_y = (int) (y - window_height / 76);
|
||||||
|
|
||||||
// center
|
// model a finger as a 3x3 block of IR sensors around the touch point
|
||||||
grid_insert(data, point_x, point_y);
|
// this gives better accuracy (than just 1x1) since the logic below
|
||||||
|
// can toggle anywhere from 1x1 to 2x2, and the game engine calculates
|
||||||
// surrounding points
|
// the center point, which means by inserting up to 8 extra blocks
|
||||||
if (games::rb::TOUCH_SIZE == 3) {
|
// we are emulating a sub-"pixel" resolution
|
||||||
grid_insert(data, point_x - offset_x, point_y); // west
|
grid_insert(data, point_x, point_y); // center
|
||||||
grid_insert(data, point_x - offset_x, point_y - offset_y); // northwest
|
grid_insert(data, point_x - offset_x, point_y); // west
|
||||||
grid_insert(data, point_x - offset_x, point_y + offset_y); // southwest
|
grid_insert(data, point_x - offset_x, point_y - offset_y); // northwest
|
||||||
grid_insert(data, point_x + offset_x, point_y); // east
|
grid_insert(data, point_x - offset_x, point_y + offset_y); // southwest
|
||||||
grid_insert(data, point_x + offset_x, point_y + offset_y); // southeast
|
grid_insert(data, point_x + offset_x, point_y); // east
|
||||||
grid_insert(data, point_x + offset_x, point_y - offset_y); // northeast
|
grid_insert(data, point_x + offset_x, point_y + offset_y); // southeast
|
||||||
grid_insert(data, point_x, point_y - offset_y); // north
|
grid_insert(data, point_x + offset_x, point_y - offset_y); // northeast
|
||||||
grid_insert(data, point_x, point_y + offset_y); // south
|
grid_insert(data, point_x, point_y - offset_y); // north
|
||||||
}
|
grid_insert(data, point_x, point_y + offset_y); // south
|
||||||
}
|
}
|
||||||
|
|
||||||
// copy data to buffer
|
// copy data to buffer
|
||||||
|
|||||||
@@ -12,6 +12,12 @@ namespace games::rb {
|
|||||||
int window_width = 1080;
|
int window_width = 1080;
|
||||||
int window_height = 1920;
|
int window_height = 1920;
|
||||||
|
|
||||||
|
// game window resolved in open(); read() sizes against this instead of the
|
||||||
|
// foreground window so touch stays correctly scaled and keeps working when
|
||||||
|
// the game is not the foreground window (rawinput delivers touch regardless
|
||||||
|
// of focus)
|
||||||
|
HWND game_hwnd = nullptr;
|
||||||
|
|
||||||
// logging
|
// logging
|
||||||
bool log_fps = false;
|
bool log_fps = false;
|
||||||
uint64_t log_time = 0;
|
uint64_t log_time = 0;
|
||||||
|
|||||||
@@ -1323,12 +1323,7 @@ int main_implementation(int argc, char *argv[]) {
|
|||||||
if (options[launcher::Options::spice2x_RBTouchScale].is_active()) {
|
if (options[launcher::Options::spice2x_RBTouchScale].is_active()) {
|
||||||
games::rb::TOUCH_SCALING = options[launcher::Options::spice2x_RBTouchScale].value_uint32();
|
games::rb::TOUCH_SCALING = options[launcher::Options::spice2x_RBTouchScale].value_uint32();
|
||||||
}
|
}
|
||||||
if (options[launcher::Options::RBTouchSize].is_active()) {
|
// -rbtouchsize is deprecated and ignored; touch emulation always uses the 3x3 model
|
||||||
const auto text = options[launcher::Options::RBTouchSize].value_text();
|
|
||||||
if (text == "3") {
|
|
||||||
games::rb::TOUCH_SIZE = 3;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (options[launcher::Options::RBTouchPollRate].is_active()) {
|
if (options[launcher::Options::RBTouchPollRate].is_active()) {
|
||||||
games::rb::TOUCH_POLL_RATE = options[launcher::Options::RBTouchPollRate].value_uint32();
|
games::rb::TOUCH_POLL_RATE = options[launcher::Options::RBTouchPollRate].value_uint32();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2716,14 +2716,15 @@ static const std::vector<OptionDefinition> OPTION_DEFINITIONS = {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
// RBTouchSize
|
// RBTouchSize
|
||||||
.title = "RB Touch Emulation Size",
|
.title = "RB Touch Emulation Size (DEPRECATED - no longer has any effect)",
|
||||||
.name = "rbtouchsize",
|
.name = "rbtouchsize",
|
||||||
.desc = "Size of the touch area; how many IR sensors a single finger activates. Default: 1 (1x1).",
|
.desc = "This option is deprecated and no longer has any effect. "
|
||||||
|
"Reflec Beat touch emulation always uses the 3x3 sensor model.",
|
||||||
.type = OptionType::Enum,
|
.type = OptionType::Enum,
|
||||||
|
.hidden = true,
|
||||||
.game_name = "Reflec Beat",
|
.game_name = "Reflec Beat",
|
||||||
.category = "Game Options",
|
.category = "Game Options",
|
||||||
.elements = {
|
.elements = {
|
||||||
{"1", "1x1"},
|
|
||||||
{"3", "3x3"},
|
{"3", "3x3"},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -2731,9 +2732,10 @@ static const std::vector<OptionDefinition> OPTION_DEFINITIONS = {
|
|||||||
// RBTouchPollRate
|
// RBTouchPollRate
|
||||||
.title = "RB Touch Emulation Poll Hz",
|
.title = "RB Touch Emulation Poll Hz",
|
||||||
.name = "rbtouchhz",
|
.name = "rbtouchhz",
|
||||||
.desc = "By default, the game polls for touch at 120Hz. "
|
.desc = "By default, the game polls for touch at ~125Hz. "
|
||||||
"This option overrides that rate; enter a number betwen 1 and 1000.\n\n"
|
"This option overrides that rate; enter a number between 1 and 1000.\n\n"
|
||||||
"It should be noted that higher poll does not necessarily improve accuracy or performance.",
|
"Higher rates reduce input latency (the game sees a fresher touch position) "
|
||||||
|
"but do NOT improve spatial accuracy, and very high rates just waste CPU.",
|
||||||
.type = OptionType::Integer,
|
.type = OptionType::Integer,
|
||||||
.setting_name = "250",
|
.setting_name = "250",
|
||||||
.game_name = "Reflec Beat",
|
.game_name = "Reflec Beat",
|
||||||
|
|||||||
+139
-128
@@ -1764,162 +1764,173 @@ LRESULT CALLBACK rawinput::RawInputManager::input_wnd_proc(
|
|||||||
// get HID data
|
// get HID data
|
||||||
auto &data_hid = data->data.hid;
|
auto &data_hid = data->data.hid;
|
||||||
|
|
||||||
// parse reports
|
// a single WM_INPUT may carry more than one HID report from the same
|
||||||
for (const auto &pair : device.hidInfo->button_usage_pages) {
|
// device: bRawData holds dwCount reports of dwSizeHid bytes each (the
|
||||||
const auto usage_page = pair.first.first;
|
// buffer size is dwSizeHid * dwCount). parse every report instead of
|
||||||
const auto link_collection = pair.first.second;
|
// only the first one.
|
||||||
const auto button_count = pair.second;
|
// https://learn.microsoft.com/en-us/windows/win32/api/winuser/ns-winuser-rawhid
|
||||||
|
const DWORD hid_report_count = data_hid.dwCount > 0 ? data_hid.dwCount : 1;
|
||||||
|
for (DWORD hid_report_index = 0; hid_report_index < hid_report_count; hid_report_index++) {
|
||||||
|
auto *report_data = reinterpret_cast<BYTE *>(data_hid.bRawData)
|
||||||
|
+ (size_t) hid_report_index * data_hid.dwSizeHid;
|
||||||
|
|
||||||
ULONG usages_length = button_count;
|
// parse reports
|
||||||
std::vector<USAGE> usages(static_cast<size_t>(usages_length));
|
for (const auto &pair : device.hidInfo->button_usage_pages) {
|
||||||
if (HidP_GetUsages(
|
const auto usage_page = pair.first.first;
|
||||||
HidP_Input,
|
const auto link_collection = pair.first.second;
|
||||||
usage_page,
|
const auto button_count = pair.second;
|
||||||
link_collection,
|
|
||||||
usages.data(),
|
|
||||||
&usages_length,
|
|
||||||
reinterpret_cast<PHIDP_PREPARSED_DATA>(device.hidInfo->preparsed_data.get()),
|
|
||||||
reinterpret_cast<PCHAR>(data_hid.bRawData),
|
|
||||||
data_hid.dwSizeHid) != HIDP_STATUS_SUCCESS) {
|
|
||||||
|
|
||||||
// log_warning(
|
ULONG usages_length = button_count;
|
||||||
|
std::vector<USAGE> usages(static_cast<size_t>(usages_length));
|
||||||
|
if (HidP_GetUsages(
|
||||||
|
HidP_Input,
|
||||||
|
usage_page,
|
||||||
|
link_collection,
|
||||||
|
usages.data(),
|
||||||
|
&usages_length,
|
||||||
|
reinterpret_cast<PHIDP_PREPARSED_DATA>(device.hidInfo->preparsed_data.get()),
|
||||||
|
reinterpret_cast<PCHAR>(report_data),
|
||||||
|
data_hid.dwSizeHid) != HIDP_STATUS_SUCCESS) {
|
||||||
|
|
||||||
|
// log_warning(
|
||||||
|
// "rawinput",
|
||||||
|
// "failed to get usages for device {}, usage page {:x} and link collection {:x}",
|
||||||
|
// device.desc,
|
||||||
|
// usage_page, link_collection);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// log_info(
|
||||||
// "rawinput",
|
// "rawinput",
|
||||||
// "failed to get usages for device {}, usage page {:x} and link collection {:x}",
|
// "processing HID input for device {}, usage page {:x} and link collection {:x} with {} buttons, got {} reports",
|
||||||
// device.desc,
|
// device.desc,
|
||||||
// usage_page, link_collection);
|
// usage_page, link_collection, button_count, usages_length);
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// log_info(
|
// buttons
|
||||||
// "rawinput",
|
for (size_t cap_num = 0; cap_num < device.hidInfo->button_caps_list.size(); cap_num++) {
|
||||||
// "processing HID input for device {}, usage page {:x} and link collection {:x} with {} buttons, got {} reports",
|
auto &button_caps = device.hidInfo->button_caps_list[cap_num];
|
||||||
// device.desc,
|
auto &button_states = device.hidInfo->button_states[cap_num];
|
||||||
// usage_page, link_collection, button_count, usages_length);
|
auto &button_down = device.hidInfo->button_down[cap_num];
|
||||||
|
auto &button_up = device.hidInfo->button_up[cap_num];
|
||||||
|
|
||||||
// buttons
|
// is this the right usage page and link collection?
|
||||||
for (size_t cap_num = 0; cap_num < device.hidInfo->button_caps_list.size(); cap_num++) {
|
if (button_caps.UsagePage != usage_page || button_caps.LinkCollection != link_collection) {
|
||||||
auto &button_caps = device.hidInfo->button_caps_list[cap_num];
|
|
||||||
auto &button_states = device.hidInfo->button_states[cap_num];
|
|
||||||
auto &button_down = device.hidInfo->button_down[cap_num];
|
|
||||||
auto &button_up = device.hidInfo->button_up[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
|
|
||||||
int button_count = button_caps.Range.UsageMax - button_caps.Range.UsageMin + 1;
|
|
||||||
if (button_count <= 0) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// update buttons
|
|
||||||
std::vector<bool> new_states(button_count);
|
|
||||||
for (ULONG usage_num = 0; usage_num < usages_length; usage_num++) {
|
|
||||||
if (usages[usage_num] < button_caps.Range.UsageMin ||
|
|
||||||
usages[usage_num] > button_caps.Range.UsageMax) {
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
USAGE usage = usages[usage_num] - button_caps.Range.UsageMin;
|
// get button count
|
||||||
|
int button_count = button_caps.Range.UsageMax - button_caps.Range.UsageMin + 1;
|
||||||
// guard against some buggy device sending an event for a usage below `UsageMin`
|
if (button_count <= 0) {
|
||||||
if (usage < button_count) {
|
continue;
|
||||||
new_states[usage] = true;
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
for (int button_num = 0; button_num < button_count; button_num++) {
|
// update buttons
|
||||||
if (!new_states[button_num] && button_states[button_num]) {
|
std::vector<bool> new_states(button_count);
|
||||||
device.updated = true;
|
for (ULONG usage_num = 0; usage_num < usages_length; usage_num++) {
|
||||||
button_states[button_num] = new_states[button_num];
|
if (usages[usage_num] < button_caps.Range.UsageMin ||
|
||||||
button_down[button_num] = input_time;
|
usages[usage_num] > button_caps.Range.UsageMax) {
|
||||||
} else if (new_states[button_num] && !button_states[button_num]) {
|
continue;
|
||||||
device.updated = true;
|
}
|
||||||
button_states[button_num] = new_states[button_num];
|
|
||||||
button_up[button_num] = input_time;
|
USAGE usage = usages[usage_num] - button_caps.Range.UsageMin;
|
||||||
|
|
||||||
|
// guard against some buggy device sending an event for a usage below `UsageMin`
|
||||||
|
if (usage < button_count) {
|
||||||
|
new_states[usage] = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (int button_num = 0; button_num < button_count; button_num++) {
|
||||||
|
if (!new_states[button_num] && button_states[button_num]) {
|
||||||
|
device.updated = true;
|
||||||
|
button_states[button_num] = new_states[button_num];
|
||||||
|
button_down[button_num] = input_time;
|
||||||
|
} else if (new_states[button_num] && !button_states[button_num]) {
|
||||||
|
device.updated = true;
|
||||||
|
button_states[button_num] = new_states[button_num];
|
||||||
|
button_up[button_num] = input_time;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// analogs
|
// analogs
|
||||||
for (auto cap_num = 0; cap_num < device.hidInfo->caps.NumberInputValueCaps; cap_num++) {
|
for (auto cap_num = 0; cap_num < device.hidInfo->caps.NumberInputValueCaps; cap_num++) {
|
||||||
auto &value_caps = device.hidInfo->value_caps_list[cap_num];
|
auto &value_caps = device.hidInfo->value_caps_list[cap_num];
|
||||||
|
|
||||||
// get value
|
// get value
|
||||||
LONG value_raw = 0;
|
LONG value_raw = 0;
|
||||||
if (HidP_GetUsageValue(
|
if (HidP_GetUsageValue(
|
||||||
HidP_Input,
|
HidP_Input,
|
||||||
value_caps.UsagePage,
|
value_caps.UsagePage,
|
||||||
value_caps.LinkCollection,
|
value_caps.LinkCollection,
|
||||||
value_caps.Range.UsageMin,
|
value_caps.Range.UsageMin,
|
||||||
reinterpret_cast<ULONG *>(&value_raw),
|
reinterpret_cast<ULONG *>(&value_raw),
|
||||||
reinterpret_cast<PHIDP_PREPARSED_DATA>(device.hidInfo->preparsed_data.get()),
|
reinterpret_cast<PHIDP_PREPARSED_DATA>(device.hidInfo->preparsed_data.get()),
|
||||||
reinterpret_cast<CHAR *>(data_hid.bRawData),
|
reinterpret_cast<CHAR *>(report_data),
|
||||||
data_hid.dwSizeHid) != HIDP_STATUS_SUCCESS)
|
data_hid.dwSizeHid) != HIDP_STATUS_SUCCESS)
|
||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// get min and max
|
// get min and max
|
||||||
LONG value_min = value_caps.LogicalMin;
|
LONG value_min = value_caps.LogicalMin;
|
||||||
LONG value_max = value_caps.LogicalMax;
|
LONG value_max = value_caps.LogicalMax;
|
||||||
|
|
||||||
float value;
|
float value;
|
||||||
// 0x1 == generic desktop, 0x39 == hat switch
|
// 0x1 == generic desktop, 0x39 == hat switch
|
||||||
if (value_caps.UsagePage == 0x1 && value_caps.Range.UsageMin == 0x39) {
|
if (value_caps.UsagePage == 0x1 && value_caps.Range.UsageMin == 0x39) {
|
||||||
if (value_min <= value_raw && value_raw <= value_max) {
|
if (value_min <= value_raw && value_raw <= value_max) {
|
||||||
// scale to float; minimum valid value is UP, and increases in clockwise order
|
// scale to float; minimum valid value is UP, and increases in clockwise order
|
||||||
value = (float) (value_raw - value_min) / (float) (value_max - value_min);
|
value = (float) (value_raw - value_min) / (float) (value_max - value_min);
|
||||||
|
} else {
|
||||||
|
// hat switches report an out-of-bounds value to indicate a neutral position, so it
|
||||||
|
// needs special handling; here, we will use a negative value to indicate neutral
|
||||||
|
value = -1.f;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
// hat switches report an out-of-bounds value to indicate a neutral position, so it
|
|
||||||
// needs special handling; here, we will use a negative value to indicate neutral
|
|
||||||
value = -1.f;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
|
|
||||||
// fix sign bits for signed values
|
// fix sign bits for signed values
|
||||||
if (value_caps.LogicalMin < 0 &&
|
if (value_caps.LogicalMin < 0 &&
|
||||||
0 < value_caps.BitSize && value_caps.BitSize < 32) {
|
0 < value_caps.BitSize && value_caps.BitSize < 32) {
|
||||||
|
|
||||||
ULONG raw = static_cast<ULONG>(value_raw) & ((1u << value_caps.BitSize) - 1u);
|
ULONG raw = static_cast<ULONG>(value_raw) & ((1u << value_caps.BitSize) - 1u);
|
||||||
const ULONG sign_bit = 1u << (value_caps.BitSize - 1);
|
const ULONG sign_bit = 1u << (value_caps.BitSize - 1);
|
||||||
value_raw = static_cast<LONG>((raw ^ sign_bit) - sign_bit);
|
value_raw = static_cast<LONG>((raw ^ sign_bit) - sign_bit);
|
||||||
|
}
|
||||||
|
|
||||||
|
// automatic calibration
|
||||||
|
if (value_raw < value_min) {
|
||||||
|
value_caps.LogicalMin = value_raw;
|
||||||
|
value_min = value_raw;
|
||||||
|
}
|
||||||
|
if (value_raw > value_max) {
|
||||||
|
value_caps.LogicalMax = value_raw;
|
||||||
|
value_max = value_raw;
|
||||||
|
}
|
||||||
|
|
||||||
|
// scale to float
|
||||||
|
value = (float) (value_raw - value_min) / (float) (value_max - value_min);
|
||||||
}
|
}
|
||||||
|
|
||||||
// automatic calibration
|
// store value
|
||||||
if (value_raw < value_min) {
|
auto &cur_state = device.hidInfo->value_states[cap_num];
|
||||||
value_caps.LogicalMin = value_raw;
|
if (cur_state != value) {
|
||||||
value_min = value_raw;
|
device.updated = true;
|
||||||
}
|
cur_state = value;
|
||||||
if (value_raw > value_max) {
|
|
||||||
value_caps.LogicalMax = value_raw;
|
|
||||||
value_max = value_raw;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// scale to float
|
// store raw value
|
||||||
value = (float) (value_raw - value_min) / (float) (value_max - value_min);
|
auto &cur_raw_state = device.hidInfo->value_states_raw[cap_num];
|
||||||
|
if (cur_raw_state != value_raw) {
|
||||||
|
device.updated = true;
|
||||||
|
cur_raw_state = value_raw;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// store value
|
// touch screen
|
||||||
auto &cur_state = device.hidInfo->value_states[cap_num];
|
rawinput::touch::update_input(&device);
|
||||||
if (cur_state != value) {
|
|
||||||
device.updated = true;
|
|
||||||
cur_state = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
// store raw value
|
|
||||||
auto &cur_raw_state = device.hidInfo->value_states_raw[cap_num];
|
|
||||||
if (cur_raw_state != value_raw) {
|
|
||||||
device.updated = true;
|
|
||||||
cur_raw_state = value_raw;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// touch screen
|
|
||||||
rawinput::touch::update_input(&device);
|
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
|
|||||||
Reference in New Issue
Block a user