mirror of
https://github.com/spice2x/spice2x.github.io.git
synced 2026-10-01 06:24:55 -07:00
5cabd026ae
## 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
227 lines
9.9 KiB
C++
227 lines
9.9 KiB
C++
#include "poke.h"
|
|
|
|
#include <chrono>
|
|
#include <thread>
|
|
|
|
#include "windows.h"
|
|
#include "games/io.h"
|
|
#include "games/iidx/iidx.h"
|
|
#include "hooks/graphics/graphics.h"
|
|
#include "launcher/shutdown.h"
|
|
#include "misc/eamuse.h"
|
|
#include "touch/native/inject.h"
|
|
#include "touch/touch.h"
|
|
#include "util/logging.h"
|
|
|
|
namespace games::iidx::poke {
|
|
|
|
static std::thread *THREAD = nullptr;
|
|
static bool THREAD_RUNNING = false;
|
|
|
|
struct KeypadMapping {
|
|
char character;
|
|
uint16_t state;
|
|
};
|
|
|
|
static KeypadMapping KEYPAD_MAPPINGS[] = {
|
|
{ '0', 1 << EAM_IO_KEYPAD_0 },
|
|
{ '1', 1 << EAM_IO_KEYPAD_1 },
|
|
{ '2', 1 << EAM_IO_KEYPAD_2 },
|
|
{ '3', 1 << EAM_IO_KEYPAD_3 },
|
|
{ '4', 1 << EAM_IO_KEYPAD_4 },
|
|
{ '5', 1 << EAM_IO_KEYPAD_5 },
|
|
{ '6', 1 << EAM_IO_KEYPAD_6 },
|
|
{ '7', 1 << EAM_IO_KEYPAD_7 },
|
|
{ '8', 1 << EAM_IO_KEYPAD_8 },
|
|
{ '9', 1 << EAM_IO_KEYPAD_9 },
|
|
{ 'A', 1 << EAM_IO_KEYPAD_00 },
|
|
|
|
// Touch panel keypad does not have the decimal key.
|
|
// This will be used for toggling the keypad instead
|
|
{ 'D', 1 << EAM_IO_KEYPAD_DECIMAL },
|
|
};
|
|
|
|
const int IIDX_KEYPAD_BUTTON_SIZE = 90;
|
|
const int IIDX_KEYPAD_GAP = 15;
|
|
const int IIDX_KEYPAD_TOP = 570;
|
|
const int IIDX_KEYPAD_LEFT_1P = 90;
|
|
const int IIDX_KEYPAD_LEFT_2P = 1530;
|
|
|
|
// <KeypadID>/<Key> mapped to 1080p coordinate space
|
|
static const std::unordered_map<std::string, int> IIDX_KEYPAD_POSITION_X {
|
|
{"0/0", (int)(IIDX_KEYPAD_LEFT_1P + IIDX_KEYPAD_BUTTON_SIZE * 0.5)},
|
|
{"0/1", (int)(IIDX_KEYPAD_LEFT_1P + IIDX_KEYPAD_BUTTON_SIZE * 0.5)},
|
|
{"0/2", (int)(IIDX_KEYPAD_LEFT_1P + IIDX_KEYPAD_BUTTON_SIZE * 1.5 + IIDX_KEYPAD_GAP)},
|
|
{"0/3", (int)(IIDX_KEYPAD_LEFT_1P + IIDX_KEYPAD_BUTTON_SIZE * 2.5 + IIDX_KEYPAD_GAP * 2)},
|
|
{"0/4", (int)(IIDX_KEYPAD_LEFT_1P + IIDX_KEYPAD_BUTTON_SIZE * 0.5)},
|
|
{"0/5", (int)(IIDX_KEYPAD_LEFT_1P + IIDX_KEYPAD_BUTTON_SIZE * 1.5 + IIDX_KEYPAD_GAP)},
|
|
{"0/6", (int)(IIDX_KEYPAD_LEFT_1P + IIDX_KEYPAD_BUTTON_SIZE * 2.5 + IIDX_KEYPAD_GAP * 2)},
|
|
{"0/7", (int)(IIDX_KEYPAD_LEFT_1P + IIDX_KEYPAD_BUTTON_SIZE * 0.5)},
|
|
{"0/8", (int)(IIDX_KEYPAD_LEFT_1P + IIDX_KEYPAD_BUTTON_SIZE * 1.5 + IIDX_KEYPAD_GAP)},
|
|
{"0/9", (int)(IIDX_KEYPAD_LEFT_1P + IIDX_KEYPAD_BUTTON_SIZE * 2.5 + IIDX_KEYPAD_GAP * 2)},
|
|
{"0/A", (int)(IIDX_KEYPAD_LEFT_1P + IIDX_KEYPAD_BUTTON_SIZE * 1.5 + IIDX_KEYPAD_GAP)},
|
|
{"0/D", 60},
|
|
{"1/0", (int)(IIDX_KEYPAD_LEFT_2P + IIDX_KEYPAD_BUTTON_SIZE * 0.5)},
|
|
{"1/1", (int)(IIDX_KEYPAD_LEFT_2P + IIDX_KEYPAD_BUTTON_SIZE * 0.5)},
|
|
{"1/2", (int)(IIDX_KEYPAD_LEFT_2P + IIDX_KEYPAD_BUTTON_SIZE * 1.5 + IIDX_KEYPAD_GAP)},
|
|
{"1/3", (int)(IIDX_KEYPAD_LEFT_2P + IIDX_KEYPAD_BUTTON_SIZE * 2.5 + IIDX_KEYPAD_GAP * 2)},
|
|
{"1/4", (int)(IIDX_KEYPAD_LEFT_2P + IIDX_KEYPAD_BUTTON_SIZE * 0.5)},
|
|
{"1/5", (int)(IIDX_KEYPAD_LEFT_2P + IIDX_KEYPAD_BUTTON_SIZE * 1.5 + IIDX_KEYPAD_GAP)},
|
|
{"1/6", (int)(IIDX_KEYPAD_LEFT_2P + IIDX_KEYPAD_BUTTON_SIZE * 2.5 + IIDX_KEYPAD_GAP * 2)},
|
|
{"1/7", (int)(IIDX_KEYPAD_LEFT_2P + IIDX_KEYPAD_BUTTON_SIZE * 0.5)},
|
|
{"1/8", (int)(IIDX_KEYPAD_LEFT_2P + IIDX_KEYPAD_BUTTON_SIZE * 1.5 + IIDX_KEYPAD_GAP)},
|
|
{"1/9", (int)(IIDX_KEYPAD_LEFT_2P + IIDX_KEYPAD_BUTTON_SIZE * 2.5 + IIDX_KEYPAD_GAP * 2)},
|
|
{"1/A", (int)(IIDX_KEYPAD_LEFT_2P + IIDX_KEYPAD_BUTTON_SIZE * 1.5 + IIDX_KEYPAD_GAP)},
|
|
{"1/D", 1920 - 60},
|
|
};
|
|
|
|
static const std::unordered_map<std::string, int> IIDX_KEYPAD_POSITION_Y {
|
|
{"0/0", (int)(IIDX_KEYPAD_TOP + IIDX_KEYPAD_GAP * 3 + IIDX_KEYPAD_BUTTON_SIZE * 3.5)},
|
|
{"0/1", (int)(IIDX_KEYPAD_TOP + IIDX_KEYPAD_GAP * 2 + IIDX_KEYPAD_BUTTON_SIZE * 2.5)},
|
|
{"0/2", (int)(IIDX_KEYPAD_TOP + IIDX_KEYPAD_GAP * 2 + IIDX_KEYPAD_BUTTON_SIZE * 2.5)},
|
|
{"0/3", (int)(IIDX_KEYPAD_TOP + IIDX_KEYPAD_GAP * 2 + IIDX_KEYPAD_BUTTON_SIZE * 2.5)},
|
|
{"0/4", (int)(IIDX_KEYPAD_TOP + IIDX_KEYPAD_GAP + IIDX_KEYPAD_BUTTON_SIZE * 1.5)},
|
|
{"0/5", (int)(IIDX_KEYPAD_TOP + IIDX_KEYPAD_GAP + IIDX_KEYPAD_BUTTON_SIZE * 1.5)},
|
|
{"0/6", (int)(IIDX_KEYPAD_TOP + IIDX_KEYPAD_GAP + IIDX_KEYPAD_BUTTON_SIZE * 1.5)},
|
|
{"0/7", (int)(IIDX_KEYPAD_TOP + IIDX_KEYPAD_BUTTON_SIZE * 0.5)},
|
|
{"0/8", (int)(IIDX_KEYPAD_TOP + IIDX_KEYPAD_BUTTON_SIZE * 0.5)},
|
|
{"0/9", (int)(IIDX_KEYPAD_TOP + IIDX_KEYPAD_BUTTON_SIZE * 0.5)},
|
|
{"0/A", (int)(IIDX_KEYPAD_TOP + IIDX_KEYPAD_GAP * 3 + IIDX_KEYPAD_BUTTON_SIZE * 3.5)},
|
|
{"0/D", 50},
|
|
{"1/0", (int)(IIDX_KEYPAD_TOP + IIDX_KEYPAD_GAP * 3 + IIDX_KEYPAD_BUTTON_SIZE * 3.5)},
|
|
{"1/1", (int)(IIDX_KEYPAD_TOP + IIDX_KEYPAD_GAP * 2 + IIDX_KEYPAD_BUTTON_SIZE * 2.5)},
|
|
{"1/2", (int)(IIDX_KEYPAD_TOP + IIDX_KEYPAD_GAP * 2 + IIDX_KEYPAD_BUTTON_SIZE * 2.5)},
|
|
{"1/3", (int)(IIDX_KEYPAD_TOP + IIDX_KEYPAD_GAP * 2 + IIDX_KEYPAD_BUTTON_SIZE * 2.5)},
|
|
{"1/4", (int)(IIDX_KEYPAD_TOP + IIDX_KEYPAD_GAP + IIDX_KEYPAD_BUTTON_SIZE * 1.5)},
|
|
{"1/5", (int)(IIDX_KEYPAD_TOP + IIDX_KEYPAD_GAP + IIDX_KEYPAD_BUTTON_SIZE * 1.5)},
|
|
{"1/6", (int)(IIDX_KEYPAD_TOP + IIDX_KEYPAD_GAP + IIDX_KEYPAD_BUTTON_SIZE * 1.5)},
|
|
{"1/7", (int)(IIDX_KEYPAD_TOP + IIDX_KEYPAD_BUTTON_SIZE * 0.5)},
|
|
{"1/8", (int)(IIDX_KEYPAD_TOP + IIDX_KEYPAD_BUTTON_SIZE * 0.5)},
|
|
{"1/9", (int)(IIDX_KEYPAD_TOP + IIDX_KEYPAD_BUTTON_SIZE * 0.5)},
|
|
{"1/A", (int)(IIDX_KEYPAD_TOP + IIDX_KEYPAD_GAP * 3 + IIDX_KEYPAD_BUTTON_SIZE * 3.5)},
|
|
{"1/D", 50},
|
|
};
|
|
|
|
static void inject_native_touch_points(const std::vector<TouchPoint> &touch_points, bool down) {
|
|
if (touch_points.empty()) {
|
|
return;
|
|
}
|
|
|
|
const auto &touch = touch_points.front();
|
|
nativetouch::inject::inject_synthetic_touch({ touch.x, touch.y }, down);
|
|
}
|
|
|
|
void enable() {
|
|
|
|
// check if already running
|
|
if (THREAD)
|
|
return;
|
|
|
|
if (!games::iidx::NATIVE_TOUCH) {
|
|
log_warning("poke", "keypad touch emulation requires native touch; disabled");
|
|
return;
|
|
}
|
|
|
|
// create new thread
|
|
THREAD_RUNNING = true;
|
|
THREAD = new std::thread([] {
|
|
// log
|
|
log_info("poke", "enabled");
|
|
|
|
|
|
std::vector<TouchPoint> touch_points;
|
|
std::vector<uint16_t> last_keypad_state = {0, 0};
|
|
|
|
// set variable to false to stop
|
|
while (THREAD_RUNNING) {
|
|
|
|
// clean up touch from last frame
|
|
if (touch_points.size() > 0) {
|
|
inject_native_touch_points(touch_points, false);
|
|
touch_points.clear();
|
|
}
|
|
|
|
for (int unit = 0; unit < 2; unit++) {
|
|
// get keypad state
|
|
auto state = eamuse_get_keypad_state(unit);
|
|
|
|
if (state != 0) {
|
|
// add keys
|
|
for (auto &mapping : KEYPAD_MAPPINGS) {
|
|
if (state & mapping.state) {
|
|
if (last_keypad_state[unit] & mapping.state) {
|
|
// log_warning("poke", "ignoring hold {} {}", unit, mapping.character);
|
|
continue;
|
|
}
|
|
std::string handle = fmt::format("{0}/{1}", unit, mapping.character);
|
|
|
|
auto x_iter = IIDX_KEYPAD_POSITION_X.find(handle);
|
|
auto y_iter = IIDX_KEYPAD_POSITION_Y.find(handle);
|
|
|
|
if (x_iter != IIDX_KEYPAD_POSITION_X.end() && y_iter != IIDX_KEYPAD_POSITION_Y.end()) {
|
|
DWORD touch_id = (DWORD)(0xFFFFFF * unit + mapping.character);
|
|
|
|
float x = x_iter->second / 1920.0;
|
|
float y = y_iter->second / 1080.0;
|
|
if (GRAPHICS_WINDOWED) {
|
|
if (SPICETOUCH_TOUCH_WIDTH <= 0 || SPICETOUCH_TOUCH_HEIGHT <= 0) {
|
|
continue;
|
|
}
|
|
x = SPICETOUCH_TOUCH_X + x * SPICETOUCH_TOUCH_WIDTH;
|
|
y = SPICETOUCH_TOUCH_Y + y * SPICETOUCH_TOUCH_HEIGHT;
|
|
} else {
|
|
x = x_iter->second;
|
|
y = y_iter->second;
|
|
}
|
|
|
|
TouchPoint tp {
|
|
.id = touch_id,
|
|
.x = (LONG)x,
|
|
.y = (LONG)y,
|
|
.mouse = true,
|
|
};
|
|
touch_points.emplace_back(tp);
|
|
// log_warning("poke", "coords: {} {}", to_string(tp.x), to_string(tp.y));
|
|
}
|
|
}
|
|
} // for all keys
|
|
} // if state != 0
|
|
|
|
last_keypad_state[unit] = state;
|
|
|
|
} // for all units
|
|
|
|
if (touch_points.size() > 0) {
|
|
inject_native_touch_points(touch_points, true);
|
|
}
|
|
|
|
// slow down
|
|
std::this_thread::sleep_for(std::chrono::milliseconds(50));
|
|
}
|
|
|
|
if (!touch_points.empty()) {
|
|
inject_native_touch_points(touch_points, false);
|
|
}
|
|
|
|
return nullptr;
|
|
});
|
|
}
|
|
|
|
void disable() {
|
|
if (!THREAD) {
|
|
return;
|
|
}
|
|
|
|
// stop old thread
|
|
THREAD_RUNNING = false;
|
|
THREAD->join();
|
|
|
|
// delete thread
|
|
delete THREAD;
|
|
THREAD = nullptr;
|
|
|
|
// log
|
|
log_info("poke", "disabled");
|
|
}
|
|
}
|