Initial re-upload of spice2x-24-08-24
This commit is contained in:
177
api/modules/analogs.cpp
Normal file
177
api/modules/analogs.cpp
Normal file
@@ -0,0 +1,177 @@
|
||||
#include "analogs.h"
|
||||
#include <functional>
|
||||
#include "external/rapidjson/document.h"
|
||||
#include "misc/eamuse.h"
|
||||
#include "cfg/analog.h"
|
||||
#include "launcher/launcher.h"
|
||||
#include "games/io.h"
|
||||
#include "util/utils.h"
|
||||
|
||||
using namespace std::placeholders;
|
||||
using namespace rapidjson;
|
||||
|
||||
|
||||
namespace api::modules {
|
||||
|
||||
Analogs::Analogs() : Module("analogs") {
|
||||
functions["read"] = std::bind(&Analogs::read, this, _1, _2);
|
||||
functions["write"] = std::bind(&Analogs::write, this, _1, _2);
|
||||
functions["write_reset"] = std::bind(&Analogs::write_reset, this, _1, _2);
|
||||
analogs = games::get_analogs(eamuse_get_game());
|
||||
}
|
||||
|
||||
/**
|
||||
* read()
|
||||
*/
|
||||
void Analogs::read(api::Request &req, Response &res) {
|
||||
|
||||
// check analog cache
|
||||
if (!analogs) {
|
||||
return;
|
||||
}
|
||||
|
||||
// add state for each analog
|
||||
for (auto &analog : *this->analogs) {
|
||||
Value state(kArrayType);
|
||||
Value analog_name(analog.getName().c_str(), res.doc()->GetAllocator());
|
||||
Value analog_state(GameAPI::Analogs::getState(RI_MGR, analog));
|
||||
Value analog_enabled(analog.override_enabled);
|
||||
state.PushBack(analog_name, res.doc()->GetAllocator());
|
||||
state.PushBack(analog_state, res.doc()->GetAllocator());
|
||||
state.PushBack(analog_enabled, res.doc()->GetAllocator());
|
||||
res.add_data(state);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* write([name: str, state: float], ...)
|
||||
*/
|
||||
void Analogs::write(Request &req, Response &res) {
|
||||
|
||||
// check analog cache
|
||||
if (!analogs)
|
||||
return;
|
||||
|
||||
// loop parameters
|
||||
for (Value ¶m : req.params.GetArray()) {
|
||||
|
||||
// check params
|
||||
if (!param.IsArray()) {
|
||||
error(res, "parameters must be arrays");
|
||||
return;
|
||||
}
|
||||
if (param.Size() < 2) {
|
||||
error_params_insufficient(res);
|
||||
continue;
|
||||
}
|
||||
if (!param[0].IsString()) {
|
||||
error_type(res, "name", "string");
|
||||
continue;
|
||||
}
|
||||
if (!param[1].IsFloat() && !param[1].IsInt()) {
|
||||
error_type(res, "state", "float");
|
||||
continue;
|
||||
}
|
||||
|
||||
// get params
|
||||
auto analog_name = param[0].GetString();
|
||||
auto analog_state = param[1].GetFloat();
|
||||
|
||||
// write analog state
|
||||
if (!this->write_analog(analog_name, analog_state)) {
|
||||
error_unknown(res, "analog", analog_name);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* write_reset()
|
||||
* write_reset([name: str], ...)
|
||||
*/
|
||||
void Analogs::write_reset(Request &req, Response &res) {
|
||||
|
||||
// check analog cache
|
||||
if (!analogs)
|
||||
return;
|
||||
|
||||
// get params
|
||||
auto params = req.params.GetArray();
|
||||
|
||||
// write_reset()
|
||||
if (params.Size() == 0) {
|
||||
if (analogs != nullptr) {
|
||||
for (auto &analog : *this->analogs) {
|
||||
analog.override_enabled = false;
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// loop parameters
|
||||
for (Value ¶m : req.params.GetArray()) {
|
||||
|
||||
// check params
|
||||
if (!param.IsArray()) {
|
||||
error(res, "parameters must be arrays");
|
||||
return;
|
||||
}
|
||||
if (param.Size() < 1) {
|
||||
error_params_insufficient(res);
|
||||
continue;
|
||||
}
|
||||
if (!param[0].IsString()) {
|
||||
error_type(res, "name", "string");
|
||||
continue;
|
||||
}
|
||||
|
||||
// get params
|
||||
auto analog_name = param[0].GetString();
|
||||
|
||||
// write analog state
|
||||
if (!this->write_analog_reset(analog_name)) {
|
||||
error_unknown(res, "analog", analog_name);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool Analogs::write_analog(std::string name, float state) {
|
||||
|
||||
// check analog cache
|
||||
if (!this->analogs) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// find analog
|
||||
for (auto &analog : *this->analogs) {
|
||||
if (analog.getName() == name) {
|
||||
analog.override_state = CLAMP(state, 0.f, 1.f);
|
||||
analog.override_enabled = true;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// unknown analog
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Analogs::write_analog_reset(std::string name) {
|
||||
|
||||
// check analog cache
|
||||
if (!analogs) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// find analog
|
||||
for (auto &analog : *this->analogs) {
|
||||
if (analog.getName() == name) {
|
||||
analog.override_enabled = false;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// unknown analog
|
||||
return false;
|
||||
}
|
||||
}
|
||||
28
api/modules/analogs.h
Normal file
28
api/modules/analogs.h
Normal file
@@ -0,0 +1,28 @@
|
||||
#pragma once
|
||||
|
||||
#include <vector>
|
||||
#include "api/module.h"
|
||||
#include "api/request.h"
|
||||
#include "cfg/api.h"
|
||||
|
||||
namespace api::modules {
|
||||
|
||||
class Analogs : public Module {
|
||||
public:
|
||||
Analogs();
|
||||
|
||||
private:
|
||||
|
||||
// state
|
||||
std::vector<Analog> *analogs;
|
||||
|
||||
// function definitions
|
||||
void read(Request &req, Response &res);
|
||||
void write(Request &req, Response &res);
|
||||
void write_reset(Request &req, Response &res);
|
||||
|
||||
// helper
|
||||
bool write_analog(std::string name, float state);
|
||||
bool write_analog_reset(std::string name);
|
||||
};
|
||||
}
|
||||
182
api/modules/buttons.cpp
Normal file
182
api/modules/buttons.cpp
Normal file
@@ -0,0 +1,182 @@
|
||||
#include "buttons.h"
|
||||
#include <functional>
|
||||
#include "external/rapidjson/document.h"
|
||||
#include "misc/eamuse.h"
|
||||
#include "cfg/button.h"
|
||||
#include "launcher/launcher.h"
|
||||
#include "games/io.h"
|
||||
#include "util/utils.h"
|
||||
|
||||
using namespace std::placeholders;
|
||||
using namespace rapidjson;
|
||||
|
||||
|
||||
namespace api::modules {
|
||||
|
||||
Buttons::Buttons() : Module("buttons") {
|
||||
functions["read"] = std::bind(&Buttons::read, this, _1, _2);
|
||||
functions["write"] = std::bind(&Buttons::write, this, _1, _2);
|
||||
functions["write_reset"] = std::bind(&Buttons::write_reset, this, _1, _2);
|
||||
buttons = games::get_buttons(eamuse_get_game());
|
||||
}
|
||||
|
||||
/**
|
||||
* read()
|
||||
*/
|
||||
void Buttons::read(api::Request &req, Response &res) {
|
||||
|
||||
// check button cache
|
||||
if (!this->buttons) {
|
||||
return;
|
||||
}
|
||||
|
||||
// add state for each button
|
||||
for (auto &button : *this->buttons) {
|
||||
Value state(kArrayType);
|
||||
Value button_name(button.getName().c_str(), res.doc()->GetAllocator());
|
||||
Value button_state(GameAPI::Buttons::getVelocity(RI_MGR, button));
|
||||
Value button_enabled(button.override_enabled);
|
||||
state.PushBack(button_name, res.doc()->GetAllocator());
|
||||
state.PushBack(button_state, res.doc()->GetAllocator());
|
||||
state.PushBack(button_enabled, res.doc()->GetAllocator());
|
||||
res.add_data(state);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* write([name: str, state: bool/float], ...)
|
||||
*/
|
||||
void Buttons::write(Request &req, Response &res) {
|
||||
|
||||
// check button cache
|
||||
if (!buttons) {
|
||||
return;
|
||||
}
|
||||
|
||||
// loop parameters
|
||||
for (Value ¶m : req.params.GetArray()) {
|
||||
|
||||
// check params
|
||||
if (!param.IsArray()) {
|
||||
error(res, "parameters must be arrays");
|
||||
return;
|
||||
}
|
||||
if (param.Size() < 2) {
|
||||
error_params_insufficient(res);
|
||||
continue;
|
||||
}
|
||||
if (!param[0].IsString()) {
|
||||
error_type(res, "name", "string");
|
||||
continue;
|
||||
}
|
||||
if (!param[1].IsBool() && !param[1].IsFloat() && !param[1].IsInt()) {
|
||||
error_type(res, "state", "bool or float");
|
||||
continue;
|
||||
}
|
||||
|
||||
// get params
|
||||
auto button_name = param[0].GetString();
|
||||
auto button_state = param[1].IsBool() ? param[1].GetBool() : param[1].GetFloat() > 0;
|
||||
auto button_velocity = param[1].IsFloat() ? param[1].GetFloat() : (button_state ? 1.f : 0.f);
|
||||
|
||||
// write button state
|
||||
if (!this->write_button(button_name, button_velocity)) {
|
||||
error_unknown(res, "button", button_name);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* write_reset()
|
||||
* write_reset([name: str], ...)
|
||||
*/
|
||||
void Buttons::write_reset(Request &req, Response &res) {
|
||||
|
||||
// check button cache
|
||||
if (!this->buttons) {
|
||||
return;
|
||||
}
|
||||
|
||||
// get params
|
||||
auto params = req.params.GetArray();
|
||||
|
||||
// write_reset()
|
||||
if (params.Size() == 0) {
|
||||
if (buttons != nullptr) {
|
||||
for (auto &button : *this->buttons) {
|
||||
button.override_enabled = false;
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// loop parameters
|
||||
for (Value ¶m : req.params.GetArray()) {
|
||||
|
||||
// check params
|
||||
if (!param.IsArray()) {
|
||||
error(res, "parameters must be arrays");
|
||||
return;
|
||||
}
|
||||
if (param.Size() < 1) {
|
||||
error_params_insufficient(res);
|
||||
continue;
|
||||
}
|
||||
if (!param[0].IsString()) {
|
||||
error_type(res, "name", "string");
|
||||
continue;
|
||||
}
|
||||
|
||||
// get params
|
||||
auto button_name = param[0].GetString();
|
||||
|
||||
// write button state
|
||||
if (!this->write_button_reset(button_name)) {
|
||||
error_unknown(res, "button", button_name);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool Buttons::write_button(std::string name, float state) {
|
||||
|
||||
// check button cache
|
||||
if (!this->buttons) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// find button
|
||||
for (auto &button : *this->buttons) {
|
||||
if (button.getName() == name) {
|
||||
button.override_state = state > 0.f ?
|
||||
GameAPI::Buttons::BUTTON_PRESSED : GameAPI::Buttons::BUTTON_NOT_PRESSED;
|
||||
button.override_velocity = CLAMP(state, 0.f, 1.f);
|
||||
button.override_enabled = true;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// unknown button
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Buttons::write_button_reset(std::string name) {
|
||||
|
||||
// check button cache
|
||||
if (!this->buttons) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// find button
|
||||
for (auto &button : *this->buttons) {
|
||||
if (button.getName() == name) {
|
||||
button.override_enabled = false;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// unknown button
|
||||
return false;
|
||||
}
|
||||
}
|
||||
28
api/modules/buttons.h
Normal file
28
api/modules/buttons.h
Normal file
@@ -0,0 +1,28 @@
|
||||
#pragma once
|
||||
|
||||
#include <vector>
|
||||
#include "api/module.h"
|
||||
#include "api/request.h"
|
||||
#include "cfg/api.h"
|
||||
|
||||
namespace api::modules {
|
||||
|
||||
class Buttons : public Module {
|
||||
public:
|
||||
Buttons();
|
||||
|
||||
private:
|
||||
|
||||
// state
|
||||
std::vector<Button> *buttons;
|
||||
|
||||
// function definitions
|
||||
void read(Request &req, Response &res);
|
||||
void write(Request &req, Response &res);
|
||||
void write_reset(Request &req, Response &res);
|
||||
|
||||
// helper
|
||||
bool write_button(std::string name, float state);
|
||||
bool write_button_reset(std::string name);
|
||||
};
|
||||
}
|
||||
82
api/modules/capture.cpp
Normal file
82
api/modules/capture.cpp
Normal file
@@ -0,0 +1,82 @@
|
||||
#include "capture.h"
|
||||
#include <functional>
|
||||
#include "external/rapidjson/document.h"
|
||||
#include "hooks/graphics/graphics.h"
|
||||
#include "util/crypt.h"
|
||||
|
||||
using namespace std::placeholders;
|
||||
using namespace rapidjson;
|
||||
|
||||
namespace api::modules {
|
||||
|
||||
static thread_local std::vector<uint8_t> CAPTURE_BUFFER;
|
||||
|
||||
Capture::Capture() : Module("capture") {
|
||||
functions["get_screens"] = std::bind(&Capture::get_screens, this, _1, _2);
|
||||
functions["get_jpg"] = std::bind(&Capture::get_jpg, this, _1, _2);
|
||||
}
|
||||
|
||||
/**
|
||||
* get_screens()
|
||||
*/
|
||||
void Capture::get_screens(Request &req, Response &res) {
|
||||
|
||||
// aquire screens
|
||||
std::vector<int> screens;
|
||||
graphics_screens_get(screens);
|
||||
|
||||
// add screens to response
|
||||
for (auto &screen : screens) {
|
||||
res.add_data(screen);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* get_jpg([screen=0, quality=70, downscale=0, divide=1])
|
||||
* screen: uint specifying the window
|
||||
* quality: uint in range [0, 100]
|
||||
* reduce: uint for dividing image size
|
||||
*/
|
||||
void Capture::get_jpg(Request &req, Response &res) {
|
||||
CAPTURE_BUFFER.reserve(1024 * 128);
|
||||
|
||||
// settings
|
||||
int screen = 0;
|
||||
int quality = 70;
|
||||
int divide = 1;
|
||||
if (req.params.Size() > 0 && req.params[0].IsUint())
|
||||
screen = req.params[0].GetUint();
|
||||
if (req.params.Size() > 1 && req.params[1].IsUint())
|
||||
quality = req.params[1].GetUint();
|
||||
if (req.params.Size() > 2 && req.params[2].IsUint())
|
||||
divide = req.params[2].GetUint();
|
||||
|
||||
// receive JPEG data
|
||||
uint64_t timestamp = 0;
|
||||
int width = 0;
|
||||
int height = 0;
|
||||
graphics_capture_trigger(screen);
|
||||
bool success = graphics_capture_receive_jpeg(screen, [] (uint8_t byte) {
|
||||
CAPTURE_BUFFER.push_back(byte);
|
||||
}, true, quality, true, divide, ×tamp, &width, &height);
|
||||
if (!success) {
|
||||
return;
|
||||
}
|
||||
|
||||
// encode to base64
|
||||
auto encoded = crypt::base64_encode(
|
||||
CAPTURE_BUFFER.data(),
|
||||
CAPTURE_BUFFER.size());
|
||||
|
||||
// clear buffer
|
||||
CAPTURE_BUFFER.clear();
|
||||
|
||||
// add data to response
|
||||
Value data;
|
||||
data.SetString(encoded.c_str(), encoded.length(), res.doc()->GetAllocator());
|
||||
res.add_data(timestamp);
|
||||
res.add_data(width);
|
||||
res.add_data(height);
|
||||
res.add_data(data);
|
||||
}
|
||||
}
|
||||
18
api/modules/capture.h
Normal file
18
api/modules/capture.h
Normal file
@@ -0,0 +1,18 @@
|
||||
#pragma once
|
||||
|
||||
#include "api/module.h"
|
||||
#include "api/request.h"
|
||||
|
||||
namespace api::modules {
|
||||
|
||||
class Capture : public Module {
|
||||
public:
|
||||
Capture();
|
||||
|
||||
private:
|
||||
|
||||
// function definitions
|
||||
void get_screens(Request &req, Response &res);
|
||||
void get_jpg(Request &req, Response &res);
|
||||
};
|
||||
}
|
||||
53
api/modules/card.cpp
Normal file
53
api/modules/card.cpp
Normal file
@@ -0,0 +1,53 @@
|
||||
#include "card.h"
|
||||
#include <functional>
|
||||
#include "external/rapidjson/document.h"
|
||||
#include "util/logging.h"
|
||||
#include "util/utils.h"
|
||||
#include "misc/eamuse.h"
|
||||
|
||||
using namespace std::placeholders;
|
||||
using namespace rapidjson;
|
||||
|
||||
|
||||
namespace api::modules {
|
||||
|
||||
Card::Card() : Module("card") {
|
||||
functions["insert"] = std::bind(&Card::insert, this, _1, _2);
|
||||
}
|
||||
|
||||
/**
|
||||
* insert(index, card_id)
|
||||
* index: uint in range [0, 1]
|
||||
* card_id: hex string of length 16
|
||||
*/
|
||||
void Card::insert(Request &req, Response &res) {
|
||||
|
||||
// check params
|
||||
if (req.params.Size() < 2)
|
||||
return error_params_insufficient(res);
|
||||
if (!req.params[0].IsUint())
|
||||
return error_type(res, "index", "uint");
|
||||
if (!req.params[1].IsString())
|
||||
return error_type(res, "card_id", "hex string");
|
||||
if (req.params[1].GetStringLength() != 16)
|
||||
return error_size(res, "card_id", 16);
|
||||
|
||||
// get params
|
||||
auto index = req.params[0].GetUint();
|
||||
auto card_hex = req.params[1].GetString();
|
||||
|
||||
// convert to binary
|
||||
uint8_t card_bin[8] {};
|
||||
if (!hex2bin(card_hex, card_bin)) {
|
||||
return error_type(res, "card_id", "hex string");
|
||||
}
|
||||
|
||||
// log
|
||||
if (LOGGING) {
|
||||
log_info("api::card", "inserting card: {}", card_hex);
|
||||
}
|
||||
|
||||
// insert card
|
||||
eamuse_card_insert(index & 1, card_bin);
|
||||
}
|
||||
}
|
||||
17
api/modules/card.h
Normal file
17
api/modules/card.h
Normal file
@@ -0,0 +1,17 @@
|
||||
#pragma once
|
||||
|
||||
#include "api/module.h"
|
||||
#include "api/request.h"
|
||||
|
||||
namespace api::modules {
|
||||
|
||||
class Card : public Module {
|
||||
public:
|
||||
Card();
|
||||
|
||||
private:
|
||||
|
||||
// function definitions
|
||||
void insert(Request &req, Response &res);
|
||||
};
|
||||
}
|
||||
79
api/modules/coin.cpp
Normal file
79
api/modules/coin.cpp
Normal file
@@ -0,0 +1,79 @@
|
||||
#include "coin.h"
|
||||
#include <functional>
|
||||
#include "external/rapidjson/document.h"
|
||||
#include "misc/eamuse.h"
|
||||
|
||||
using namespace std::placeholders;
|
||||
using namespace rapidjson;
|
||||
|
||||
|
||||
namespace api::modules {
|
||||
|
||||
Coin::Coin() : Module("coin") {
|
||||
functions["get"] = std::bind(&Coin::get, this, _1, _2);
|
||||
functions["set"] = std::bind(&Coin::set, this, _1, _2);
|
||||
functions["insert"] = std::bind(&Coin::insert, this, _1, _2);
|
||||
functions["blocker_get"] = std::bind(&Coin::blocker_get, this, _1, _2);
|
||||
}
|
||||
|
||||
/**
|
||||
* get()
|
||||
*/
|
||||
void Coin::get(api::Request &req, api::Response &res) {
|
||||
|
||||
// get coin stock
|
||||
auto coin_stock = eamuse_coin_get_stock();
|
||||
|
||||
// insert value
|
||||
Value coin_stock_val(coin_stock);
|
||||
res.add_data(coin_stock_val);
|
||||
}
|
||||
|
||||
/**
|
||||
* set(amount: int)
|
||||
*/
|
||||
void Coin::set(api::Request &req, api::Response &res) {
|
||||
|
||||
// check params
|
||||
if (req.params.Size() < 1)
|
||||
return error_params_insufficient(res);
|
||||
if (!req.params[0].IsInt())
|
||||
return error_type(res, "amount", "int");
|
||||
|
||||
// set coin stock
|
||||
eamuse_coin_set_stock(req.params[0].GetInt());
|
||||
}
|
||||
|
||||
/**
|
||||
* insert()
|
||||
* insert(amount: int)
|
||||
*/
|
||||
void Coin::insert(api::Request &req, api::Response &res) {
|
||||
|
||||
// insert()
|
||||
if (req.params.Size() == 0) {
|
||||
eamuse_coin_add();
|
||||
return;
|
||||
}
|
||||
|
||||
// check params
|
||||
if (!req.params[0].IsInt())
|
||||
return error_type(res, "amount", "int");
|
||||
|
||||
// add to coin stock
|
||||
eamuse_coin_set_stock(eamuse_coin_get_stock() + std::max(0, req.params[0].GetInt()));
|
||||
}
|
||||
|
||||
/*
|
||||
* blocker_get()
|
||||
*/
|
||||
void Coin::blocker_get(api::Request &req, api::Response &res) {
|
||||
|
||||
// get block status
|
||||
auto block_status = eamuse_coin_get_block();
|
||||
|
||||
// insert value
|
||||
Value block_val(block_status);
|
||||
res.add_data(block_val);
|
||||
}
|
||||
}
|
||||
20
api/modules/coin.h
Normal file
20
api/modules/coin.h
Normal file
@@ -0,0 +1,20 @@
|
||||
#pragma once
|
||||
|
||||
#include "api/module.h"
|
||||
#include "api/request.h"
|
||||
|
||||
namespace api::modules {
|
||||
|
||||
class Coin : public Module {
|
||||
public:
|
||||
Coin();
|
||||
|
||||
private:
|
||||
|
||||
// function definitions
|
||||
void get(Request &req, Response &res);
|
||||
void set(Request &req, Response &res);
|
||||
void insert(Request &req, Response &res);
|
||||
void blocker_get(Request &req, Response &res);
|
||||
};
|
||||
}
|
||||
152
api/modules/control.cpp
Normal file
152
api/modules/control.cpp
Normal file
@@ -0,0 +1,152 @@
|
||||
#include "control.h"
|
||||
|
||||
#include <csignal>
|
||||
#include <functional>
|
||||
|
||||
#include "external/rapidjson/document.h"
|
||||
#include "launcher/shutdown.h"
|
||||
#include "util/logging.h"
|
||||
#include "util/crypt.h"
|
||||
#include "util/utils.h"
|
||||
|
||||
using namespace std::placeholders;
|
||||
using namespace rapidjson;
|
||||
|
||||
namespace api::modules {
|
||||
|
||||
struct SignalMapping {
|
||||
int signum;
|
||||
const char* name;
|
||||
};
|
||||
static SignalMapping SIGNAL_MAPPINGS[] = {
|
||||
{ SIGABRT, "SIGABRT" },
|
||||
{ SIGFPE, "SIGFPE" },
|
||||
{ SIGILL, "SIGILL" },
|
||||
{ SIGINT, "SIGINT" },
|
||||
{ SIGSEGV, "SIGSEGV" },
|
||||
{ SIGTERM, "SIGTERM" },
|
||||
};
|
||||
|
||||
Control::Control() : Module("control", true) {
|
||||
functions["raise"] = std::bind(&Control::raise, this, _1, _2);
|
||||
functions["exit"] = std::bind(&Control::exit, this, _1, _2);
|
||||
functions["restart"] = std::bind(&Control::restart, this, _1, _2);
|
||||
functions["session_refresh"] = std::bind(&Control::session_refresh, this, _1, _2);
|
||||
functions["shutdown"] = std::bind(&Control::shutdown, this, _1, _2);
|
||||
functions["reboot"] = std::bind(&Control::reboot, this, _1, _2);
|
||||
}
|
||||
|
||||
/**
|
||||
* raise(signal: str)
|
||||
*/
|
||||
void Control::raise(Request &req, Response &res) {
|
||||
|
||||
// check args
|
||||
if (req.params.Size() < 1)
|
||||
return error_params_insufficient(res);
|
||||
if (!req.params[0].IsString())
|
||||
return error_type(res, "signal", "string");
|
||||
|
||||
// get signal
|
||||
auto signal_str = req.params[0].GetString();
|
||||
int signal_val = -1;
|
||||
for (auto mapping : SIGNAL_MAPPINGS) {
|
||||
if (_stricmp(mapping.name, signal_str) == 0) {
|
||||
signal_val = mapping.signum;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// check if not found
|
||||
if (signal_val < 0)
|
||||
return error_unknown(res, "signal", signal_str);
|
||||
|
||||
// raise signal
|
||||
if (::raise(signal_val))
|
||||
return error(res, "Failed to raise signo " + to_string(signal_val));
|
||||
}
|
||||
|
||||
/**
|
||||
* exit()
|
||||
* exit(code: int)
|
||||
*/
|
||||
void Control::exit(Request &req, Response &res) {
|
||||
|
||||
// exit()
|
||||
if (req.params.Size() == 0) {
|
||||
launcher::shutdown();
|
||||
}
|
||||
|
||||
// check code
|
||||
if (!req.params[0].IsInt())
|
||||
return error_type(res, "code", "int");
|
||||
|
||||
// exit
|
||||
launcher::shutdown(req.params[0].GetInt());
|
||||
}
|
||||
|
||||
/**
|
||||
* restart()
|
||||
*/
|
||||
void Control::restart(Request &req, Response &res) {
|
||||
|
||||
// restart launcher
|
||||
launcher::restart();
|
||||
}
|
||||
|
||||
/**
|
||||
* session_refresh()
|
||||
*/
|
||||
void Control::session_refresh(Request &req, Response &res) {
|
||||
|
||||
// generate new password
|
||||
uint8_t password_bin[128];
|
||||
crypt::random_bytes(password_bin, std::size(password_bin));
|
||||
std::string password = bin2hex(&password_bin[0], std::size(password_bin));
|
||||
|
||||
// add to response
|
||||
Value password_val(password.c_str(), res.doc()->GetAllocator());
|
||||
res.add_data(password_val);
|
||||
|
||||
// change password
|
||||
res.password_change(password);
|
||||
}
|
||||
|
||||
/**
|
||||
* shutdown()
|
||||
*/
|
||||
void Control::shutdown(Request &req, Response &res) {
|
||||
|
||||
// acquire privileges
|
||||
if (!acquire_shutdown_privs())
|
||||
return error(res, "Unable to acquire shutdown privileges");
|
||||
|
||||
// exit windows
|
||||
if (!ExitWindowsEx(EWX_SHUTDOWN | EWX_HYBRID_SHUTDOWN | EWX_FORCE,
|
||||
SHTDN_REASON_MAJOR_APPLICATION |
|
||||
SHTDN_REASON_MINOR_MAINTENANCE))
|
||||
return error(res, "Unable to shutdown system");
|
||||
|
||||
// terminate this process
|
||||
launcher::shutdown(0);
|
||||
}
|
||||
|
||||
/**
|
||||
* reboot()
|
||||
*/
|
||||
void Control::reboot(Request &req, Response &res) {
|
||||
|
||||
// acquire privileges
|
||||
if (!acquire_shutdown_privs())
|
||||
return error(res, "Unable to acquire shutdown privileges");
|
||||
|
||||
// exit windows
|
||||
if (!ExitWindowsEx(EWX_REBOOT | EWX_FORCE,
|
||||
SHTDN_REASON_MAJOR_APPLICATION |
|
||||
SHTDN_REASON_MINOR_MAINTENANCE))
|
||||
return error(res, "Unable to reboot system");
|
||||
|
||||
// terminate this process
|
||||
launcher::shutdown(0);
|
||||
}
|
||||
}
|
||||
22
api/modules/control.h
Normal file
22
api/modules/control.h
Normal file
@@ -0,0 +1,22 @@
|
||||
#pragma once
|
||||
|
||||
#include "api/module.h"
|
||||
#include "api/request.h"
|
||||
|
||||
namespace api::modules {
|
||||
|
||||
class Control : public Module {
|
||||
public:
|
||||
Control();
|
||||
|
||||
private:
|
||||
|
||||
// function definitions
|
||||
void raise(Request &req, Response &res);
|
||||
void exit(Request &req, Response &res);
|
||||
void restart(Request &req, Response &res);
|
||||
void session_refresh(Request &req, Response &res);
|
||||
void shutdown(Request &req, Response &res);
|
||||
void reboot(Request &req, Response &res);
|
||||
};
|
||||
}
|
||||
91
api/modules/drs.cpp
Normal file
91
api/modules/drs.cpp
Normal file
@@ -0,0 +1,91 @@
|
||||
#include "drs.h"
|
||||
#include <functional>
|
||||
#include "external/rapidjson/document.h"
|
||||
#include "games/drs/drs.h"
|
||||
|
||||
using namespace std::placeholders;
|
||||
using namespace rapidjson;
|
||||
|
||||
namespace api::modules {
|
||||
|
||||
DRS::DRS() : Module("drs") {
|
||||
functions["tapeled_get"] = std::bind(&DRS::tapeled_get, this, _1, _2);
|
||||
functions["touch_set"] = std::bind(&DRS::touch_set, this, _1, _2);
|
||||
}
|
||||
|
||||
/**
|
||||
* ticker_get()
|
||||
*/
|
||||
void DRS::tapeled_get(Request &req, Response &res) {
|
||||
|
||||
// copy data to array
|
||||
Value tapeled(kArrayType);
|
||||
const size_t tape_len = sizeof(games::drs::DRS_TAPELED);
|
||||
const uint8_t *tape_raw = (uint8_t*) games::drs::DRS_TAPELED;
|
||||
tapeled.Reserve(tape_len, res.doc()->GetAllocator());
|
||||
for (size_t i = 0; i < tape_len; i++) {
|
||||
tapeled.PushBack(tape_raw[i], res.doc()->GetAllocator());
|
||||
}
|
||||
|
||||
// add to response
|
||||
res.add_data(tapeled);
|
||||
}
|
||||
|
||||
void DRS::touch_set(Request &req, Response &res) {
|
||||
|
||||
// get all touch points
|
||||
games::drs::drs_touch_t touches[16];
|
||||
size_t i = 0;
|
||||
for (Value ¶m : req.params.GetArray()) {
|
||||
|
||||
// check params
|
||||
if (param.Size() < 6) {
|
||||
error_params_insufficient(res);
|
||||
continue;
|
||||
}
|
||||
if (!param[0].IsUint()) {
|
||||
error_type(res, "type", "uint");
|
||||
continue;
|
||||
}
|
||||
if (!param[1].IsUint()) {
|
||||
error_type(res, "id", "uint");
|
||||
continue;
|
||||
}
|
||||
if (!param[2].IsDouble()) {
|
||||
error_type(res, "x", "double");
|
||||
continue;
|
||||
}
|
||||
if (!param[3].IsDouble()) {
|
||||
error_type(res, "y", "double");
|
||||
continue;
|
||||
}
|
||||
if (!param[4].IsDouble()) {
|
||||
error_type(res, "width", "double");
|
||||
continue;
|
||||
}
|
||||
if (!param[5].IsDouble()) {
|
||||
error_type(res, "height", "double");
|
||||
continue;
|
||||
}
|
||||
|
||||
// get params
|
||||
auto touch_type = param[0].GetUint();
|
||||
auto touch_id = param[1].GetUint();
|
||||
auto touch_x = param[2].GetDouble();
|
||||
auto touch_y = param[3].GetDouble();
|
||||
auto width = param[4].GetDouble();
|
||||
auto height = param[5].GetDouble();
|
||||
|
||||
touches[i].type = touch_type;
|
||||
touches[i].id = touch_id;
|
||||
touches[i].x = touch_x;
|
||||
touches[i].y = touch_y;
|
||||
touches[i].width = width;
|
||||
touches[i].height = height;
|
||||
i++;
|
||||
}
|
||||
|
||||
// apply touch points
|
||||
games::drs::fire_touches(touches, i);
|
||||
}
|
||||
}
|
||||
19
api/modules/drs.h
Normal file
19
api/modules/drs.h
Normal file
@@ -0,0 +1,19 @@
|
||||
#pragma once
|
||||
|
||||
#include <vector>
|
||||
#include "api/module.h"
|
||||
#include "api/request.h"
|
||||
|
||||
namespace api::modules {
|
||||
|
||||
class DRS : public Module {
|
||||
public:
|
||||
DRS();
|
||||
|
||||
private:
|
||||
|
||||
// function definitions
|
||||
void tapeled_get(Request &req, Response &res);
|
||||
void touch_set(Request &req, Response &res);
|
||||
};
|
||||
}
|
||||
72
api/modules/iidx.cpp
Normal file
72
api/modules/iidx.cpp
Normal file
@@ -0,0 +1,72 @@
|
||||
#include "iidx.h"
|
||||
#include <functional>
|
||||
#include <vector>
|
||||
#include "games/iidx/iidx.h"
|
||||
#include "external/rapidjson/document.h"
|
||||
|
||||
using namespace std::placeholders;
|
||||
using namespace rapidjson;
|
||||
|
||||
|
||||
namespace api::modules {
|
||||
|
||||
// settings
|
||||
static const size_t TICKER_SIZE = 9;
|
||||
|
||||
IIDX::IIDX() : Module("iidx") {
|
||||
functions["ticker_get"] = std::bind(&IIDX::ticker_get, this, _1, _2);
|
||||
functions["ticker_set"] = std::bind(&IIDX::ticker_set, this, _1, _2);
|
||||
functions["ticker_reset"] = std::bind(&IIDX::ticker_reset, this, _1, _2);
|
||||
}
|
||||
|
||||
/**
|
||||
* ticker_get()
|
||||
*/
|
||||
void IIDX::ticker_get(api::Request &req, Response &res) {
|
||||
|
||||
// get led ticker
|
||||
games::iidx::IIDX_LED_TICKER_LOCK.lock();
|
||||
Value led_ticker(StringRef(games::iidx::IIDXIO_LED_TICKER, TICKER_SIZE), res.doc()->GetAllocator());
|
||||
games::iidx::IIDX_LED_TICKER_LOCK.unlock();
|
||||
|
||||
// add to response
|
||||
res.add_data(led_ticker);
|
||||
}
|
||||
|
||||
/**
|
||||
* ticker_set(text: str)
|
||||
*/
|
||||
void IIDX::ticker_set(api::Request &req, api::Response &res) {
|
||||
|
||||
// check param
|
||||
if (req.params.Size() < 1)
|
||||
return error_params_insufficient(res);
|
||||
if (!req.params[0].IsString())
|
||||
return error_type(res, "text", "str");
|
||||
|
||||
// get param
|
||||
auto text = req.params[0].GetString();
|
||||
auto text_len = req.params[0].GetStringLength();
|
||||
|
||||
// lock
|
||||
std::lock_guard<std::mutex> ticker_lock(games::iidx::IIDX_LED_TICKER_LOCK);
|
||||
|
||||
// set to read only
|
||||
games::iidx::IIDXIO_LED_TICKER_READONLY = true;
|
||||
|
||||
// set led ticker
|
||||
memset(games::iidx::IIDXIO_LED_TICKER, ' ', TICKER_SIZE);
|
||||
for (size_t i = 0; i < TICKER_SIZE && i < text_len; i++) {
|
||||
games::iidx::IIDXIO_LED_TICKER[i] = text[i];
|
||||
}
|
||||
}
|
||||
|
||||
void IIDX::ticker_reset(api::Request &req, api::Response &res) {
|
||||
|
||||
// lock
|
||||
std::lock_guard<std::mutex> ticker_lock(games::iidx::IIDX_LED_TICKER_LOCK);
|
||||
|
||||
// disable read only
|
||||
games::iidx::IIDXIO_LED_TICKER_READONLY = false;
|
||||
}
|
||||
}
|
||||
19
api/modules/iidx.h
Normal file
19
api/modules/iidx.h
Normal file
@@ -0,0 +1,19 @@
|
||||
#pragma once
|
||||
|
||||
#include "api/module.h"
|
||||
#include "api/request.h"
|
||||
|
||||
namespace api::modules {
|
||||
|
||||
class IIDX : public Module {
|
||||
public:
|
||||
IIDX();
|
||||
|
||||
private:
|
||||
|
||||
// function definitions
|
||||
void ticker_get(Request &req, Response &res);
|
||||
void ticker_set(Request &req, Response &res);
|
||||
void ticker_reset(Request &req, Response &res);
|
||||
};
|
||||
}
|
||||
98
api/modules/info.cpp
Normal file
98
api/modules/info.cpp
Normal file
@@ -0,0 +1,98 @@
|
||||
#include "info.h"
|
||||
#include <functional>
|
||||
#include <iomanip>
|
||||
#include "external/rapidjson/document.h"
|
||||
#include "avs/game.h"
|
||||
#include "avs/ea3.h"
|
||||
#include "util/logging.h"
|
||||
#include "util/utils.h"
|
||||
#include "util/memutils.h"
|
||||
#include "build/defs.h"
|
||||
|
||||
using namespace std::placeholders;
|
||||
using namespace rapidjson;
|
||||
|
||||
|
||||
namespace api::modules {
|
||||
|
||||
Info::Info() : Module("info") {
|
||||
functions["avs"] = std::bind(&Info::avs, this, _1, _2);
|
||||
functions["launcher"] = std::bind(&Info::launcher, this, _1, _2);
|
||||
functions["memory"] = std::bind(&Info::memory, this, _1, _2);
|
||||
}
|
||||
|
||||
/**
|
||||
* avs()
|
||||
*/
|
||||
void Info::avs(Request &req, Response &res) {
|
||||
|
||||
// get allocator
|
||||
auto &alloc = res.doc()->GetAllocator();
|
||||
|
||||
// build info object
|
||||
Value info(kObjectType);
|
||||
info.AddMember("model", StringRef(avs::game::MODEL, 3), alloc);
|
||||
info.AddMember("dest", StringRef(avs::game::DEST, 1), alloc);
|
||||
info.AddMember("spec", StringRef(avs::game::SPEC, 1), alloc);
|
||||
info.AddMember("rev", StringRef(avs::game::REV, 1), alloc);
|
||||
info.AddMember("ext", StringRef(avs::game::EXT, 10), alloc);
|
||||
info.AddMember("services", StringRef(avs::ea3::EA3_BOOT_URL.c_str()), alloc);
|
||||
|
||||
// add info object
|
||||
res.add_data(info);
|
||||
}
|
||||
|
||||
/**
|
||||
* launcher()
|
||||
*/
|
||||
void Info::launcher(Request &req, Response &res) {
|
||||
|
||||
// get allocator
|
||||
auto &alloc = res.doc()->GetAllocator();
|
||||
|
||||
// build args
|
||||
Value args(kArrayType);
|
||||
for (int count = 0; count < LAUNCHER_ARGC; count++) {
|
||||
auto arg = LAUNCHER_ARGV[count];
|
||||
args.PushBack(StringRef(arg), alloc);
|
||||
}
|
||||
|
||||
// get system time
|
||||
auto t_now = std::time(nullptr);
|
||||
auto tm_now = *std::gmtime(&t_now);
|
||||
auto tm_str = to_string(std::put_time(&tm_now, "%Y-%m-%dT%H:%M:%SZ"));
|
||||
Value system_time(tm_str.c_str(), alloc);
|
||||
|
||||
// build info object
|
||||
Value info(kObjectType);
|
||||
info.AddMember("version", StringRef(VERSION_STRING), alloc);
|
||||
info.AddMember("compile_date", StringRef(__DATE__), alloc);
|
||||
info.AddMember("compile_time", StringRef(__TIME__), alloc);
|
||||
info.AddMember("system_time", system_time, alloc);
|
||||
info.AddMember("args", args, alloc);
|
||||
|
||||
// add info object
|
||||
res.add_data(info);
|
||||
}
|
||||
|
||||
/**
|
||||
* memory()
|
||||
*/
|
||||
void Info::memory(Request &req, Response &res) {
|
||||
|
||||
// get allocator
|
||||
auto &alloc = res.doc()->GetAllocator();
|
||||
|
||||
// build info object
|
||||
Value info(kObjectType);
|
||||
info.AddMember("mem_total", memutils::mem_total(), alloc);
|
||||
info.AddMember("mem_total_used", memutils::mem_total_used(), alloc);
|
||||
info.AddMember("mem_used", memutils::mem_used(), alloc);
|
||||
info.AddMember("vmem_total", memutils::vmem_total(), alloc);
|
||||
info.AddMember("vmem_total_used", memutils::vmem_total_used(), alloc);
|
||||
info.AddMember("vmem_used", memutils::vmem_used(), alloc);
|
||||
|
||||
// add info object
|
||||
res.add_data(info);
|
||||
}
|
||||
}
|
||||
19
api/modules/info.h
Normal file
19
api/modules/info.h
Normal file
@@ -0,0 +1,19 @@
|
||||
#pragma once
|
||||
|
||||
#include "api/module.h"
|
||||
#include "api/request.h"
|
||||
|
||||
namespace api::modules {
|
||||
|
||||
class Info : public Module {
|
||||
public:
|
||||
Info();
|
||||
|
||||
private:
|
||||
|
||||
// function definitions
|
||||
void avs(Request &req, Response &res);
|
||||
void launcher(Request &req, Response &res);
|
||||
void memory(Request &req, Response &res);
|
||||
};
|
||||
}
|
||||
176
api/modules/keypads.cpp
Normal file
176
api/modules/keypads.cpp
Normal file
@@ -0,0 +1,176 @@
|
||||
#include "keypads.h"
|
||||
|
||||
#include <functional>
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
#include "avs/game.h"
|
||||
#include "external/rapidjson/document.h"
|
||||
#include "misc/eamuse.h"
|
||||
|
||||
using namespace std::placeholders;
|
||||
using namespace rapidjson;
|
||||
|
||||
namespace api::modules {
|
||||
|
||||
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 },
|
||||
{ 'D', 1 << EAM_IO_KEYPAD_DECIMAL },
|
||||
};
|
||||
|
||||
Keypads::Keypads() : Module("keypads") {
|
||||
functions["write"] = std::bind(&Keypads::write, this, _1, _2);
|
||||
functions["set"] = std::bind(&Keypads::set, this, _1, _2);
|
||||
functions["get"] = std::bind(&Keypads::get, this, _1, _2);
|
||||
}
|
||||
|
||||
/**
|
||||
* write(keypad: uint, input: str)
|
||||
*/
|
||||
void Keypads::write(Request &req, Response &res) {
|
||||
|
||||
// check params
|
||||
if (req.params.Size() < 2) {
|
||||
return error_params_insufficient(res);
|
||||
}
|
||||
if (!req.params[0].IsUint()) {
|
||||
return error_type(res, "keypad", "uint");
|
||||
}
|
||||
if (!req.params[1].IsString()) {
|
||||
return error_type(res, "input", "string");
|
||||
}
|
||||
|
||||
// get params
|
||||
auto keypad = req.params[0].GetUint();
|
||||
auto input = std::string(req.params[1].GetString());
|
||||
|
||||
// process all chars
|
||||
for (auto c : input) {
|
||||
uint16_t state = 0;
|
||||
|
||||
// find mapping
|
||||
bool mapping_found = false;
|
||||
for (auto &mapping : KEYPAD_MAPPINGS) {
|
||||
if (_strnicmp(&mapping.character, &c, 1) == 0) {
|
||||
state |= mapping.state;
|
||||
mapping_found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// check for error
|
||||
if (!mapping_found) {
|
||||
return error_unknown(res, "char", std::string("") + c);
|
||||
}
|
||||
|
||||
/*
|
||||
* Write input to keypad.
|
||||
* We try to make sure it was accepted by waiting a bit more than two frames.
|
||||
*/
|
||||
DWORD sleep_time = 70;
|
||||
if (avs::game::is_model("MDX")) {
|
||||
|
||||
// cuz fuck DDR
|
||||
sleep_time = 150;
|
||||
}
|
||||
|
||||
// set
|
||||
eamuse_set_keypad_overrides(keypad, state);
|
||||
Sleep(sleep_time);
|
||||
|
||||
// unset
|
||||
eamuse_set_keypad_overrides(keypad, 0);
|
||||
Sleep(sleep_time);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* set(keypad: uint, key: char, ...)
|
||||
*/
|
||||
void Keypads::set(Request &req, Response &res) {
|
||||
|
||||
// check keypad
|
||||
if (req.params.Size() < 1) {
|
||||
return error_params_insufficient(res);
|
||||
}
|
||||
if (!req.params[0].IsUint()) {
|
||||
return error_type(res, "keypad", "uint");
|
||||
}
|
||||
auto keypad = req.params[0].GetUint();
|
||||
|
||||
// iterate params
|
||||
uint16_t state = 0;
|
||||
auto params = req.params.GetArray();
|
||||
for (size_t i = 1; i < params.Size(); i++) {
|
||||
auto ¶m = params[i];
|
||||
|
||||
// check key
|
||||
if (!param.IsString()) {
|
||||
error_type(res, "key", "char");
|
||||
}
|
||||
if (param.GetStringLength() < 1) {
|
||||
error_size(res, "key", 1);
|
||||
}
|
||||
|
||||
// find mapping
|
||||
auto key = param.GetString();
|
||||
bool mapping_found = false;
|
||||
for (auto &mapping : KEYPAD_MAPPINGS) {
|
||||
if (_strnicmp(&mapping.character, key, 1) == 0) {
|
||||
state |= mapping.state;
|
||||
mapping_found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// check for error
|
||||
if (!mapping_found) {
|
||||
return error_unknown(res, "key", key);
|
||||
}
|
||||
}
|
||||
|
||||
// set keypad state
|
||||
eamuse_set_keypad_overrides(keypad, state);
|
||||
}
|
||||
|
||||
/**
|
||||
* get(keypad: uint)
|
||||
*/
|
||||
void Keypads::get(Request &req, Response &res) {
|
||||
|
||||
// check keypad
|
||||
if (req.params.Size() < 1) {
|
||||
return error_params_insufficient(res);
|
||||
}
|
||||
if (!req.params[0].IsUint()) {
|
||||
return error_type(res, "keypad", "uint");
|
||||
}
|
||||
auto keypad = req.params[0].GetUint();
|
||||
|
||||
// get keypad state
|
||||
auto state = eamuse_get_keypad_state(keypad);
|
||||
|
||||
// add keys to response
|
||||
for (auto &mapping : KEYPAD_MAPPINGS) {
|
||||
if (state & mapping.state) {
|
||||
Value val(&mapping.character, 1);
|
||||
res.add_data(val);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
19
api/modules/keypads.h
Normal file
19
api/modules/keypads.h
Normal file
@@ -0,0 +1,19 @@
|
||||
#pragma once
|
||||
|
||||
#include "api/module.h"
|
||||
#include "api/request.h"
|
||||
|
||||
namespace api::modules {
|
||||
|
||||
class Keypads : public Module {
|
||||
public:
|
||||
Keypads();
|
||||
|
||||
private:
|
||||
|
||||
// function definitions
|
||||
void write(Request &req, Response &res);
|
||||
void set(Request &req, Response &res);
|
||||
void get(Request &req, Response &res);
|
||||
};
|
||||
}
|
||||
36
api/modules/lcd.cpp
Normal file
36
api/modules/lcd.cpp
Normal file
@@ -0,0 +1,36 @@
|
||||
#include "lcd.h"
|
||||
#include "external/rapidjson/document.h"
|
||||
#include "games/shared/lcdhandle.h"
|
||||
|
||||
using namespace std::placeholders;
|
||||
using namespace rapidjson;
|
||||
|
||||
namespace api::modules {
|
||||
|
||||
LCD::LCD() : Module("lcd") {
|
||||
functions["info"] = std::bind(&LCD::info, this, _1, _2);
|
||||
}
|
||||
|
||||
/*
|
||||
* info()
|
||||
*/
|
||||
void LCD::info(Request &req, Response &res) {
|
||||
|
||||
// get allocator
|
||||
auto &alloc = res.doc()->GetAllocator();
|
||||
|
||||
// build info object
|
||||
Value info(kObjectType);
|
||||
info.AddMember("enabled", games::shared::LCD_ENABLED, alloc);
|
||||
info.AddMember("csm", StringRef(games::shared::LCD_CSM.c_str()), alloc);
|
||||
info.AddMember("bri", games::shared::LCD_BRI, alloc);
|
||||
info.AddMember("con", games::shared::LCD_CON, alloc);
|
||||
info.AddMember("bl", games::shared::LCD_BL, alloc);
|
||||
info.AddMember("red", games::shared::LCD_RED, alloc);
|
||||
info.AddMember("green", games::shared::LCD_GREEN, alloc);
|
||||
info.AddMember("blue", games::shared::LCD_BLUE, alloc);
|
||||
|
||||
// add info object
|
||||
res.add_data(info);
|
||||
}
|
||||
}
|
||||
17
api/modules/lcd.h
Normal file
17
api/modules/lcd.h
Normal file
@@ -0,0 +1,17 @@
|
||||
#pragma once
|
||||
|
||||
#include "api/module.h"
|
||||
#include "api/request.h"
|
||||
|
||||
namespace api::modules {
|
||||
|
||||
class LCD : public Module {
|
||||
public:
|
||||
LCD();
|
||||
|
||||
private:
|
||||
|
||||
// function definitions
|
||||
void info(Request &req, Response &res);
|
||||
};
|
||||
}
|
||||
191
api/modules/lights.cpp
Normal file
191
api/modules/lights.cpp
Normal file
@@ -0,0 +1,191 @@
|
||||
#include "lights.h"
|
||||
#include <functional>
|
||||
#include <cfg/configurator.h>
|
||||
|
||||
#include "external/rapidjson/document.h"
|
||||
#include "misc/eamuse.h"
|
||||
#include "cfg/light.h"
|
||||
#include "launcher/launcher.h"
|
||||
#include "games/io.h"
|
||||
#include "util/utils.h"
|
||||
|
||||
using namespace std::placeholders;
|
||||
using namespace rapidjson;
|
||||
|
||||
|
||||
namespace api::modules {
|
||||
|
||||
Lights::Lights() : Module("lights") {
|
||||
functions["read"] = std::bind(&Lights::read, this, _1, _2);
|
||||
functions["write"] = std::bind(&Lights::write, this, _1, _2);
|
||||
functions["write_reset"] = std::bind(&Lights::write_reset, this, _1, _2);
|
||||
lights = games::get_lights(eamuse_get_game());
|
||||
}
|
||||
|
||||
/**
|
||||
* read()
|
||||
*/
|
||||
void Lights::read(api::Request &req, Response &res) {
|
||||
|
||||
// check light cache
|
||||
if (!this->lights) {
|
||||
return;
|
||||
}
|
||||
|
||||
// add state for each light
|
||||
for (auto &light : *this->lights) {
|
||||
Value state(kArrayType);
|
||||
Value light_name(light.getName().c_str(), res.doc()->GetAllocator());
|
||||
Value light_state(GameAPI::Lights::readLight(RI_MGR, light));
|
||||
Value light_enabled(light.override_enabled);
|
||||
state.PushBack(light_name, res.doc()->GetAllocator());
|
||||
state.PushBack(light_state, res.doc()->GetAllocator());
|
||||
state.PushBack(light_enabled, res.doc()->GetAllocator());
|
||||
res.add_data(state);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* write([name: str, state: float], ...)
|
||||
*/
|
||||
void Lights::write(Request &req, Response &res) {
|
||||
|
||||
// check light cache
|
||||
if (!this->lights) {
|
||||
return;
|
||||
}
|
||||
|
||||
// loop parameters
|
||||
for (Value ¶m : req.params.GetArray()) {
|
||||
|
||||
// check params
|
||||
if (!param.IsArray()) {
|
||||
error(res, "parameters must be arrays");
|
||||
return;
|
||||
}
|
||||
if (param.Size() < 2) {
|
||||
error_params_insufficient(res);
|
||||
continue;
|
||||
}
|
||||
if (!param[0].IsString()) {
|
||||
error_type(res, "name", "string");
|
||||
continue;
|
||||
}
|
||||
if (!param[1].IsFloat() && !param[1].IsInt()) {
|
||||
error_type(res, "state", "float");
|
||||
continue;
|
||||
}
|
||||
|
||||
// get params
|
||||
auto light_name = param[0].GetString();
|
||||
auto light_state = param[1].GetFloat();
|
||||
|
||||
// write light state
|
||||
if (!this->write_light(light_name, light_state)) {
|
||||
error_unknown(res, "light", light_name);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* write_reset()
|
||||
* write_reset([name: str], ...)
|
||||
*/
|
||||
void Lights::write_reset(Request &req, Response &res) {
|
||||
|
||||
// check light cache
|
||||
if (!this->lights) {
|
||||
return;
|
||||
}
|
||||
|
||||
// get params
|
||||
auto params = req.params.GetArray();
|
||||
|
||||
// write_reset()
|
||||
if (params.Size() == 0) {
|
||||
if (lights != nullptr) {
|
||||
for (auto &light : *this->lights) {
|
||||
if (light.override_enabled) {
|
||||
if (cfg::CONFIGURATOR_STANDALONE) {
|
||||
GameAPI::Lights::writeLight(RI_MGR, light, light.last_state);
|
||||
}
|
||||
light.override_enabled = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// loop parameters
|
||||
for (Value ¶m : req.params.GetArray()) {
|
||||
|
||||
// check params
|
||||
if (!param.IsArray()) {
|
||||
error(res, "parameters must be arrays");
|
||||
return;
|
||||
}
|
||||
if (param.Size() < 1) {
|
||||
error_params_insufficient(res);
|
||||
continue;
|
||||
}
|
||||
if (!param[0].IsString()) {
|
||||
error_type(res, "name", "string");
|
||||
continue;
|
||||
}
|
||||
|
||||
// get params
|
||||
auto light_name = param[0].GetString();
|
||||
|
||||
// write analog state
|
||||
if (!this->write_light_reset(light_name)) {
|
||||
error_unknown(res, "analog", light_name);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool Lights::write_light(std::string name, float state) {
|
||||
|
||||
// check light cache
|
||||
if (!this->lights) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// find light
|
||||
for (auto &light : *this->lights) {
|
||||
if (light.getName() == name) {
|
||||
light.override_state = CLAMP(state, 0.f, 1.f);
|
||||
light.override_enabled = true;
|
||||
|
||||
if (cfg::CONFIGURATOR_STANDALONE) {
|
||||
GameAPI::Lights::writeLight(RI_MGR, light, state);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// unknown light
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Lights::write_light_reset(std::string name) {
|
||||
|
||||
// check light cache
|
||||
if (!this->lights) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// find light
|
||||
for (auto &light : *this->lights) {
|
||||
if (light.getName() == name) {
|
||||
light.override_enabled = false;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// unknown light
|
||||
return false;
|
||||
}
|
||||
}
|
||||
28
api/modules/lights.h
Normal file
28
api/modules/lights.h
Normal file
@@ -0,0 +1,28 @@
|
||||
#pragma once
|
||||
|
||||
#include <vector>
|
||||
#include "api/module.h"
|
||||
#include "api/request.h"
|
||||
#include "cfg/api.h"
|
||||
|
||||
namespace api::modules {
|
||||
|
||||
class Lights : public Module {
|
||||
public:
|
||||
Lights();
|
||||
|
||||
private:
|
||||
|
||||
// state
|
||||
std::vector<Light> *lights;
|
||||
|
||||
// function definitions
|
||||
void read(Request &req, Response &res);
|
||||
void write(Request &req, Response &res);
|
||||
void write_reset(Request &req, Response &res);
|
||||
|
||||
// helper
|
||||
bool write_light(std::string name, float state);
|
||||
bool write_light_reset(std::string name);
|
||||
};
|
||||
}
|
||||
233
api/modules/memory.cpp
Normal file
233
api/modules/memory.cpp
Normal file
@@ -0,0 +1,233 @@
|
||||
#include "memory.h"
|
||||
|
||||
#include <functional>
|
||||
#include <mutex>
|
||||
|
||||
#include "external/rapidjson/document.h"
|
||||
#include "util/fileutils.h"
|
||||
#include "util/libutils.h"
|
||||
#include "util/memutils.h"
|
||||
#include "util/sigscan.h"
|
||||
#include "util/utils.h"
|
||||
|
||||
using namespace std::placeholders;
|
||||
using namespace rapidjson;
|
||||
|
||||
|
||||
namespace api::modules {
|
||||
|
||||
// global lock to prevent simultaneous access to memory
|
||||
static std::mutex MEMORY_LOCK;
|
||||
|
||||
Memory::Memory() : Module("memory", true) {
|
||||
functions["write"] = std::bind(&Memory::write, this, _1, _2);
|
||||
functions["read"] = std::bind(&Memory::read, this, _1, _2);
|
||||
functions["signature"] = std::bind(&Memory::signature, this, _1, _2);
|
||||
}
|
||||
|
||||
/**
|
||||
* write(dll_name: str, data: hex, offset: uint)
|
||||
*/
|
||||
void Memory::write(Request &req, Response &res) {
|
||||
std::lock_guard<std::mutex> lock(MEMORY_LOCK);
|
||||
|
||||
// check params
|
||||
if (req.params.Size() < 3) {
|
||||
return error_params_insufficient(res);
|
||||
}
|
||||
if (!req.params[0].IsString()) {
|
||||
return error_type(res, "dll_name", "str");
|
||||
}
|
||||
if (!req.params[1].IsString() || (req.params[1].GetStringLength() & 1)) {
|
||||
return error_type(res, "data", "hex string");
|
||||
}
|
||||
if (!req.params[2].IsUint()) {
|
||||
return error_type(res, "offset", "uint");
|
||||
}
|
||||
|
||||
// get params
|
||||
auto dll_name = req.params[0].GetString();
|
||||
auto dll_path = MODULE_PATH / dll_name;
|
||||
auto data = req.params[1].GetString();
|
||||
intptr_t offset = req.params[2].GetUint();
|
||||
|
||||
// convert data to bin
|
||||
size_t data_bin_size = strlen(data) / 2;
|
||||
auto data_bin = std::make_unique<uint8_t[]>(data_bin_size);
|
||||
hex2bin(data, data_bin.get());
|
||||
|
||||
// check if file exists in modules
|
||||
if (!fileutils::file_exists(dll_path)) {
|
||||
return error(res, "Couldn't find " + dll_path.string());
|
||||
}
|
||||
|
||||
// get module
|
||||
auto module = libutils::try_module(dll_name);
|
||||
if (!module) {
|
||||
return error(res, "Couldn't find module.");
|
||||
}
|
||||
|
||||
// convert offset to RVA
|
||||
offset = libutils::offset2rva(dll_path, offset);
|
||||
if (offset == ~0) {
|
||||
return error(res, "Couldn't convert offset to RVA.");
|
||||
}
|
||||
|
||||
// get module information
|
||||
MODULEINFO module_info {};
|
||||
if (!GetModuleInformation(GetCurrentProcess(), module, &module_info, sizeof(MODULEINFO))) {
|
||||
return error(res, "Couldn't get module information.");
|
||||
}
|
||||
|
||||
// check bounds
|
||||
if (offset + data_bin_size >= (size_t) module_info.lpBaseOfDll + module_info.SizeOfImage) {
|
||||
return error(res, "Data out of bounds.");
|
||||
}
|
||||
auto data_pos = reinterpret_cast<uint8_t *>(module_info.lpBaseOfDll) + offset;
|
||||
|
||||
// replace data
|
||||
memutils::VProtectGuard guard(data_pos, data_bin_size);
|
||||
memcpy(data_pos, data_bin.get(), data_bin_size);
|
||||
}
|
||||
|
||||
/**
|
||||
* read(dll_name: str, offset: uint, size: uint)
|
||||
*/
|
||||
void Memory::read(Request &req, Response &res) {
|
||||
std::lock_guard<std::mutex> lock(MEMORY_LOCK);
|
||||
|
||||
// check params
|
||||
if (req.params.Size() < 3) {
|
||||
return error_params_insufficient(res);
|
||||
}
|
||||
if (!req.params[0].IsString()) {
|
||||
return error_type(res, "dll_name", "str");
|
||||
}
|
||||
if (!req.params[1].IsUint()) {
|
||||
return error_type(res, "offset", "uint");
|
||||
}
|
||||
if (!req.params[2].IsUint()) {
|
||||
return error_type(res, "size", "uint");
|
||||
}
|
||||
|
||||
// get params
|
||||
auto dll_name = req.params[0].GetString();
|
||||
auto dll_path = MODULE_PATH / dll_name;
|
||||
intptr_t offset = req.params[1].GetUint();
|
||||
auto size = req.params[2].GetUint();
|
||||
|
||||
// check if file exists in modules
|
||||
if (!fileutils::file_exists(dll_path)) {
|
||||
return error(res, "Couldn't find " + dll_path.string());
|
||||
}
|
||||
|
||||
// get module
|
||||
auto module = libutils::try_module(dll_name);
|
||||
if (!module) {
|
||||
return error(res, "Couldn't find module.");
|
||||
}
|
||||
|
||||
// convert offset to RVA
|
||||
offset = libutils::offset2rva(dll_path, offset);
|
||||
if (offset == ~0) {
|
||||
return error(res, "Couldn't convert offset to RVA.");
|
||||
}
|
||||
|
||||
// get module information
|
||||
MODULEINFO module_info {};
|
||||
if (!GetModuleInformation(GetCurrentProcess(), module, &module_info, sizeof(MODULEINFO))) {
|
||||
return error(res, "Couldn't get module information.");
|
||||
}
|
||||
|
||||
// check bounds
|
||||
auto max = offset + size;
|
||||
if ((size_t) max >= (size_t) module_info.lpBaseOfDll + module_info.SizeOfImage) {
|
||||
return error(res, "Data out of bounds.");
|
||||
}
|
||||
|
||||
// read memory to hex (without virtual protect)
|
||||
std::string hex = bin2hex((uint8_t*) module_info.lpBaseOfDll + offset, size);
|
||||
Value hex_val(hex.c_str(), res.doc()->GetAllocator());
|
||||
res.add_data(hex_val);
|
||||
}
|
||||
|
||||
/**
|
||||
* signature(
|
||||
* dll_name: str,
|
||||
* signature: hex,
|
||||
* replacement: hex,
|
||||
* offset: uint,
|
||||
* usage: uint)
|
||||
*
|
||||
* Both signature and replacement will ignore bytes specified as "??" in the hex string.
|
||||
* The offset specifies the offset between the found signature and the position to write the replacement to.
|
||||
* The resulting integer is the file offset where the replacement was written to.
|
||||
*/
|
||||
void Memory::signature(Request &req, Response &res) {
|
||||
std::lock_guard<std::mutex> lock(MEMORY_LOCK);
|
||||
|
||||
// check params
|
||||
if (req.params.Size() < 5) {
|
||||
return error_params_insufficient(res);
|
||||
}
|
||||
if (!req.params[0].IsString()) {
|
||||
return error_type(res, "dll_name", "string");
|
||||
}
|
||||
if (!req.params[1].IsString() || (req.params[1].GetStringLength() & 1)) {
|
||||
return error_type(res, "signature", "hex string");
|
||||
}
|
||||
if (!req.params[2].IsString() || (req.params[2].GetStringLength() & 1)) {
|
||||
return error_type(res, "replacement", "hex string");
|
||||
}
|
||||
if (!req.params[3].IsUint()) {
|
||||
return error_type(res, "offset", "uint");
|
||||
}
|
||||
if (!req.params[4].IsUint()) {
|
||||
return error_type(res, "usage", "uint");
|
||||
}
|
||||
|
||||
// get params
|
||||
auto dll_name = req.params[0].GetString();
|
||||
auto dll_path = MODULE_PATH / dll_name;
|
||||
auto signature = req.params[1].GetString();
|
||||
auto replacement = req.params[2].GetString();
|
||||
auto offset = req.params[3].GetUint();
|
||||
auto usage = req.params[4].GetUint();
|
||||
|
||||
// check if file exists in modules
|
||||
if (!fileutils::file_exists(dll_path)) {
|
||||
return error(res, "Couldn't find " + dll_path.string());
|
||||
}
|
||||
|
||||
// get module
|
||||
auto module = libutils::try_module(dll_name);
|
||||
if (!module) {
|
||||
return error(res, "Couldn't find module.");
|
||||
}
|
||||
|
||||
// execute
|
||||
auto result = replace_pattern(
|
||||
module,
|
||||
signature,
|
||||
replacement,
|
||||
offset,
|
||||
usage
|
||||
);
|
||||
|
||||
// check result
|
||||
if (!result) {
|
||||
return error(res, std::string("Pattern not found in memory of ") + dll_name);
|
||||
}
|
||||
|
||||
// convert to offset
|
||||
auto rva = result - reinterpret_cast<intptr_t>(module);
|
||||
result = libutils::rva2offset(dll_path, rva);
|
||||
if (result == -1) {
|
||||
return error(res, "Couldn't convert RVA to file offset.");
|
||||
}
|
||||
|
||||
// add result
|
||||
Value result_val(result);
|
||||
res.add_data(result_val);
|
||||
}
|
||||
}
|
||||
19
api/modules/memory.h
Normal file
19
api/modules/memory.h
Normal file
@@ -0,0 +1,19 @@
|
||||
#pragma once
|
||||
|
||||
#include "api/module.h"
|
||||
#include "api/request.h"
|
||||
|
||||
namespace api::modules {
|
||||
|
||||
class Memory : public Module {
|
||||
public:
|
||||
Memory();
|
||||
|
||||
private:
|
||||
|
||||
// function definitions
|
||||
void write(Request &req, Response &res);
|
||||
void read(Request &req, Response &res);
|
||||
void signature(Request &req, Response &res);
|
||||
};
|
||||
}
|
||||
145
api/modules/touch.cpp
Normal file
145
api/modules/touch.cpp
Normal file
@@ -0,0 +1,145 @@
|
||||
#include "touch.h"
|
||||
|
||||
#include <functional>
|
||||
|
||||
#include "external/rapidjson/document.h"
|
||||
#include "avs/game.h"
|
||||
#include "hooks/graphics/graphics.h"
|
||||
#include "misc/eamuse.h"
|
||||
#include "launcher/launcher.h"
|
||||
#include "touch/touch.h"
|
||||
#include "util/utils.h"
|
||||
#include "games/iidx/iidx.h"
|
||||
|
||||
using namespace std::placeholders;
|
||||
using namespace rapidjson;
|
||||
|
||||
|
||||
namespace api::modules {
|
||||
|
||||
Touch::Touch() : Module("touch") {
|
||||
is_sdvx = avs::game::is_model("KFC");
|
||||
|
||||
is_tdj_fhd = (avs::game::is_model("LDJ") && games::iidx::is_tdj_fhd());
|
||||
// special case: when windowed subscreen is in use, use the original coords
|
||||
if (GRAPHICS_IIDX_WSUB) {
|
||||
is_tdj_fhd = false;
|
||||
}
|
||||
|
||||
functions["read"] = std::bind(&Touch::read, this, _1, _2);
|
||||
functions["write"] = std::bind(&Touch::write, this, _1, _2);
|
||||
functions["write_reset"] = std::bind(&Touch::write_reset, this, _1, _2);
|
||||
}
|
||||
|
||||
/**
|
||||
* read()
|
||||
*/
|
||||
void Touch::read(api::Request &req, Response &res) {
|
||||
|
||||
// get touch points
|
||||
std::vector<TouchPoint> touch_points;
|
||||
touch_get_points(touch_points);
|
||||
|
||||
// add state for each touch point
|
||||
for (auto &touch : touch_points) {
|
||||
Value state(kArrayType);
|
||||
Value id((uint64_t) touch.id);
|
||||
Value x((int64_t) touch.x);
|
||||
Value y((int64_t) touch.y);
|
||||
Value mouse((bool) touch.mouse);
|
||||
state.PushBack(id, res.doc()->GetAllocator());
|
||||
state.PushBack(x, res.doc()->GetAllocator());
|
||||
state.PushBack(y, res.doc()->GetAllocator());
|
||||
state.PushBack(mouse, res.doc()->GetAllocator());
|
||||
res.add_data(state);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* write([id: uint, x: int, y: int], ...)
|
||||
*/
|
||||
void Touch::write(Request &req, Response &res) {
|
||||
|
||||
// get all touch points
|
||||
std::vector<TouchPoint> touch_points;
|
||||
for (Value ¶m : req.params.GetArray()) {
|
||||
|
||||
// check params
|
||||
if (param.Size() < 3) {
|
||||
error_params_insufficient(res);
|
||||
continue;
|
||||
}
|
||||
if (!param[0].IsUint()) {
|
||||
error_type(res, "id", "uint");
|
||||
continue;
|
||||
}
|
||||
if (!param[1].IsInt()) {
|
||||
error_type(res, "x", "int");
|
||||
continue;
|
||||
}
|
||||
if (!param[2].IsInt()) {
|
||||
error_type(res, "y", "int");
|
||||
continue;
|
||||
}
|
||||
// TODO: optional mouse parameter
|
||||
|
||||
// get params
|
||||
auto touch_id = param[0].GetUint();
|
||||
auto touch_x = param[1].GetInt();
|
||||
auto touch_y = param[2].GetInt();
|
||||
|
||||
apply_touch_errata(touch_x, touch_y);
|
||||
|
||||
touch_points.emplace_back(TouchPoint {
|
||||
.id = touch_id,
|
||||
.x = touch_x,
|
||||
.y = touch_y,
|
||||
.mouse = false,
|
||||
});
|
||||
}
|
||||
|
||||
// apply touch points
|
||||
touch_write_points(&touch_points);
|
||||
}
|
||||
|
||||
/**
|
||||
* write_reset(id: uint, ...)
|
||||
*/
|
||||
void Touch::write_reset(Request &req, Response &res) {
|
||||
|
||||
// get all IDs
|
||||
std::vector<DWORD> touch_point_ids;
|
||||
for (Value ¶m : req.params.GetArray()) {
|
||||
|
||||
// check params
|
||||
if (!param.IsUint()) {
|
||||
error_type(res, "id", "uint");
|
||||
continue;
|
||||
}
|
||||
|
||||
// remember touch ID
|
||||
auto touch_id = param.GetUint();
|
||||
touch_point_ids.emplace_back(touch_id);
|
||||
}
|
||||
|
||||
// remove all IDs
|
||||
touch_remove_points(&touch_point_ids);
|
||||
}
|
||||
|
||||
void Touch::apply_touch_errata(int &x, int &y) {
|
||||
int x_raw = x;
|
||||
int y_raw = y;
|
||||
|
||||
if (is_tdj_fhd) {
|
||||
// deal with TDJ FHD resolution mismatch (upgrade 720p to 1080p)
|
||||
// we don't know what screen is being shown on the companion and the API doesn't specify
|
||||
// the target of the touch events so just assume it's the sub screen
|
||||
x = x_raw * 1920 / 1280;
|
||||
y = y_raw * 1080 / 720;
|
||||
} else if (is_sdvx) {
|
||||
// for exceed gear, they are both 1080p screens, but need to apply transformation
|
||||
x = 1080 - y_raw;
|
||||
y = x_raw;
|
||||
}
|
||||
}
|
||||
}
|
||||
24
api/modules/touch.h
Normal file
24
api/modules/touch.h
Normal file
@@ -0,0 +1,24 @@
|
||||
#pragma once
|
||||
|
||||
#include <vector>
|
||||
#include "api/module.h"
|
||||
#include "api/request.h"
|
||||
|
||||
namespace api::modules {
|
||||
|
||||
class Touch : public Module {
|
||||
public:
|
||||
Touch();
|
||||
|
||||
private:
|
||||
bool is_sdvx;
|
||||
bool is_tdj_fhd;
|
||||
|
||||
// function definitions
|
||||
void read(Request &req, Response &res);
|
||||
void write(Request &req, Response &res);
|
||||
void write_reset(Request &req, Response &res);
|
||||
void apply_touch_errata(int &x, int &y);
|
||||
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user