mirror of
https://github.com/spice2x/spice2x.github.io.git
synced 2026-10-03 00:38:14 -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
223 lines
8.1 KiB
C++
223 lines
8.1 KiB
C++
#include "poke.h"
|
|
|
|
#include <atomic>
|
|
#include <chrono>
|
|
#include <optional>
|
|
#include <thread>
|
|
|
|
#include "games/nost/io.h"
|
|
#include "cfg/api.h"
|
|
#include "rawinput/rawinput.h"
|
|
#include "misc/eamuse.h"
|
|
#include "touch/native/inject.h"
|
|
#include "touch/native/nativetouchhook.h"
|
|
#include "util/logging.h"
|
|
|
|
namespace games::nost::poke {
|
|
|
|
static std::thread *THREAD = nullptr;
|
|
static std::atomic<bool> THREAD_RUNNING { false };
|
|
|
|
// positions use game-client pixels, matching the legacy client-sized touch window
|
|
static const std::unordered_map<int, std::pair<LONG, LONG>> NOST_POKE_KEYPAD {
|
|
{EAM_IO_KEYPAD_0, {760, 440}},
|
|
{EAM_IO_KEYPAD_1, {760, 385}},
|
|
{EAM_IO_KEYPAD_2, {820, 385}},
|
|
{EAM_IO_KEYPAD_3, {880, 385}},
|
|
{EAM_IO_KEYPAD_4, {760, 325}},
|
|
{EAM_IO_KEYPAD_5, {820, 325}},
|
|
{EAM_IO_KEYPAD_6, {880, 325}},
|
|
{EAM_IO_KEYPAD_7, {760, 265}},
|
|
{EAM_IO_KEYPAD_8, {820, 265}},
|
|
{EAM_IO_KEYPAD_9, {880, 265}},
|
|
{EAM_IO_KEYPAD_00, {820, 440}}, // erase button
|
|
{EAM_IO_KEYPAD_DECIMAL, {880, 440}} // also erase button
|
|
};
|
|
|
|
static const std::unordered_map<
|
|
games::nost::Buttons::Button, std::pair<LONG, LONG>> NOST_POKE_BUTTONS {
|
|
{games::nost::Buttons::Button::PokeConfirm, {1100, 525}},
|
|
{games::nost::Buttons::Button::PokeBack, {340, 100}},
|
|
{games::nost::Buttons::Button::PokeSong1, {450, 190}},
|
|
{games::nost::Buttons::Button::PokeSong2, {450, 330}},
|
|
{games::nost::Buttons::Button::PokeSong3, {450, 480}},
|
|
{games::nost::Buttons::Button::PokeSong4, {840, 190}},
|
|
{games::nost::Buttons::Button::PokeSong5, {840, 330}},
|
|
{games::nost::Buttons::Button::PokeSong6, {840, 480}},
|
|
{games::nost::Buttons::Button::PokeDifficulty1, {820, 240}},
|
|
{games::nost::Buttons::Button::PokeDifficulty2, {820, 320}},
|
|
{games::nost::Buttons::Button::PokeDifficulty3, {820, 410}},
|
|
{games::nost::Buttons::Button::PokeDifficulty4, {820, 490}},
|
|
};
|
|
|
|
static bool inject_poke_position(POINT position, bool down) {
|
|
return nativetouch::inject::inject_synthetic_touch(position, down);
|
|
}
|
|
|
|
void enable() {
|
|
// check if already running
|
|
if (THREAD) {
|
|
return;
|
|
}
|
|
|
|
if (!nativetouch::is_hooked()) {
|
|
log_warning("poke", "Nostalgia poke requires native touch; disabled");
|
|
return;
|
|
}
|
|
|
|
// create new thread
|
|
THREAD_RUNNING = true;
|
|
THREAD = new std::thread([] {
|
|
const int swipe_anim_total_frames = 6;
|
|
const int swipe_anim_y = 300;
|
|
|
|
const int swipe_next_page_x_begin = 1120;
|
|
const int swipe_next_page_x_end = 1120 - 120;
|
|
|
|
const int swipe_prev_page_x_begin = 280 - 120;
|
|
const int swipe_prev_page_x_end = 280;
|
|
|
|
int next_page_anim_index = -1;
|
|
int prev_page_anim_index = -1;
|
|
bool contact_active = false;
|
|
bool release_pending = false;
|
|
POINT last_position {};
|
|
std::unordered_map<games::nost::Buttons::Button, bool> button_states;
|
|
uint16_t last_keypad_state = 0;
|
|
|
|
// log
|
|
log_info("poke", "enabled");
|
|
|
|
// set variable to false to stop
|
|
while (THREAD_RUNNING) {
|
|
if (release_pending) {
|
|
if (contact_active) {
|
|
inject_poke_position(last_position, false);
|
|
}
|
|
contact_active = false;
|
|
release_pending = false;
|
|
}
|
|
|
|
auto &buttons = games::nost::get_buttons();
|
|
std::optional<POINT> touch_position;
|
|
bool release_after_touch = false;
|
|
|
|
const auto button_triggered = [&](games::nost::Buttons::Button button) {
|
|
const auto pressed =
|
|
GameAPI::Buttons::getState(RI_MGR, buttons.at(button));
|
|
const auto triggered = pressed && !button_states[button];
|
|
button_states[button] = pressed;
|
|
return triggered;
|
|
};
|
|
|
|
std::optional<POINT> triggered_touch_position;
|
|
for (const auto& it : NOST_POKE_BUTTONS) {
|
|
if (button_triggered(it.first) && !triggered_touch_position.has_value()) {
|
|
triggered_touch_position = POINT {
|
|
it.second.first,
|
|
it.second.second,
|
|
};
|
|
}
|
|
}
|
|
|
|
const auto next_triggered =
|
|
button_triggered(games::nost::Buttons::PokeNextPage);
|
|
const auto prev_triggered =
|
|
button_triggered(games::nost::Buttons::PokePrevPage);
|
|
|
|
const auto keypad_state = eamuse_get_keypad_state(0);
|
|
if (!triggered_touch_position.has_value()) {
|
|
for (const auto& it : NOST_POKE_KEYPAD) {
|
|
const auto mask = static_cast<uint16_t>(1 << it.first);
|
|
if ((keypad_state & mask) && !(last_keypad_state & mask)) {
|
|
triggered_touch_position = POINT {
|
|
it.second.first,
|
|
it.second.second,
|
|
};
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
last_keypad_state = keypad_state;
|
|
|
|
if (0 <= next_page_anim_index) {
|
|
const auto delta =
|
|
(swipe_next_page_x_end - swipe_next_page_x_begin)
|
|
* (swipe_anim_total_frames - next_page_anim_index) / swipe_anim_total_frames;
|
|
|
|
touch_position = POINT {
|
|
swipe_next_page_x_begin + delta,
|
|
swipe_anim_y,
|
|
};
|
|
next_page_anim_index--;
|
|
if (next_page_anim_index < 0) {
|
|
release_after_touch = true;
|
|
}
|
|
} else if (0 <= prev_page_anim_index) {
|
|
const auto delta =
|
|
(swipe_prev_page_x_end - swipe_prev_page_x_begin)
|
|
* (swipe_anim_total_frames - prev_page_anim_index) / swipe_anim_total_frames;
|
|
|
|
touch_position = POINT {
|
|
swipe_prev_page_x_begin + delta,
|
|
swipe_anim_y,
|
|
};
|
|
prev_page_anim_index--;
|
|
if (prev_page_anim_index < 0) {
|
|
release_after_touch = true;
|
|
}
|
|
} else {
|
|
touch_position = triggered_touch_position;
|
|
release_after_touch = touch_position.has_value();
|
|
|
|
// start animations for next frame
|
|
if (!touch_position.has_value()) {
|
|
if (next_triggered) {
|
|
next_page_anim_index = swipe_anim_total_frames;
|
|
}
|
|
|
|
if (prev_triggered) {
|
|
prev_page_anim_index = swipe_anim_total_frames;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (touch_position.has_value() &&
|
|
inject_poke_position(*touch_position, true)) {
|
|
contact_active = true;
|
|
last_position = *touch_position;
|
|
}
|
|
if (release_after_touch && contact_active) {
|
|
release_pending = true;
|
|
}
|
|
|
|
// slow down
|
|
std::this_thread::sleep_for(std::chrono::milliseconds(30));
|
|
}
|
|
|
|
if (contact_active) {
|
|
inject_poke_position(last_position, 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");
|
|
}
|
|
}
|