mirror of
https://github.com/spice2x/spice2x.github.io.git
synced 2026-08-01 22:30:42 -07:00
Compare commits
19 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 06374ef78a | |||
| bdde1ec6b8 | |||
| d2176fe4f0 | |||
| fb9eef904a | |||
| 48903998a5 | |||
| f2dca0265f | |||
| 1147ed9858 | |||
| 19d93f4ffd | |||
| 15bfffa1d3 | |||
| 18a9a47c33 | |||
| 6838e69ebe | |||
| 26b3b64794 | |||
| aadd2bdd59 | |||
| d0e24e31ca | |||
| 4fb7f20c7b | |||
| 6ddae70c5a | |||
| b38160d6c2 | |||
| 231c998cc0 | |||
| 127d31a85c |
+122
-20
@@ -35,24 +35,33 @@ struct ICCA_STATUS_LA9 {
|
||||
static_assert(sizeof(struct ICCA_STATUS) == 24, "ICCA_STATUS must be 24 bytes");
|
||||
|
||||
enum ICCA_WORKFLOW {
|
||||
STEP,
|
||||
SLEEP,
|
||||
START,
|
||||
INIT,
|
||||
READY,
|
||||
GET_USERID,
|
||||
ACTIVE,
|
||||
EJECT,
|
||||
EJECT_CHECK,
|
||||
END,
|
||||
CLOSE_EJECT,
|
||||
CLOSE_E_CHK,
|
||||
CLOSE_END,
|
||||
ERR_GETUID = -2
|
||||
STEP = 0,
|
||||
SLEEP = 1,
|
||||
START = 2,
|
||||
INIT = 3,
|
||||
READY = 4,
|
||||
GET_USERID = 5,
|
||||
ACTIVE = 6,
|
||||
EJECT = 7,
|
||||
EJECT_CHECK = 8,
|
||||
END = 9,
|
||||
CLOSE_EJECT = 10,
|
||||
CLOSE_E_CHK = 11,
|
||||
CLOSE_END = 12,
|
||||
ERR_GETUID = -2,
|
||||
ERR_REMOVED = -11
|
||||
};
|
||||
|
||||
// used by RA as the status_code
|
||||
enum ICCA_STATUS_CODE {
|
||||
EMPTY = 1,
|
||||
ENGAGED = 2
|
||||
};
|
||||
|
||||
struct ICCA_UNIT {
|
||||
struct ICCA_STATUS status {};
|
||||
enum ICCA_WORKFLOW state = STEP;
|
||||
enum ICCA_WORKFLOW state_jdz = SLEEP;
|
||||
bool card_cmd_pressed = false;
|
||||
bool card_in = false;
|
||||
double card_in_time = 0.0;
|
||||
@@ -75,6 +84,11 @@ static inline int icca_get_active_count() {
|
||||
}
|
||||
|
||||
static inline int icca_get_unit_id(int unit_id) {
|
||||
// on RA the unit_id is zero-indexed
|
||||
if (avs::game::is_model("JDZ")) {
|
||||
return unit_id;
|
||||
}
|
||||
|
||||
if (icca_get_active_count() < 2)
|
||||
return 1;
|
||||
else {
|
||||
@@ -122,9 +136,15 @@ static inline void update_card(int unit_id) {
|
||||
IS_LAST_CARD_FELICA = is_card_uid_felica(unit->status.uid);
|
||||
|
||||
unit->state = acio::ICCA_COMPAT_ACTIVE ? START : ACTIVE;
|
||||
unit->state_jdz = ACTIVE;
|
||||
unit->status.error = 0;
|
||||
unit->status.front_sensor = 1;
|
||||
unit->status.rear_sensor = 1;
|
||||
} else {
|
||||
unit->state = ERR_GETUID;
|
||||
unit->state_jdz = ERR_GETUID;
|
||||
unit->status.front_sensor = 1;
|
||||
unit->status.rear_sensor = 1;
|
||||
memset(unit->status.uid, 0, 8);
|
||||
}
|
||||
unit->card_in = true;
|
||||
@@ -132,10 +152,25 @@ static inline void update_card(int unit_id) {
|
||||
} else if (unit->state == EJECT_CHECK) {
|
||||
unit->state = SLEEP;
|
||||
unit->card_in = false;
|
||||
unit->status.front_sensor = 0;
|
||||
unit->status.rear_sensor = 0;
|
||||
} else if (unit->state_jdz == READY) {
|
||||
unit->state = GET_USERID;
|
||||
unit->state_jdz = GET_USERID;
|
||||
unit->status.error = 0;
|
||||
unit->status.front_sensor = 1;
|
||||
unit->status.rear_sensor = 1;
|
||||
unit->card_in = true;
|
||||
unit->card_in_time = get_performance_seconds();
|
||||
}
|
||||
} else {
|
||||
unit->state = acio::ICCA_COMPAT_ACTIVE ? START : ACTIVE;
|
||||
if (unit->state_jdz == READY) {
|
||||
unit->state_jdz = GET_USERID;
|
||||
}
|
||||
unit->status.error = 0;
|
||||
unit->status.front_sensor = 1;
|
||||
unit->status.rear_sensor = 1;
|
||||
unit->card_in = true;
|
||||
unit->card_in_time = get_performance_seconds();
|
||||
}
|
||||
@@ -144,6 +179,12 @@ static inline void update_card(int unit_id) {
|
||||
unit->state = CLOSE_EJECT;
|
||||
if (fabs(get_performance_seconds() - unit->card_in_time) > CARD_TIMEOUT) {
|
||||
unit->card_in = false;
|
||||
memset(unit->status.uid, 0, 8);
|
||||
if (unit->state_jdz == ACTIVE || unit->state_jdz == GET_USERID) {
|
||||
unit->state_jdz = ERR_REMOVED;
|
||||
}
|
||||
unit->status.front_sensor = 0;
|
||||
unit->status.rear_sensor = 0;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -302,7 +343,11 @@ static char __cdecl ac_io_icca_get_status(void *a1, void *a2) {
|
||||
|
||||
// copy state to output buffer
|
||||
ICCA_UNIT *unit = &ICCA_UNITS[unit_id];
|
||||
unit->status.status_code = unit->state;
|
||||
if (avs::game::is_model("JDZ")) {
|
||||
unit->status.status_code = unit->card_in ? ENGAGED : EMPTY;
|
||||
} else {
|
||||
unit->status.status_code = unit->state;
|
||||
}
|
||||
memcpy(status, &unit->status, sizeof(struct ICCA_STATUS));
|
||||
|
||||
// funny workaround
|
||||
@@ -387,6 +432,11 @@ static char __cdecl ac_io_icca_req_uid(int unit_id) {
|
||||
static int __cdecl ac_io_icca_req_uid_isfinished(int unit_id, DWORD *read_state) {
|
||||
unit_id = icca_get_unit_id(unit_id);
|
||||
ICCA_UNIT *unit = &ICCA_UNITS[unit_id];
|
||||
if (avs::game::is_model("JDZ")) {
|
||||
// hack for RA - only ever seen it as this
|
||||
*read_state = 8;
|
||||
return 1;
|
||||
}
|
||||
if (unit->card_in) {
|
||||
if (fabs(get_performance_seconds() - unit->card_in_time) < CARD_TIMEOUT) {
|
||||
unit->state = END;
|
||||
@@ -403,16 +453,61 @@ static int __cdecl ac_io_icca_send_keep_alive_packet(int a1, int a2, int a3) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __cdecl ac_io_icca_workflow_jdz(int workflow, int unit_id) {
|
||||
|
||||
unit_id = icca_get_unit_id(unit_id);
|
||||
ICCA_UNIT *unit = &ICCA_UNITS[unit_id];
|
||||
switch (workflow) {
|
||||
// RA uses "STEP" as more of a polling thing it seems
|
||||
case STEP:
|
||||
switch (unit->state_jdz) {
|
||||
case CLOSE_EJECT:
|
||||
unit->state_jdz = CLOSE_E_CHK;
|
||||
break;
|
||||
case CLOSE_E_CHK:
|
||||
unit->state_jdz = CLOSE_END;
|
||||
break;
|
||||
case CLOSE_END:
|
||||
unit->state_jdz = SLEEP;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case SLEEP:
|
||||
unit->state = SLEEP;
|
||||
break;
|
||||
case START:
|
||||
unit->state_jdz = INIT;
|
||||
break;
|
||||
case INIT:
|
||||
case READY:
|
||||
unit->state_jdz = READY;
|
||||
break;
|
||||
case CLOSE_EJECT:
|
||||
unit->state_jdz = CLOSE_EJECT;
|
||||
return CLOSE_E_CHK;
|
||||
case CLOSE_END:
|
||||
unit->state_jdz = SLEEP;
|
||||
break;
|
||||
default:
|
||||
// should probably log a warning here
|
||||
break;
|
||||
}
|
||||
return unit->state_jdz;
|
||||
}
|
||||
|
||||
static int __cdecl ac_io_icca_workflow(int workflow, int unit_id) {
|
||||
// RA uses a different workflow process for the slotted readers; treat it differently
|
||||
if (avs::game::is_model("JDZ")) {
|
||||
return ac_io_icca_workflow_jdz(workflow, unit_id);
|
||||
}
|
||||
|
||||
unit_id = icca_get_unit_id(unit_id);
|
||||
ICCA_UNIT *unit = &ICCA_UNITS[unit_id];
|
||||
switch (workflow) {
|
||||
case STEP:
|
||||
if (avs::game::is_model("JDZ"))
|
||||
unit->state = SLEEP;
|
||||
else
|
||||
unit->state = STEP;
|
||||
unit->state = STEP;
|
||||
break;
|
||||
case SLEEP:
|
||||
unit->state = SLEEP;
|
||||
@@ -441,7 +536,6 @@ static int __cdecl ac_io_icca_workflow(int workflow, int unit_id) {
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return unit->state;
|
||||
}
|
||||
|
||||
@@ -467,6 +561,14 @@ acio::ICCAModule::ICCAModule(HMODULE module, acio::HookMode hookMode) : ACIOModu
|
||||
void acio::ICCAModule::attach() {
|
||||
ACIOModule::attach();
|
||||
|
||||
// workaround for RA; ac_io_icca_cardunit_init is never called so treat like both are initialized
|
||||
if (avs::game::is_model("JDZ")) {
|
||||
ICCA_UNITS[0].initialized = true;
|
||||
ICCA_UNITS[1].initialized = true;
|
||||
|
||||
CARD_TIMEOUT = 10.0; // keep the card in the slot for longer
|
||||
}
|
||||
|
||||
// hooks
|
||||
ACIO_MODULE_HOOK(ac_io_icca_cardunit_init);
|
||||
ACIO_MODULE_HOOK(ac_io_icca_cardunit_init_isfinished);
|
||||
|
||||
@@ -217,8 +217,10 @@ namespace avs {
|
||||
ea3_config_name = "prop/eamuse-config.xml";
|
||||
}
|
||||
|
||||
if (avs::core::file_exists(ea3_config_name)) {
|
||||
log_info("avs-ea3", "booting (using {})", ea3_config_name);
|
||||
if (fileutils::file_exists(ea3_config_name)) {
|
||||
log_info("avs-ea3", "found {} on disk", ea3_config_name);
|
||||
} else if (CFG_PATH.size()) {
|
||||
log_fatal("avs-ea3", "user-specified ea3 config file is missing: {}", ea3_config_name);
|
||||
} else {
|
||||
log_warning("avs-ea3", "looked for the following files in order:");
|
||||
log_warning("avs-ea3", " * prop/ea3-config.xml");
|
||||
|
||||
@@ -163,6 +163,7 @@ time (
|
||||
if ((BUILD_XP > 0))
|
||||
then
|
||||
# 32 bit Windows XP
|
||||
echo ""
|
||||
echo "Building 32bit targets (WinXP toolchain)..."
|
||||
echo "========================="
|
||||
if ((CLEAN_BUILD > 0))
|
||||
@@ -187,6 +188,7 @@ time (
|
||||
CXXFLAGS="$CXXFLAGS -DSPICE_XP=1" cmake -G "Ninja" -DCMAKE_TOOLCHAIN_FILE=${TOOLCHAIN_WINXP_64} -DCMAKE_BUILD_TYPE=${BUILD_TYPE} "$OLDPWD" && ninja ${TARGETS_XP64}
|
||||
popd > /dev/null
|
||||
else
|
||||
echo ""
|
||||
echo "Skipping WinXP builds, toolchain not specified"
|
||||
fi
|
||||
|
||||
|
||||
+12
-2
@@ -199,9 +199,19 @@ GameAPI::Buttons::State GameAPI::Buttons::getState(rawinput::RawInputManager *ma
|
||||
if (vKey < value_states->size()) {
|
||||
auto value = value_states->at(vKey);
|
||||
if (current_button->getAnalogType() == BAT_POSITIVE) {
|
||||
state = value > 0.6f ? BUTTON_PRESSED : BUTTON_NOT_PRESSED;
|
||||
float threshold = 0.6f;
|
||||
if (current_button->getBatThreshold() > 0) {
|
||||
threshold = std::clamp(current_button->getBatThreshold() / 100.f, 0.01f, 0.99f);
|
||||
}
|
||||
state = value > threshold ? BUTTON_PRESSED : BUTTON_NOT_PRESSED;
|
||||
|
||||
} else if (current_button->getAnalogType() == BAT_NEGATIVE) {
|
||||
state = value < 0.4f ? BUTTON_PRESSED : BUTTON_NOT_PRESSED;
|
||||
float threshold = 0.4f;
|
||||
if (current_button->getBatThreshold() > 0) {
|
||||
threshold = std::clamp((100 - current_button->getBatThreshold()) / 100.f, 0.01f, 0.99f);
|
||||
}
|
||||
state = value < threshold ? BUTTON_PRESSED : BUTTON_NOT_PRESSED;
|
||||
|
||||
} else {
|
||||
state = value > 0.01f ? BUTTON_PRESSED : BUTTON_NOT_PRESSED;
|
||||
}
|
||||
|
||||
@@ -56,6 +56,7 @@ private:
|
||||
ButtonAnalogType analog_type = BAT_NONE;
|
||||
double debounce_up = 0.0;
|
||||
double debounce_down = 0.0;
|
||||
int bat_threshold = 0; // for positive/negative only, value in percentage, zero is default
|
||||
bool invert = false;
|
||||
bool is_temporary = false;
|
||||
|
||||
@@ -109,6 +110,7 @@ public:
|
||||
alternatives.clear();
|
||||
device_identifier = "";
|
||||
analog_type = BAT_NONE;
|
||||
bat_threshold = 0;
|
||||
}
|
||||
|
||||
std::string getDisplayString(rawinput::RawInputManager* manager);
|
||||
@@ -169,6 +171,14 @@ public:
|
||||
this->debounce_down = debounce_time_down;
|
||||
}
|
||||
|
||||
inline void setBatThreshold(int bat_threshold) {
|
||||
this->bat_threshold = bat_threshold;
|
||||
}
|
||||
|
||||
inline int getBatThreshold() const {
|
||||
return this->bat_threshold;
|
||||
}
|
||||
|
||||
inline bool getInvert() const {
|
||||
return this->invert;
|
||||
}
|
||||
|
||||
@@ -162,6 +162,7 @@ bool Config::addGame(Game &game) {
|
||||
auto analogType = (int) BAT_NONE;
|
||||
double debounce_up = 0.0;
|
||||
double debounce_down = 0.0;
|
||||
int bat_threshold = 0;
|
||||
int velocity_threshold = 0;
|
||||
bool invert = false;
|
||||
tinyxml2::XMLError attrError = gameButtonNode->QueryIntAttribute("vkey", &vKey);
|
||||
@@ -169,6 +170,7 @@ bool Config::addGame(Game &game) {
|
||||
gameButtonNode->QueryIntAttribute("analogtype", &analogType);
|
||||
gameButtonNode->QueryDoubleAttribute("debounce_up", &debounce_up);
|
||||
gameButtonNode->QueryDoubleAttribute("debounce_down", &debounce_down);
|
||||
gameButtonNode->QueryIntAttribute("bat_threshold", &bat_threshold);
|
||||
gameButtonNode->QueryIntAttribute("velocity_threshold", &velocity_threshold);
|
||||
gameButtonNode->QueryBoolAttribute("invert", &invert);
|
||||
if (attrError != tinyxml2::XMLError::XML_SUCCESS) {
|
||||
@@ -180,6 +182,7 @@ bool Config::addGame(Game &game) {
|
||||
gameButtonNode->SetAttribute("devid", button->getDeviceIdentifier().c_str());
|
||||
gameButtonNode->SetAttribute("debounce_up", debounce_up);
|
||||
gameButtonNode->SetAttribute("debounce_down", debounce_down);
|
||||
gameButtonNode->SetAttribute("bat_threshold", bat_threshold);
|
||||
gameButtonNode->SetAttribute("velocity_threshold", velocity_threshold);
|
||||
gameButtonNode->SetAttribute("invert", invert);
|
||||
gameButtonsNode->InsertEndChild(gameButtonNode);
|
||||
@@ -188,6 +191,7 @@ bool Config::addGame(Game &game) {
|
||||
button->setAnalogType((ButtonAnalogType) analogType);
|
||||
button->setDebounceUp(debounce_up);
|
||||
button->setDebounceDown(debounce_down);
|
||||
button->setBatThreshold(bat_threshold);
|
||||
button->setVelocityThreshold(velocity_threshold);
|
||||
button->setInvert(invert);
|
||||
if (devid) {
|
||||
@@ -207,6 +211,7 @@ bool Config::addGame(Game &game) {
|
||||
gameButtonNode->SetAttribute("analogtype", (int) it.getAnalogType());
|
||||
gameButtonNode->SetAttribute("debounce_up", it.getDebounceUp());
|
||||
gameButtonNode->SetAttribute("debounce_down", it.getDebounceDown());
|
||||
gameButtonNode->SetAttribute("bat_threshold", it.getBatThreshold());
|
||||
gameButtonNode->SetAttribute("velocity_threshold", it.getVelocityThreshold());
|
||||
gameButtonNode->SetAttribute("invert", it.getInvert());
|
||||
gameButtonNode->SetAttribute("devid", it.getDeviceIdentifier().c_str());
|
||||
@@ -432,6 +437,7 @@ bool Config::addGame(Game &game) {
|
||||
gameButtonNode->SetAttribute("analogtype", it.getAnalogType());
|
||||
gameButtonNode->SetAttribute("debounce_up", it.getDebounceUp());
|
||||
gameButtonNode->SetAttribute("debounce_down", it.getDebounceDown());
|
||||
gameButtonNode->SetAttribute("bat_threshold", it.getBatThreshold());
|
||||
gameButtonNode->SetAttribute("velocity_threshold", it.getVelocityThreshold());
|
||||
gameButtonNode->SetAttribute("invert", it.getInvert());
|
||||
gameButtonNode->SetAttribute("devid", it.getDeviceIdentifier().c_str());
|
||||
@@ -535,6 +541,7 @@ bool Config::updateBinding(const Game &game, const Button &button, int alternati
|
||||
gameButtonNode->SetAttribute("analogtype", (int) button.getAnalogType());
|
||||
gameButtonNode->SetAttribute("debounce_up", button.getDebounceUp());
|
||||
gameButtonNode->SetAttribute("debounce_down", button.getDebounceDown());
|
||||
gameButtonNode->SetAttribute("bat_threshold", button.getBatThreshold());
|
||||
gameButtonNode->SetAttribute("velocity_threshold", button.getVelocityThreshold());
|
||||
gameButtonNode->SetAttribute("invert", button.getInvert());
|
||||
gameButtonNode->SetAttribute("devid", button.getDeviceIdentifier().c_str());
|
||||
@@ -551,6 +558,7 @@ bool Config::updateBinding(const Game &game, const Button &button, int alternati
|
||||
gameButtonNode->SetAttribute("analogtype", 0);
|
||||
gameButtonNode->SetAttribute("debounce_up", 0.0);
|
||||
gameButtonNode->SetAttribute("debounce_down", 0.0);
|
||||
gameButtonNode->SetAttribute("bat_threshold", 0);
|
||||
gameButtonNode->SetAttribute("velocity_threshold", 0);
|
||||
gameButtonNode->SetAttribute("invert", false);
|
||||
gameButtonNode->SetAttribute("devid", "");
|
||||
@@ -946,12 +954,14 @@ std::vector<Button> Config::getButtons(const std::string &gameName) {
|
||||
auto analogType = (int) BAT_NONE;
|
||||
double debounce_up = 0.0;
|
||||
double debounce_down = 0.0;
|
||||
int bat_threshold = 0;
|
||||
int velocity_threshold = 0;
|
||||
bool invert = false;
|
||||
gameButtonNode->QueryIntAttribute("vkey", &vKey);
|
||||
gameButtonNode->QueryIntAttribute("analogtype", &analogType);
|
||||
gameButtonNode->QueryDoubleAttribute("debounce_up", &debounce_up);
|
||||
gameButtonNode->QueryDoubleAttribute("debounce_down", &debounce_down);
|
||||
gameButtonNode->QueryIntAttribute("bat_threshold", &bat_threshold);
|
||||
gameButtonNode->QueryIntAttribute("velocity_threshold", &velocity_threshold);
|
||||
gameButtonNode->QueryBoolAttribute("invert", &invert);
|
||||
const char *devid = gameButtonNode->Attribute("devid");
|
||||
@@ -966,6 +976,7 @@ std::vector<Button> Config::getButtons(const std::string &gameName) {
|
||||
alt.setAnalogType((ButtonAnalogType) analogType);
|
||||
alt.setDebounceUp(debounce_up);
|
||||
alt.setDebounceDown(debounce_down);
|
||||
alt.setBatThreshold(bat_threshold);
|
||||
alt.setVelocityThreshold(velocity_threshold);
|
||||
alt.setInvert(invert);
|
||||
if (devid) {
|
||||
@@ -984,6 +995,7 @@ std::vector<Button> Config::getButtons(const std::string &gameName) {
|
||||
button.setAnalogType((ButtonAnalogType) analogType);
|
||||
button.setDebounceUp(debounce_up);
|
||||
button.setDebounceDown(debounce_down);
|
||||
button.setBatThreshold(bat_threshold);
|
||||
button.setVelocityThreshold(velocity_threshold);
|
||||
button.setInvert(invert);
|
||||
if (devid) {
|
||||
|
||||
@@ -24,6 +24,7 @@ namespace overlay::windows {
|
||||
el->SetAttribute("invert", entry.invert);
|
||||
el->SetAttribute("debounce_up", entry.debounce_up);
|
||||
el->SetAttribute("debounce_down", entry.debounce_down);
|
||||
el->SetAttribute("bat_threshold", entry.bat_threshold);
|
||||
el->SetAttribute("velocity_threshold", entry.velocity_threshold);
|
||||
parent->InsertEndChild(el);
|
||||
}
|
||||
@@ -49,6 +50,10 @@ namespace overlay::windows {
|
||||
el->QueryIntAttribute("velocity_threshold", &vel);
|
||||
entry.velocity_threshold = (unsigned short)vel;
|
||||
|
||||
int bat = 0;
|
||||
el->QueryIntAttribute("bat_threshold", &bat);
|
||||
entry.bat_threshold = bat;
|
||||
|
||||
return entry;
|
||||
}
|
||||
|
||||
|
||||
@@ -60,6 +60,7 @@ namespace cfg {
|
||||
// window = rectangle including the frame
|
||||
// client = just the content area without frames.
|
||||
bool window_always_on_top = false;
|
||||
bool window_disable_round_corners = false;
|
||||
bool client_keep_aspect_ratio = true;
|
||||
bool enable_window_resize = false;
|
||||
int window_decoration = 0; // enum type WindowDecorationMode
|
||||
|
||||
@@ -915,8 +915,7 @@ namespace games::iidx {
|
||||
log_warning(
|
||||
"iidx",
|
||||
"Failed to apply ASIO compatibility fix for iidx32+. "
|
||||
"Unless patches are applied, your ASIO device ({}) may hang or fail to work",
|
||||
ASIO_DRIVER->c_str());
|
||||
"Unless patches are applied, your ASIO device may hang or fail to work");
|
||||
} else {
|
||||
log_info(
|
||||
"iidx",
|
||||
|
||||
@@ -387,15 +387,6 @@ namespace games::popn {
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct PopnLight {
|
||||
int data_index;
|
||||
Lights::popn_lights_t light;
|
||||
uint8_t size;
|
||||
PopnLight(
|
||||
int data_index, Lights::popn_lights_t light, uint8_t size) :
|
||||
data_index(data_index), light(light), size(size) {}
|
||||
};
|
||||
|
||||
static void __fastcall aioIob5Bi3a_SetTapeLedDataPart(
|
||||
AIO_IOB5_BI3A *i_pNodeCtl, uint32_t i_CnPin, char i_LedType, const void *i_pData, uint32_t i_DataSize, bool i_bIsLast) {
|
||||
|
||||
@@ -484,7 +475,7 @@ namespace games::popn {
|
||||
const auto data_size = std::min(map.data.capacity(), (size_t)number_of_leds / 3);
|
||||
|
||||
// pick a color to use
|
||||
const auto rgb = tapeledutils::pick_color_from_led_tape((uint8_t *)i_pData, data_size);
|
||||
const auto rgb = tapeledutils::pick_color_from_led_tape(map, (uint8_t *)i_pData, data_size);
|
||||
|
||||
// program the lights into API
|
||||
auto &lights = get_lights();
|
||||
|
||||
@@ -136,6 +136,18 @@ std::vector<Light> &games::popn::get_lights() {
|
||||
{"Pika", "IC Card R"},
|
||||
{"Pika", "IC Card G"},
|
||||
{"Pika", "IC Card B"},
|
||||
{"Pika", "Speakers R"},
|
||||
{"Pika", "Speakers G"},
|
||||
{"Pika", "Speakers B"},
|
||||
{"Pika", "Monitor R"},
|
||||
{"Pika", "Monitor G"},
|
||||
{"Pika", "Monitor B"},
|
||||
{"Pika", "Control Panel R"},
|
||||
{"Pika", "Control Panel G"},
|
||||
{"Pika", "Control Panel B"},
|
||||
{"Pika", "Cabinet R"},
|
||||
{"Pika", "Cabinet G"},
|
||||
{"Pika", "Cabinet B"},
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -121,6 +121,18 @@ namespace games::popn {
|
||||
IC_Card_R,
|
||||
IC_Card_G,
|
||||
IC_Card_B,
|
||||
Speaker_R,
|
||||
Speaker_G,
|
||||
Speaker_B,
|
||||
Monitor_R,
|
||||
Monitor_G,
|
||||
Monitor_B,
|
||||
ControlPanel_R,
|
||||
ControlPanel_G,
|
||||
ControlPanel_B,
|
||||
Cabinet_R,
|
||||
Cabinet_G,
|
||||
Cabinet_B,
|
||||
} popn_lights_t;
|
||||
}
|
||||
|
||||
|
||||
@@ -19,11 +19,13 @@
|
||||
#include "util/sysutils.h"
|
||||
#include "io.h"
|
||||
#include "util/deferlog.h"
|
||||
#include "misc/nativetouchhook.h"
|
||||
#include "misc/wintouchemu.h"
|
||||
|
||||
namespace games::popn {
|
||||
|
||||
bool SHOW_PIKA_MONITOR_WARNING = false;
|
||||
bool NATIVE_TOUCH = false;
|
||||
|
||||
#if SPICE64 && !SPICE_XP
|
||||
|
||||
@@ -36,39 +38,83 @@ namespace games::popn {
|
||||
// pin 1 = left pop (red pop kun), size 16, values 0-0xFF
|
||||
// pin 2 = right pop (blue pop kun), size 16, values 0-0xFF
|
||||
// pin 3 = title, size 44, values 0-0xFF
|
||||
// pin 4 = speaker, size 40, values 0-0xFF - U region only
|
||||
// pin 4 = speaker, size 40, values 0-0x7F - U region only
|
||||
// pin 5 = monitor, size 18, values 0-0x7F - U region only
|
||||
// pin 6 = control panel, size 28, values 0-0x7F - U region only
|
||||
// pin 7 = cabinet, size 22, values 0-0x7F - U region only
|
||||
tapeledutils::tape_led TAPELED_MAPPING[POPN_TAPELED_TOTAL] = {
|
||||
{
|
||||
0, // these are button lights and handled specially
|
||||
// [0] button lights: these are button lights and handled specially
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
"Invalid"
|
||||
},
|
||||
{
|
||||
// [1] red pop-kun
|
||||
5, // 5*3; game reports 16 but make it 15
|
||||
Lights::popn_lights_t::RedPopKun_R,
|
||||
Lights::popn_lights_t::RedPopKun_G,
|
||||
Lights::popn_lights_t::RedPopKun_B,
|
||||
0xFF,
|
||||
"Red Pop-Kun"
|
||||
},
|
||||
{
|
||||
// [2] blue pop-kun
|
||||
5, // 5*3; game reports 16 but make it 15
|
||||
Lights::popn_lights_t::BluePopKun_R,
|
||||
Lights::popn_lights_t::BluePopKun_G,
|
||||
Lights::popn_lights_t::BluePopKun_B,
|
||||
0xFF,
|
||||
"Blue Pop-Kun"
|
||||
},
|
||||
{
|
||||
14, // 14*3; game reports 44 but make it 42; these are lights above the banner
|
||||
// [3] top LED
|
||||
14, // 14*3; game reports 44 but make it 42
|
||||
Lights::popn_lights_t::TopLED_R,
|
||||
Lights::popn_lights_t::TopLED_G,
|
||||
Lights::popn_lights_t::TopLED_B,
|
||||
0xFF,
|
||||
"Top"
|
||||
},
|
||||
{
|
||||
// [4] speakers
|
||||
13, // 13*3; game reports 40 but make it 39
|
||||
Lights::popn_lights_t::Speaker_G,
|
||||
Lights::popn_lights_t::Speaker_R,
|
||||
Lights::popn_lights_t::Speaker_B,
|
||||
0x7F,
|
||||
"Speakers"
|
||||
},
|
||||
{
|
||||
// [5] monitor
|
||||
6,
|
||||
Lights::popn_lights_t::Monitor_G,
|
||||
Lights::popn_lights_t::Monitor_R,
|
||||
Lights::popn_lights_t::Monitor_B,
|
||||
0x7F,
|
||||
"Monitor"
|
||||
},
|
||||
{
|
||||
// [6] control panel
|
||||
9, // 9*3; game reports 28
|
||||
Lights::popn_lights_t::ControlPanel_G,
|
||||
Lights::popn_lights_t::ControlPanel_R,
|
||||
Lights::popn_lights_t::ControlPanel_B,
|
||||
0x7F,
|
||||
"Control Panel"
|
||||
},
|
||||
{
|
||||
// [7] Cabinet
|
||||
7, // 7*3; game reports 22
|
||||
Lights::popn_lights_t::Cabinet_G,
|
||||
Lights::popn_lights_t::Cabinet_R,
|
||||
Lights::popn_lights_t::Cabinet_B,
|
||||
0x7F,
|
||||
"Cabinet"
|
||||
},
|
||||
};
|
||||
|
||||
|
||||
@@ -670,9 +716,13 @@ namespace games::popn {
|
||||
// set third column to 0 and it will work with BIO2
|
||||
|
||||
if (!GRAPHICS_WINDOWED) {
|
||||
wintouchemu::FORCE = true;
|
||||
wintouchemu::INJECT_MOUSE_AS_WM_TOUCH = true;
|
||||
wintouchemu::hook_title_ends("", "Main Screen", avs::game::DLL_INSTANCE);
|
||||
if (NATIVE_TOUCH) {
|
||||
nativetouchhook::hook(avs::game::DLL_INSTANCE);
|
||||
} else {
|
||||
wintouchemu::FORCE = true;
|
||||
wintouchemu::INJECT_MOUSE_AS_WM_TOUCH = true;
|
||||
wintouchemu::hook_title_ends("", "Main Screen", avs::game::DLL_INSTANCE);
|
||||
}
|
||||
}
|
||||
|
||||
sysutils::hook_EnumDisplayDevicesA();
|
||||
|
||||
@@ -17,11 +17,12 @@ namespace games::popn {
|
||||
}
|
||||
|
||||
#if SPICE64
|
||||
constexpr int POPN_TAPELED_TOTAL = 4;
|
||||
constexpr int POPN_TAPELED_TOTAL = 8;
|
||||
extern tapeledutils::tape_led TAPELED_MAPPING[POPN_TAPELED_TOTAL];
|
||||
#endif
|
||||
|
||||
extern bool SHOW_PIKA_MONITOR_WARNING;
|
||||
extern bool NATIVE_TOUCH;
|
||||
|
||||
class POPNGame : public games::Game {
|
||||
public:
|
||||
|
||||
@@ -66,14 +66,16 @@ static HRESULT STDAPICALLTYPE CoCreateInstance_hook(
|
||||
if (FAILED(ret)) {
|
||||
if (IsEqualCLSID(rclsid, CLSID_MMDeviceEnumerator)) {
|
||||
log_warning("audio", "CoCreateInstance failed for CLSID_MMDeviceEnumerator, hr={}", FMT_HRESULT(ret));
|
||||
}
|
||||
|
||||
// Windows 11 KB5052093 issue - reverb DMO went missing from dsdmo.dll (fails with 0x80040154)
|
||||
if (IsEqualCLSID(rclsid, CLSID_DirectSoundI3DL2ReverbDMO) && ret == (HRESULT)0x80040154) {
|
||||
log_warning(
|
||||
"audio",
|
||||
"CoCreateInstance for CLSID_DirectSoundI3DL2ReverbDMO failed with 0x80040154, swap with CLSID_DirectSoundWavesReverbDMO "
|
||||
"(workaround for Windows 11 KB5052093 issue); REVERB EX replaced with REVERB");
|
||||
} else if (IsEqualCLSID(rclsid, CLSID_DirectSoundI3DL2ReverbDMO)) {
|
||||
// deal with reverb DMO missing from dsdmo.dll
|
||||
// it usually fails with 0x80040154 (REGDB_E_CLASSNOTREG), but we have also seen 0x8007007e (ERROR_MOD_NOT_FOUND)
|
||||
static std::once_flag printed;
|
||||
std::call_once(printed, [ret]() {
|
||||
log_warning(
|
||||
"audio",
|
||||
"CoCreateInstance for CLSID_DirectSoundI3DL2ReverbDMO failed with {}, swap with CLSID_DirectSoundWavesReverbDMO...",
|
||||
FMT_HRESULT(ret));
|
||||
});
|
||||
ret = CoCreateInstance_orig(CLSID_DirectSoundWavesReverbDMO, pUnkOuter, dwClsContext, riid, ppv);
|
||||
if (FAILED(ret)) {
|
||||
log_warning("audio", "CoCreateInstance(CLSID_DirectSoundWavesReverbDMO...) failed, hr={}", FMT_HRESULT(ret));
|
||||
|
||||
@@ -476,6 +476,14 @@ static HWND WINAPI CreateWindowExW_hook(DWORD dwExStyle, LPCWSTR lpClassName, LP
|
||||
}
|
||||
}
|
||||
|
||||
// FTT
|
||||
if (avs::game::is_model("MMD")) {
|
||||
// set window name
|
||||
if (!lpWindowName) {
|
||||
lpWindowName = L"Future TomTom";
|
||||
}
|
||||
}
|
||||
|
||||
if (GRAPHICS_WINDOWED) {
|
||||
graphics_window_check_bounds_before_creation(x, y, nWidth, nHeight);
|
||||
}
|
||||
@@ -924,6 +932,9 @@ void graphics_hook_subscreen_window(HWND hWnd) {
|
||||
if (GRAPHICS_WSUB_ALWAYS_ON_TOP) {
|
||||
graphics_update_z_order(hWnd, true);
|
||||
}
|
||||
if (GRAPHICS_WINDOW_DISABLE_ROUNDED_CORNERS) {
|
||||
graphics_set_corner_preference(hWnd, true);
|
||||
}
|
||||
}
|
||||
|
||||
void graphics_screens_register(int screen) {
|
||||
|
||||
@@ -7,6 +7,9 @@
|
||||
|
||||
#include <windows.h>
|
||||
#include <d3d9.h>
|
||||
#if !SPICE_XP
|
||||
#include <dwmapi.h>
|
||||
#endif
|
||||
|
||||
#include "external/toojpeg/toojpeg.h"
|
||||
|
||||
@@ -50,6 +53,7 @@ extern std::optional<std::pair<uint32_t, uint32_t>> GRAPHICS_WINDOW_SIZE;
|
||||
extern std::optional<std::string> GRAPHICS_WINDOW_POS;
|
||||
extern bool GRAPHICS_WINDOW_ALWAYS_ON_TOP;
|
||||
extern bool GRAPHICS_WINDOW_BACKBUFFER_SCALE;
|
||||
extern bool GRAPHICS_WINDOW_DISABLE_ROUNDED_CORNERS;
|
||||
extern std::optional<HWND> GRAPHICS_HOOKED_WINDOW;
|
||||
|
||||
extern bool GRAPHICS_IIDX_WSUB;
|
||||
@@ -103,6 +107,7 @@ void graphics_windowed_wndproc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lPara
|
||||
void graphics_capture_initial_window(HWND hWnd);
|
||||
void graphics_update_window_style(HWND hWnd, bool force_update=false);
|
||||
void graphics_update_z_order(HWND hWnd, bool always_on_top);
|
||||
void graphics_set_corner_preference(HWND hWnd, bool disable);
|
||||
void graphics_move_resize_window(HWND hWnd);
|
||||
bool graphics_window_options_breaks_game();
|
||||
bool graphics_window_decoration_change_crashes_game();
|
||||
|
||||
@@ -24,6 +24,7 @@ std::optional<std::pair<uint32_t, uint32_t>> GRAPHICS_WINDOW_SIZE;
|
||||
std::optional<std::string> GRAPHICS_WINDOW_POS;
|
||||
bool GRAPHICS_WINDOW_ALWAYS_ON_TOP = false;
|
||||
bool GRAPHICS_WINDOW_BACKBUFFER_SCALE = false;
|
||||
bool GRAPHICS_WINDOW_DISABLE_ROUNDED_CORNERS = false;
|
||||
std::optional<HWND> GRAPHICS_HOOKED_WINDOW;
|
||||
|
||||
// IIDX Windowed Subscreen - starts out as false, enabled by IIDX module on pre-attach as needed
|
||||
@@ -132,6 +133,10 @@ void graphics_capture_initial_window(HWND hWnd) {
|
||||
log_info("graphics-windowed", "[{}] change window z-order - always on top", fmt::ptr(hWnd));
|
||||
graphics_update_z_order(hWnd, true);
|
||||
}
|
||||
if (cfg::SCREENRESIZE->window_disable_round_corners) {
|
||||
log_info("graphics-windowed", "[{}] disabling rounded corners", fmt::ptr(hWnd));
|
||||
graphics_set_corner_preference(hWnd, true);
|
||||
}
|
||||
|
||||
// ensure spicetouch coordinates are initialized
|
||||
update_spicetouch_window_dimensions(hWnd);
|
||||
@@ -181,6 +186,10 @@ void graphics_load_windowed_parameters() {
|
||||
cfg::SCREENRESIZE->window_always_on_top = true;
|
||||
}
|
||||
|
||||
if (GRAPHICS_WINDOW_DISABLE_ROUNDED_CORNERS) {
|
||||
cfg::SCREENRESIZE->window_disable_round_corners = true;
|
||||
}
|
||||
|
||||
log_debug("graphics-windowed", "graphics_load_windowed_parameters returned");
|
||||
}
|
||||
|
||||
@@ -469,6 +478,27 @@ void graphics_update_z_order(HWND hWnd, bool always_on_top) {
|
||||
log_debug("graphics-windowed", "graphics_update_z_order returned");
|
||||
}
|
||||
|
||||
void graphics_set_corner_preference(HWND hWnd, bool disable) {
|
||||
if (!GRAPHICS_WINDOWED) {
|
||||
return;
|
||||
}
|
||||
|
||||
#if !SPICE_XP
|
||||
log_debug("graphics-windowed", "graphics_set_corner_preference called");
|
||||
|
||||
DWM_WINDOW_CORNER_PREFERENCE corner_preference = disable ? DWMWCP_DONOTROUND : DWMWCP_DEFAULT;
|
||||
DwmSetWindowAttribute(
|
||||
hWnd,
|
||||
DWMWA_WINDOW_CORNER_PREFERENCE,
|
||||
&corner_preference, sizeof(corner_preference));
|
||||
|
||||
log_debug("graphics-windowed", "graphics_set_corner_preference returned");
|
||||
#else
|
||||
// don't link against DwmSetWindowAttribute on XP
|
||||
log_debug("graphics-windowed", "graphics_set_corner_preference called; ignoring");
|
||||
#endif
|
||||
}
|
||||
|
||||
void graphics_move_resize_window(HWND hWnd) {
|
||||
if (!GRAPHICS_WINDOWED) {
|
||||
return;
|
||||
@@ -502,8 +532,8 @@ bool graphics_window_decoration_change_crashes_game() {
|
||||
static std::once_flag flag;
|
||||
static bool result = false;
|
||||
std::call_once(flag, []() {
|
||||
// ddr crashes when frame style changes
|
||||
if (avs::game::is_model("MDX")) {
|
||||
// ddr and ftt crash when frame style changes
|
||||
if (avs::game::is_model("MDX") || avs::game::is_model("MMD")) {
|
||||
result = true;
|
||||
}
|
||||
|
||||
|
||||
@@ -597,6 +597,9 @@ int main_implementation(int argc, char *argv[]) {
|
||||
if (options[launcher::Options::PopnSubMonitorOverride].is_active()) {
|
||||
sysutils::SECOND_MONITOR_OVERRIDE = options[launcher::Options::PopnSubMonitorOverride].value_text();
|
||||
}
|
||||
if (options[launcher::Options::PopnNativeTouch].value_bool()) {
|
||||
games::popn::NATIVE_TOUCH = true;
|
||||
}
|
||||
if (options[launcher::Options::LoadMetalGearArcadeModule].value_bool()) {
|
||||
attach_mga = true;
|
||||
}
|
||||
@@ -1117,6 +1120,7 @@ int main_implementation(int argc, char *argv[]) {
|
||||
}
|
||||
GRAPHICS_WINDOW_ALWAYS_ON_TOP = options[launcher::Options::spice2x_WindowAlwaysOnTop].value_bool();
|
||||
GRAPHICS_WINDOW_BACKBUFFER_SCALE = options[launcher::Options::WindowForceScaling].value_bool();
|
||||
GRAPHICS_WINDOW_DISABLE_ROUNDED_CORNERS = options[launcher::Options::WindowDisableRoundedCorners].value_bool();
|
||||
|
||||
// IIDX/SDVX Windowed Subscreen
|
||||
if (options[launcher::Options::spice2x_IIDXWindowedSubscreenSize].is_active()) {
|
||||
@@ -1831,9 +1835,7 @@ int main_implementation(int argc, char *argv[]) {
|
||||
attach_ftt = true;
|
||||
|
||||
// the game is windowed by default unless we set the env
|
||||
if (GRAPHICS_WINDOWED) {
|
||||
GRAPHICS_WINDOWED = false;
|
||||
} else {
|
||||
if (!GRAPHICS_WINDOWED) {
|
||||
SetEnvironmentVariable("DAMAC_VIEWER_FULLSCREEN", "0");
|
||||
}
|
||||
|
||||
@@ -2362,9 +2364,9 @@ int main_implementation(int argc, char *argv[]) {
|
||||
// layeredfs
|
||||
if (fileutils::dir_exists("data_mods") &&
|
||||
GetModuleHandleA("ifs_hook.dll") == nullptr) {
|
||||
log_warning("launcher", "data_mods directory found, but ifs_hook.dll is not present; mods will not load");
|
||||
log_warning("launcher", "data_mods directory found, but ifs_hook.dll is not loaded; mods will not load");
|
||||
deferredlogs::defer_error_messages({
|
||||
"data_mods directory was found, but ifs_hook.dll is not present",
|
||||
"data_mods directory was found, but ifs_hook.dll is not loaded",
|
||||
" your mods will not load",
|
||||
" to fix this, download ifs_layeredfs and add it as a DLL hook (-k)",
|
||||
" https://github.com/mon/ifs_layeredfs"
|
||||
|
||||
@@ -32,6 +32,7 @@ static const std::vector<std::string> CATEGORY_ORDER_BASIC = {
|
||||
|
||||
static const std::vector<std::string> CATEGORY_ORDER_ADVANCED = {
|
||||
"Game Options (Advanced)",
|
||||
"Game Options (Peripherals)",
|
||||
"Overlay",
|
||||
"Network (Advanced)",
|
||||
"Performance",
|
||||
@@ -513,7 +514,7 @@ static const std::vector<OptionDefinition> OPTION_DEFINITIONS = {
|
||||
.desc = "Flip the camera order.",
|
||||
.type = OptionType::Bool,
|
||||
.game_name = "Beatmania IIDX",
|
||||
.category = "Game Options (Advanced)",
|
||||
.category = "Game Options (Peripherals)",
|
||||
},
|
||||
{
|
||||
// IIDXDisableCameras
|
||||
@@ -523,7 +524,7 @@ static const std::vector<OptionDefinition> OPTION_DEFINITIONS = {
|
||||
.type = OptionType::Bool,
|
||||
.hidden = true,
|
||||
.game_name = "Beatmania IIDX",
|
||||
.category = "Game Options",
|
||||
.category = "Game Options (Peripherals)",
|
||||
},
|
||||
{
|
||||
// IIDXCabCamAccess
|
||||
@@ -533,7 +534,7 @@ static const std::vector<OptionDefinition> OPTION_DEFINITIONS = {
|
||||
"Only turn this on if you have OFFICIAL arcade cameras connected to the correct USB ports. Default: auto.",
|
||||
.type = OptionType::Enum,
|
||||
.game_name = "Beatmania IIDX",
|
||||
.category = "Game Options (Advanced)",
|
||||
.category = "Game Options (Peripherals)",
|
||||
.elements = {
|
||||
{"auto", ""},
|
||||
{"off", ""},
|
||||
@@ -549,7 +550,7 @@ static const std::vector<OptionDefinition> OPTION_DEFINITIONS = {
|
||||
.desc = "Experimental camera support for IIDX 27+ via texture hooking. Requires camera(s) that support YUY2 or NV12 encoding.",
|
||||
.type = OptionType::Bool,
|
||||
.game_name = "Beatmania IIDX",
|
||||
.category = "Game Options (Advanced)",
|
||||
.category = "Game Options (Peripherals)",
|
||||
},
|
||||
{
|
||||
// IIDXCamHookRatio
|
||||
@@ -561,7 +562,7 @@ static const std::vector<OptionDefinition> OPTION_DEFINITIONS = {
|
||||
.type = OptionType::Enum,
|
||||
.hidden = true,
|
||||
.game_name = "Beatmania IIDX",
|
||||
.category = "Game Options (Advanced)",
|
||||
.category = "Game Options (Peripherals)",
|
||||
.elements = {
|
||||
{"43", "4:3"},
|
||||
{"169", "16:9"},
|
||||
@@ -579,7 +580,7 @@ static const std::vector<OptionDefinition> OPTION_DEFINITIONS = {
|
||||
.type = OptionType::Text,
|
||||
.setting_name = "0x5817a0,0x6fffbd8,0xbbae40,0xe0,0x30",
|
||||
.game_name = "Beatmania IIDX",
|
||||
.category = "Game Options (Advanced)",
|
||||
.category = "Game Options (Peripherals)",
|
||||
},
|
||||
{
|
||||
// IIDXCamHookTopId
|
||||
@@ -594,7 +595,7 @@ static const std::vector<OptionDefinition> OPTION_DEFINITIONS = {
|
||||
.type = OptionType::Text,
|
||||
.setting_name = "vid_1234&pid_5678",
|
||||
.game_name = "Beatmania IIDX",
|
||||
.category = "Game Options (Advanced)",
|
||||
.category = "Game Options (Peripherals)",
|
||||
},
|
||||
{
|
||||
// IIDXCamHookFrontId
|
||||
@@ -609,7 +610,7 @@ static const std::vector<OptionDefinition> OPTION_DEFINITIONS = {
|
||||
.type = OptionType::Text,
|
||||
.setting_name = "vid_90ab&pid_cdef",
|
||||
.game_name = "Beatmania IIDX",
|
||||
.category = "Game Options (Advanced)",
|
||||
.category = "Game Options (Peripherals)",
|
||||
},
|
||||
{
|
||||
.title = "IIDX Sound Output Device",
|
||||
@@ -772,11 +773,11 @@ static const std::vector<OptionDefinition> OPTION_DEFINITIONS = {
|
||||
.category = "Game Options (Advanced)",
|
||||
},
|
||||
{
|
||||
.title = "SDVX Force 720p",
|
||||
.title = "SDVX Vivid Wave Force 720p Window (DEPRECATED - use -windowsize instead)",
|
||||
.name = "sdvx720",
|
||||
.desc = "Force Sound Voltex 720p display mode, used by older games. "
|
||||
"For newer games, use window resize function instead.",
|
||||
.desc = "Old & deprecated option for launching Vivid Wave in 720p when using windowed mode.",
|
||||
.type = OptionType::Bool,
|
||||
.hidden = true,
|
||||
.game_name = "Sound Voltex",
|
||||
.category = "Game Options (Advanced)",
|
||||
},
|
||||
@@ -786,7 +787,7 @@ static const std::vector<OptionDefinition> OPTION_DEFINITIONS = {
|
||||
.desc = "Enable Sound Voltex printer emulation.",
|
||||
.type = OptionType::Bool,
|
||||
.game_name = "Sound Voltex",
|
||||
.category = "Game Options (Advanced)",
|
||||
.category = "Game Options (Peripherals)",
|
||||
},
|
||||
{
|
||||
// SDVXPrinterOutputPath
|
||||
@@ -795,7 +796,7 @@ static const std::vector<OptionDefinition> OPTION_DEFINITIONS = {
|
||||
.desc = "Path to folder where images will be stored.",
|
||||
.type = OptionType::Text,
|
||||
.game_name = "Sound Voltex",
|
||||
.category = "Game Options (Advanced)",
|
||||
.category = "Game Options (Peripherals)",
|
||||
.picker = OptionPickerType::DirectoryPath,
|
||||
},
|
||||
{
|
||||
@@ -804,7 +805,7 @@ static const std::vector<OptionDefinition> OPTION_DEFINITIONS = {
|
||||
.desc = "Clean up saved images in the output directory on startup.",
|
||||
.type = OptionType::Bool,
|
||||
.game_name = "Sound Voltex",
|
||||
.category = "Game Options (Advanced)",
|
||||
.category = "Game Options (Peripherals)",
|
||||
},
|
||||
{
|
||||
.title = "SDVX Printer Output Overwrite",
|
||||
@@ -812,7 +813,7 @@ static const std::vector<OptionDefinition> OPTION_DEFINITIONS = {
|
||||
.desc = "Always overwrite the same file in output directory.",
|
||||
.type = OptionType::Bool,
|
||||
.game_name = "Sound Voltex",
|
||||
.category = "Game Options (Advanced)",
|
||||
.category = "Game Options (Peripherals)",
|
||||
},
|
||||
{
|
||||
// SDVXPrinterOutputFormat
|
||||
@@ -822,7 +823,7 @@ static const std::vector<OptionDefinition> OPTION_DEFINITIONS = {
|
||||
.type = OptionType::Text,
|
||||
.setting_name = "(png/bmp/tga/jpg)",
|
||||
.game_name = "Sound Voltex",
|
||||
.category = "Game Options (Advanced)",
|
||||
.category = "Game Options (Peripherals)",
|
||||
},
|
||||
{
|
||||
.title = "SDVX Printer JPG Quality",
|
||||
@@ -831,7 +832,7 @@ static const std::vector<OptionDefinition> OPTION_DEFINITIONS = {
|
||||
.type = OptionType::Integer,
|
||||
.setting_name = "(0-100)",
|
||||
.game_name = "Sound Voltex",
|
||||
.category = "Game Options (Advanced)",
|
||||
.category = "Game Options (Peripherals)",
|
||||
},
|
||||
{
|
||||
.title = "SDVX Disable Cameras (DEPRECATED - no longer needed)",
|
||||
@@ -842,7 +843,7 @@ static const std::vector<OptionDefinition> OPTION_DEFINITIONS = {
|
||||
.type = OptionType::Bool,
|
||||
.hidden = true,
|
||||
.game_name = "Sound Voltex",
|
||||
.category = "Game Options",
|
||||
.category = "Game Options (Peripherals)",
|
||||
},
|
||||
{
|
||||
.title = "SDVX FS Subscreen Native Touch Handling",
|
||||
@@ -1008,6 +1009,18 @@ static const std::vector<OptionDefinition> OPTION_DEFINITIONS = {
|
||||
.category = "Monitor",
|
||||
.picker = OptionPickerType::Monitor,
|
||||
},
|
||||
{
|
||||
// PopnNativeTouch
|
||||
.title = "Pop'n Music PikaPika Native Touch Handling",
|
||||
.name = "popnnativetouch",
|
||||
.desc = "Disables touch hooks and lets the game access a touch screen directly. "
|
||||
"Requires a touch screen to be connected as a secondary monitor. "
|
||||
"Touch input must be routed to the primary screen via Windows Tablet PC settings. "
|
||||
"Enable this when you get duplicate touch inputs from an actual touch screen.",
|
||||
.type = OptionType::Bool,
|
||||
.game_name = "Pop'n Music",
|
||||
.category = "Game Options (Advanced)",
|
||||
},
|
||||
{
|
||||
.title = "Force Load HELLO! Pop'n Music Module",
|
||||
.name = "hpm",
|
||||
@@ -2218,6 +2231,14 @@ static const std::vector<OptionDefinition> OPTION_DEFINITIONS = {
|
||||
.type = OptionType::Bool,
|
||||
.category = "Graphics (Windowed)",
|
||||
},
|
||||
{
|
||||
// WindowDisableRoundedCorners
|
||||
.title = "Disable Round Window Corners",
|
||||
.name = "windownoroundcorners",
|
||||
.desc = "Windows 11 and above only: Disables rounded corners on the game window(s).",
|
||||
.type = OptionType::Bool,
|
||||
.category = "Graphics (Windowed)",
|
||||
},
|
||||
{
|
||||
// spice2x_IIDXWindowedSubscreenSize
|
||||
.title = "IIDX Windowed Subscreen Size",
|
||||
@@ -2347,7 +2368,7 @@ static const std::vector<OptionDefinition> OPTION_DEFINITIONS = {
|
||||
"Note: this is NOT for the motion camera - you still need a real RealSense camera for that!",
|
||||
.type = OptionType::Bool,
|
||||
.game_name = "DANCERUSH",
|
||||
.category = "Game Options",
|
||||
.category = "Game Options (Peripherals)",
|
||||
},
|
||||
{
|
||||
// spice2x_IIDXNativeTouch
|
||||
@@ -2681,7 +2702,7 @@ static const std::vector<OptionDefinition> OPTION_DEFINITIONS = {
|
||||
.desc = "Allow game to access camera; camera must be compatible with game.",
|
||||
.type = OptionType::Bool,
|
||||
.game_name = "LovePlus",
|
||||
.category = "Game Options",
|
||||
.category = "Game Options (Peripherals)",
|
||||
},
|
||||
{
|
||||
// LovePlusPrinterOutputPath
|
||||
@@ -2690,7 +2711,7 @@ static const std::vector<OptionDefinition> OPTION_DEFINITIONS = {
|
||||
.desc = "Path to folder where images will be stored.",
|
||||
.type = OptionType::Text,
|
||||
.game_name = "LovePlus",
|
||||
.category = "Game Options (Advanced)",
|
||||
.category = "Game Options (Peripherals)",
|
||||
.picker = OptionPickerType::DirectoryPath,
|
||||
},
|
||||
{
|
||||
@@ -2699,7 +2720,7 @@ static const std::vector<OptionDefinition> OPTION_DEFINITIONS = {
|
||||
.desc = "Clean up saved images in the output directory on startup.",
|
||||
.type = OptionType::Bool,
|
||||
.game_name = "LovePlus",
|
||||
.category = "Game Options (Advanced)",
|
||||
.category = "Game Options (Peripherals)",
|
||||
},
|
||||
{
|
||||
.title = "LovePlus Printer Output Overwrite",
|
||||
@@ -2707,7 +2728,7 @@ static const std::vector<OptionDefinition> OPTION_DEFINITIONS = {
|
||||
.desc = "Always overwrite the same file in output directory.",
|
||||
.type = OptionType::Bool,
|
||||
.game_name = "LovePlus",
|
||||
.category = "Game Options (Advanced)",
|
||||
.category = "Game Options (Peripherals)",
|
||||
},
|
||||
{
|
||||
// LovePlusPrinterOutputFormat
|
||||
@@ -2717,7 +2738,7 @@ static const std::vector<OptionDefinition> OPTION_DEFINITIONS = {
|
||||
.type = OptionType::Text,
|
||||
.setting_name = "(png/bmp/tga/jpg)",
|
||||
.game_name = "LovePlus",
|
||||
.category = "Game Options (Advanced)",
|
||||
.category = "Game Options (Peripherals)",
|
||||
},
|
||||
{
|
||||
.title = "LovePlus Printer JPG Quality",
|
||||
@@ -2726,7 +2747,7 @@ static const std::vector<OptionDefinition> OPTION_DEFINITIONS = {
|
||||
.type = OptionType::Integer,
|
||||
.setting_name = "(0-100)",
|
||||
.game_name = "LovePlus",
|
||||
.category = "Game Options (Advanced)",
|
||||
.category = "Game Options (Peripherals)",
|
||||
},
|
||||
{
|
||||
// OptionConflictResolution
|
||||
@@ -2747,7 +2768,7 @@ static const std::vector<OptionDefinition> OPTION_DEFINITIONS = {
|
||||
"option to bypass camera error during boot, allowing you to try out the game.",
|
||||
.type = OptionType::Bool,
|
||||
.game_name = "Otoca D'or",
|
||||
.category = "Game Options",
|
||||
.category = "Game Options (Peripherals)",
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -101,6 +101,7 @@ namespace launcher {
|
||||
PopnMusicForceSDMode,
|
||||
PopnNoSub,
|
||||
PopnSubMonitorOverride,
|
||||
PopnNativeTouch,
|
||||
LoadHelloPopnMusicModule,
|
||||
LoadGitaDoraModule,
|
||||
GitaDoraTwoChannelAudio,
|
||||
@@ -232,6 +233,7 @@ namespace launcher {
|
||||
spice2x_WindowPosition,
|
||||
spice2x_WindowAlwaysOnTop,
|
||||
WindowForceScaling,
|
||||
WindowDisableRoundedCorners,
|
||||
spice2x_IIDXWindowedSubscreenSize,
|
||||
spice2x_IIDXWindowedSubscreenPosition,
|
||||
IIDXWindowedSubscreenBorderless,
|
||||
|
||||
@@ -86,13 +86,12 @@ namespace launcher {
|
||||
if (LAUNCHER_ARGC > 0) {
|
||||
|
||||
// build cmd line
|
||||
std::stringstream cmd_line;
|
||||
cmd_line << "START \"\" ";
|
||||
std::string cmd_line = "START \"\" ";
|
||||
for (int i = 0; i < LAUNCHER_ARGC; i++)
|
||||
cmd_line << " \"" << LAUNCHER_ARGV[i] << "\"";
|
||||
cmd_line += " \"" + std::string(LAUNCHER_ARGV[i]) + "\"";
|
||||
|
||||
// run command
|
||||
system(cmd_line.str().c_str());
|
||||
system(cmd_line.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
#include "external/imgui/misc/cpp/imgui_stdlib.h"
|
||||
#include "games/io.h"
|
||||
#include "games/sdvx/sdvx.h"
|
||||
#include "games/popn/popn.h"
|
||||
#include "avs/core.h"
|
||||
#include "avs/ea3.h"
|
||||
#include "avs/game.h"
|
||||
@@ -283,18 +284,8 @@ namespace overlay::windows {
|
||||
|
||||
// keypad buttons
|
||||
ImGui::TextUnformatted("");
|
||||
if (this->games_selected_name == "Beatmania IIDX") {
|
||||
ImGui::Indent(INDENT);
|
||||
ImGui::TextColored(
|
||||
ImVec4(1, 0.5f, 0.5f, 1.f),
|
||||
"WARNING: Lightning Model (TDJ) I/O will ignore the keypad!");
|
||||
ImGui::TextWrapped(
|
||||
"Use Toggle Sub Screen button to show the overlay and use your mouse, "
|
||||
"connect using SpiceCompanion app, or connect a touch screen to enter "
|
||||
"the PIN.");
|
||||
ImGui::Unindent(INDENT);
|
||||
ImGui::TextUnformatted("");
|
||||
}
|
||||
this->build_keypad_warning();
|
||||
|
||||
auto keypad_buttons = games::get_buttons_keypads(this->games_selected_name);
|
||||
auto keypad_count = eamuse_get_game_keypads_name();
|
||||
if (keypad_count == 1) {
|
||||
@@ -602,6 +593,34 @@ namespace overlay::windows {
|
||||
}
|
||||
}
|
||||
|
||||
void Config::build_keypad_warning() {
|
||||
// not checking the -iidxtdj option here, we could do that in the future
|
||||
const bool is_tdj = this->games_selected_name == "Beatmania IIDX";
|
||||
|
||||
// not using games::popn::is_pikapika_model() here since that always returns false on 32-bit
|
||||
const bool is_popn = this->games_selected_name == "Pop'n Music" && avs::game::SPEC[0] == 'D';
|
||||
if (!is_tdj && !is_popn) {
|
||||
return;
|
||||
}
|
||||
|
||||
ImGui::Indent(INDENT);
|
||||
if (is_tdj) {
|
||||
ImGui::TextColored(
|
||||
ImVec4(1, 0.5f, 0.5f, 1.f),
|
||||
"WARNING: Lightning Model (TDJ) I/O will ignore keypad number input!");
|
||||
} else if (is_popn) {
|
||||
ImGui::TextColored(
|
||||
ImVec4(1, 0.5f, 0.5f, 1.f),
|
||||
"WARNING: PikaPika Pop-Kun model will ignore keypad number input!");
|
||||
}
|
||||
ImGui::TextWrapped(
|
||||
"Use Toggle Sub Screen button (Overlay tab) to show the overlay and use your mouse, "
|
||||
"connect using SpiceCompanion app, or connect a touch screen to enter "
|
||||
"the PIN.");
|
||||
ImGui::Unindent(INDENT);
|
||||
ImGui::TextUnformatted("");
|
||||
}
|
||||
|
||||
void Config::build_buttons(const std::string &name, std::vector<Button> *buttons, int min, int max) {
|
||||
ImGui::AlignTextToFramePadding();
|
||||
ImGui::TextColored(ImVec4(1.f, 0.7f, 0, 1), "%s Buttons", name.c_str());
|
||||
@@ -1044,6 +1063,7 @@ namespace overlay::windows {
|
||||
button->setAnalogType(BAT_NONE);
|
||||
button->setDebounceUp(0.0);
|
||||
button->setDebounceDown(0.0);
|
||||
button->setBatThreshold(0);
|
||||
button->setVelocityThreshold(0);
|
||||
button->setInvert(false);
|
||||
button->setLastState(GameAPI::Buttons::BUTTON_NOT_PRESSED);
|
||||
@@ -1246,6 +1266,7 @@ namespace overlay::windows {
|
||||
button->setAnalogType(bat);
|
||||
button->setDebounceUp(0.0);
|
||||
button->setDebounceDown(0.0);
|
||||
button->setBatThreshold(0);
|
||||
button->setVelocityThreshold(0);
|
||||
::Config::getInstance().updateBinding(
|
||||
games_list[games_selected], *button,
|
||||
@@ -1294,6 +1315,7 @@ namespace overlay::windows {
|
||||
button->setAnalogType(buffer[0]);
|
||||
button->setDebounceUp(0.0);
|
||||
button->setDebounceDown(0.0);
|
||||
button->setBatThreshold(0);
|
||||
button->setVelocityThreshold(0);
|
||||
::Config::getInstance().updateBinding(
|
||||
games_list[games_selected], *button,
|
||||
@@ -1341,6 +1363,7 @@ namespace overlay::windows {
|
||||
button->setAnalogType(BAT_NONE);
|
||||
button->setDebounceUp(0.0);
|
||||
button->setDebounceDown(0.0);
|
||||
button->setBatThreshold(0);
|
||||
// same idea as setMidiVKey - keep velocity threshold consistent
|
||||
button->setVelocityThreshold(
|
||||
device->midiInfo->v2_velocity_threshold[button->getVKey()]);
|
||||
@@ -1366,6 +1389,7 @@ namespace overlay::windows {
|
||||
button->setAnalogType(BAT_MIDI_CTRL_PRECISION);
|
||||
button->setDebounceUp(0.0);
|
||||
button->setDebounceDown(0.0);
|
||||
button->setBatThreshold(0);
|
||||
button->setVelocityThreshold(0);
|
||||
::Config::getInstance().updateBinding(
|
||||
games_list[games_selected], *button,
|
||||
@@ -1392,6 +1416,7 @@ namespace overlay::windows {
|
||||
button->setAnalogType(BAT_MIDI_CTRL_SINGLE);
|
||||
button->setDebounceUp(0.0);
|
||||
button->setDebounceDown(0.0);
|
||||
button->setBatThreshold(0);
|
||||
button->setVelocityThreshold(0);
|
||||
::Config::getInstance().updateBinding(
|
||||
games_list[games_selected], *button,
|
||||
@@ -1418,6 +1443,7 @@ namespace overlay::windows {
|
||||
button->setAnalogType(BAT_MIDI_CTRL_ONOFF);
|
||||
button->setDebounceUp(0.0);
|
||||
button->setDebounceDown(0.0);
|
||||
button->setBatThreshold(0);
|
||||
button->setVelocityThreshold(0);
|
||||
::Config::getInstance().updateBinding(
|
||||
games_list[games_selected], *button,
|
||||
@@ -1443,6 +1469,7 @@ namespace overlay::windows {
|
||||
button->setAnalogType(BAT_MIDI_PITCH_DOWN);
|
||||
button->setDebounceUp(0.0);
|
||||
button->setDebounceDown(0.0);
|
||||
button->setBatThreshold(0);
|
||||
button->setVelocityThreshold(0);
|
||||
::Config::getInstance().updateBinding(
|
||||
games_list[games_selected], *button,
|
||||
@@ -1463,6 +1490,7 @@ namespace overlay::windows {
|
||||
button->setAnalogType(BAT_MIDI_PITCH_UP);
|
||||
button->setDebounceUp(0.0);
|
||||
button->setDebounceDown(0.0);
|
||||
button->setBatThreshold(0);
|
||||
button->setVelocityThreshold(0);
|
||||
::Config::getInstance().updateBinding(
|
||||
games_list[games_selected], *button,
|
||||
@@ -1492,6 +1520,7 @@ namespace overlay::windows {
|
||||
button->setAnalogType(BAT_NONE);
|
||||
button->setDebounceUp(0.0);
|
||||
button->setDebounceDown(0.0);
|
||||
button->setBatThreshold(0);
|
||||
button->setVelocityThreshold(0);
|
||||
::Config::getInstance().updateBinding(
|
||||
games_list[games_selected], *button,
|
||||
@@ -1616,6 +1645,7 @@ namespace overlay::windows {
|
||||
button->setVKey(vKey);
|
||||
button->setDebounceUp(0.0);
|
||||
button->setDebounceDown(0.0);
|
||||
button->setBatThreshold(0);
|
||||
button->setVelocityThreshold(0);
|
||||
::Config::getInstance().updateBinding(
|
||||
games_list[games_selected], *button,
|
||||
@@ -1667,6 +1697,9 @@ namespace overlay::windows {
|
||||
button->setDeviceIdentifier(device.name);
|
||||
// reset controls when switching devices
|
||||
button->setAnalogType(ButtonAnalogType::BAT_NONE);
|
||||
button->setDebounceUp(0.0);
|
||||
button->setDebounceDown(0.0);
|
||||
button->setBatThreshold(0);
|
||||
button->setVelocityThreshold(0);
|
||||
button->setVKey(0);
|
||||
button->setInvert(false);
|
||||
@@ -2031,11 +2064,48 @@ namespace overlay::windows {
|
||||
|
||||
// invert
|
||||
bool invert = button->getInvert();
|
||||
if (ImGui::Checkbox("Invert", &invert)) {
|
||||
if (ImGui::Checkbox("Invert Resulting Value", &invert)) {
|
||||
button->setInvert(invert);
|
||||
dirty = true;
|
||||
}
|
||||
|
||||
// bat threshold
|
||||
if (device->type == rawinput::HID &&
|
||||
(button->getAnalogType() == BAT_POSITIVE || button->getAnalogType() == BAT_NEGATIVE)) {
|
||||
int bat_threshold = button->getBatThreshold();
|
||||
|
||||
bool is_active = (bat_threshold > 0);
|
||||
if (ImGui::Checkbox("Custom Analog Threshold", &is_active)) {
|
||||
if (!is_active) {
|
||||
button->setBatThreshold(0);
|
||||
} else if (bat_threshold == 0) {
|
||||
button->setBatThreshold(60);
|
||||
}
|
||||
dirty = true;
|
||||
}
|
||||
ImGui::SameLine();
|
||||
ImGui::HelpMarker(
|
||||
"Assuming that 50% is the center, value exceeding 60% triggers the button by default. "
|
||||
"With this option, you can customize the trigger threshold.\n\n"
|
||||
"Setting this to 51% means tiny movements will trigger the button (small deadzone), "
|
||||
"while setting this to 99% means the button will only trigger at maximum value (large deadzone).\n\n"
|
||||
"Setting this to below 50% adjusts the neutral / center position.");
|
||||
|
||||
if (is_active) {
|
||||
if (ImGui::SliderInt(
|
||||
"Analog Threshold",
|
||||
&bat_threshold,
|
||||
1, 99,
|
||||
"%d%%",
|
||||
ImGuiSliderFlags_AlwaysClamp)) {
|
||||
button->setBatThreshold(bat_threshold);
|
||||
}
|
||||
if (ImGui::IsItemDeactivatedAfterEdit()) {
|
||||
dirty = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// state display
|
||||
ImGui::TextUnformatted("");
|
||||
if (device != nullptr && device->type == rawinput::MIDI) {
|
||||
@@ -5264,6 +5334,7 @@ namespace overlay::windows {
|
||||
btn.setInvert(entry->invert);
|
||||
btn.setDebounceUp(entry->debounce_up);
|
||||
btn.setDebounceDown(entry->debounce_down);
|
||||
btn.setBatThreshold(entry->bat_threshold);
|
||||
btn.setVelocityThreshold(entry->velocity_threshold);
|
||||
::Config::getInstance().updateBinding(game, btn, -1);
|
||||
} else {
|
||||
@@ -5274,6 +5345,7 @@ namespace overlay::windows {
|
||||
alt_btn.setInvert(entry->invert);
|
||||
alt_btn.setDebounceUp(entry->debounce_up);
|
||||
alt_btn.setDebounceDown(entry->debounce_down);
|
||||
alt_btn.setBatThreshold(entry->bat_threshold);
|
||||
alt_btn.setVelocityThreshold(entry->velocity_threshold);
|
||||
alt_btn.setTemporary(true);
|
||||
btn.getAlternatives().push_back(alt_btn);
|
||||
|
||||
@@ -193,13 +193,15 @@ namespace overlay::windows {
|
||||
std::vector<Option> *options, const std::string &category, const std::string *filter=nullptr);
|
||||
void build_about();
|
||||
void build_launcher();
|
||||
void launch_shell(LPCSTR app, LPCSTR file=nullptr);
|
||||
void build_keypad_warning();
|
||||
|
||||
void launch_shell(LPCSTR app, LPCSTR file=nullptr);
|
||||
|
||||
void build_menu(int *game_selected);
|
||||
void shutdown_system(bool force, bool reboot_instead);
|
||||
|
||||
|
||||
void set_alternating_row_colors(const int row_index);
|
||||
|
||||
|
||||
bool validate_ea_card(char card_number[16]);
|
||||
|
||||
public:
|
||||
|
||||
@@ -628,13 +628,12 @@ namespace overlay::windows {
|
||||
ImGui::Text("Wheel: %ld", mouse->pos_wheel);
|
||||
|
||||
// keys
|
||||
std::stringstream keys;
|
||||
keys << "[";
|
||||
std::string keys = "[";
|
||||
for (auto key : mouse->key_states) {
|
||||
keys << (key ? "1," : "0,");
|
||||
keys += (key ? "1," : "0,");
|
||||
}
|
||||
keys << "]";
|
||||
ImGui::Text("Keys: %s", keys.str().c_str());
|
||||
keys += "]";
|
||||
ImGui::Text("Keys: %s", keys.c_str());
|
||||
|
||||
break;
|
||||
}
|
||||
@@ -643,15 +642,14 @@ namespace overlay::windows {
|
||||
ImGui::Text("Type: Keyboard");
|
||||
|
||||
// keys
|
||||
std::stringstream keys;
|
||||
keys << "[";
|
||||
std::string keys = "[";
|
||||
for (size_t i = 0; i < std::size(keyboard->key_states); i++) {
|
||||
if (keyboard->key_states[i]) {
|
||||
keys << i << ",";
|
||||
keys += std::to_string(i) + ",";
|
||||
}
|
||||
}
|
||||
keys << "]";
|
||||
ImGui::Text("Keys: %s", keys.str().c_str());
|
||||
keys += "]";
|
||||
ImGui::Text("Keys: %s", keys.c_str());
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -17,6 +17,7 @@ namespace overlay::windows {
|
||||
bool invert = false;
|
||||
double debounce_up = 0.0;
|
||||
double debounce_down = 0.0;
|
||||
int bat_threshold = 0;
|
||||
unsigned short velocity_threshold = 0;
|
||||
|
||||
bool is_naive() const { return device_identifier.empty() && vKey != INVALID_VKEY; }
|
||||
@@ -31,6 +32,7 @@ namespace overlay::windows {
|
||||
e.invert = btn.getInvert();
|
||||
e.debounce_up = btn.getDebounceUp();
|
||||
e.debounce_down = btn.getDebounceDown();
|
||||
e.bat_threshold = btn.getBatThreshold();
|
||||
e.velocity_threshold = btn.getVelocityThreshold();
|
||||
return e;
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
|
||||
#include "avs/game.h"
|
||||
#include "games/iidx/iidx.h"
|
||||
#include "games/popn/popn.h"
|
||||
#include "misc/eamuse.h"
|
||||
#include "util/logging.h"
|
||||
#include "overlay/imgui/extensions.h"
|
||||
@@ -42,6 +43,8 @@ namespace overlay::windows {
|
||||
void Keypad::build_content() {
|
||||
if (avs::game::is_model("LDJ") && games::iidx::TDJ_MODE) {
|
||||
build_tdj_keypad();
|
||||
} else if (games::popn::is_pikapika_model()) {
|
||||
build_popn_pika_keypad();
|
||||
} else {
|
||||
build_keypad();
|
||||
}
|
||||
@@ -132,4 +135,26 @@ namespace overlay::windows {
|
||||
eamuse_set_keypad_overrides_overlay(this->unit, 0);
|
||||
}
|
||||
}
|
||||
|
||||
void Keypad::build_popn_pika_keypad() {
|
||||
ImGui::AlignTextToFramePadding();
|
||||
ImGui::TextDisabled("Keypad disabled in Pop'n Pikapika model!\nUse subscreen overlay.");
|
||||
ImGui::SameLine();
|
||||
ImGui::WarnMarker(
|
||||
nullptr,
|
||||
"Pop'n Music Pikapika cabinets do not have any keypads; they use the subscreen.\n\n"
|
||||
"Fullscreen mode: bind a key in Overlay tab, and press it in game to show the subscreen, "
|
||||
"then use your mouse to click. Page Up button is the default binding.\n\n"
|
||||
"Windowed mode: look for the second window in the taskbar (or ALT+TAB).\n\n"
|
||||
"Windowed mode with -popnnosub: bring up the subscreen overlay (default Page Up).\n\n"
|
||||
);
|
||||
|
||||
ImGui::Spacing();
|
||||
|
||||
if (ImGui::Button("Insert Card")) {
|
||||
eamuse_set_keypad_overrides_overlay(this->unit, 1 << EAM_IO_INSERT);
|
||||
} else {
|
||||
eamuse_set_keypad_overrides_overlay(this->unit, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,6 +10,7 @@ namespace overlay::windows {
|
||||
size_t unit = 0;
|
||||
void build_keypad();
|
||||
void build_tdj_keypad();
|
||||
void build_popn_pika_keypad();
|
||||
|
||||
public:
|
||||
|
||||
|
||||
@@ -605,16 +605,6 @@ void rawinput::RawInputManager::devices_scan_rawinput(RAWINPUTDEVICELIST *device
|
||||
value_caps.LogicalMax = 255;
|
||||
}
|
||||
|
||||
// fix min and max values
|
||||
if (value_caps.BitSize > 0 && value_caps.BitSize <= sizeof(value_caps.LogicalMin) * 8) {
|
||||
auto shift_size = sizeof(value_caps.LogicalMin) * 8 - value_caps.BitSize + 1;
|
||||
auto mask = ((uint64_t) 1 << value_caps.BitSize) - 1;
|
||||
value_caps.LogicalMin &= mask;
|
||||
value_caps.LogicalMin <<= shift_size;
|
||||
value_caps.LogicalMin >>= shift_size;
|
||||
value_caps.LogicalMax &= mask;
|
||||
}
|
||||
|
||||
// fix up hat switch to initially report as neutral position
|
||||
if (value_caps.UsagePage == 0x1 && value_caps.Range.UsageMin == 0x39) {
|
||||
value_states[value_cap_num] = -1.f;
|
||||
@@ -1914,15 +1904,6 @@ LRESULT CALLBACK rawinput::RawInputManager::input_wnd_proc(
|
||||
LONG value_min = value_caps.LogicalMin;
|
||||
LONG value_max = value_caps.LogicalMax;
|
||||
|
||||
// fix sign bits for signed values
|
||||
if (value_caps.LogicalMin < 0 &&
|
||||
value_caps.BitSize > 0 &&
|
||||
value_caps.BitSize <= sizeof(value_caps.LogicalMin) * 8) {
|
||||
auto shift_size = sizeof(value_caps.LogicalMin) * 8 - value_caps.BitSize + 1;
|
||||
value_raw <<= shift_size;
|
||||
value_raw >>= shift_size;
|
||||
}
|
||||
|
||||
float value;
|
||||
// 0x1 == generic desktop, 0x39 == hat switch
|
||||
if (value_caps.UsagePage == 0x1 && value_caps.Range.UsageMin == 0x39) {
|
||||
@@ -1935,6 +1916,16 @@ LRESULT CALLBACK rawinput::RawInputManager::input_wnd_proc(
|
||||
value = -1.f;
|
||||
}
|
||||
} else {
|
||||
|
||||
// fix sign bits for signed values
|
||||
if (value_caps.LogicalMin < 0 &&
|
||||
0 < value_caps.BitSize && value_caps.BitSize < 32) {
|
||||
|
||||
ULONG raw = static_cast<ULONG>(value_raw) & ((1u << value_caps.BitSize) - 1u);
|
||||
const ULONG sign_bit = 1u << (value_caps.BitSize - 1);
|
||||
value_raw = static_cast<LONG>((raw ^ sign_bit) - sign_bit);
|
||||
}
|
||||
|
||||
// automatic calibration
|
||||
if (value_raw < value_min) {
|
||||
value_caps.LogicalMin = value_raw;
|
||||
|
||||
@@ -99,7 +99,7 @@ namespace rawinput::touch {
|
||||
|
||||
// check type
|
||||
if (device->type != HID) {
|
||||
log_fatal("rawinput", "touch update called on non HID device");
|
||||
log_warning("rawinput", "touch update called on non HID device");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -192,8 +192,10 @@ namespace rawinput::touch {
|
||||
contact_count = std::max(contact_count, (size_t) hid->value_states_raw[index]);
|
||||
}
|
||||
|
||||
// https://learn.microsoft.com/en-us/windows-hardware/design/component-guidelines/touchscreen-packet-reporting-modes
|
||||
// hybrid mode devices will report a contact count of 0 for subsequent reports that are
|
||||
// part of the same initial frame
|
||||
// most laptops and touchscreens are like this - they have the contact count set to 5 but can actually report up to 10 fingers
|
||||
if (contact_count > 0) {
|
||||
if (contact_count > touch_report_count) {
|
||||
touch.remaining_contact_count = contact_count - touch_report_count;
|
||||
@@ -216,6 +218,12 @@ namespace rawinput::touch {
|
||||
touch_points.reserve(touch.elements_x.size());
|
||||
for (size_t i = 0; i < touch.elements_x.size(); i++) {
|
||||
|
||||
// if there are no more touch events to handle, exit out early
|
||||
if (touch_report_count == 0) {
|
||||
break;
|
||||
}
|
||||
touch_report_count--;
|
||||
|
||||
// build touch point
|
||||
HIDTouchPoint hid_tp{};
|
||||
auto pos_x = hid->value_states[touch.elements_x[i]];
|
||||
@@ -247,17 +255,6 @@ namespace rawinput::touch {
|
||||
hid_tp.y = 1.f - hid_tp.y;
|
||||
}
|
||||
|
||||
// check if this touch point should be considered valid
|
||||
//
|
||||
// If "Contact count" reports there are no touch reports remaining and the X and Y
|
||||
// coordinates of this touch point are zero, then this report element should be
|
||||
// skipped.
|
||||
if (touch_report_count == 0 && hid_tp.x == 0.f && hid_tp.y == 0.f) {
|
||||
continue;
|
||||
} else if (touch_report_count > 0) {
|
||||
touch_report_count--;
|
||||
}
|
||||
|
||||
// generate ID (hopefully unique)
|
||||
hid_tp.id = (DWORD) hid->value_states_raw[touch.elements_contact_identifier[i]];
|
||||
hid_tp.id += (DWORD) (0xFFFFFF + device->id * 512);
|
||||
|
||||
@@ -219,20 +219,21 @@ intptr_t replace_pattern(HMODULE module, const std::string &signature,
|
||||
strreplace(pattern_str, "??", "00");
|
||||
auto pattern_bin = std::make_unique<uint8_t[]>(signature.length() / 2);
|
||||
if (!hex2bin(pattern_str.c_str(), pattern_bin.get())) {
|
||||
return false;
|
||||
return 0;
|
||||
}
|
||||
|
||||
// build signature mask
|
||||
std::ostringstream signature_mask;
|
||||
std::string signature_mask;
|
||||
signature_mask.reserve(signature.size() / 2);
|
||||
for (size_t i = 0; i < signature.length(); i += 2) {
|
||||
if (signature[i] == '?') {
|
||||
if (signature[i + 1] == '?') {
|
||||
signature_mask << '?';
|
||||
signature_mask += '?';
|
||||
} else {
|
||||
return false;
|
||||
return 0;
|
||||
}
|
||||
} else {
|
||||
signature_mask << 'X';
|
||||
signature_mask += 'X';
|
||||
}
|
||||
}
|
||||
|
||||
@@ -241,20 +242,21 @@ intptr_t replace_pattern(HMODULE module, const std::string &signature,
|
||||
strreplace(replace_data_str, "??", "00");
|
||||
auto replace_data_bin = std::make_unique<uint8_t[]>(replacement.length() / 2);
|
||||
if (!hex2bin(replace_data_str.c_str(), replace_data_bin.get())) {
|
||||
return false;
|
||||
return 0;
|
||||
}
|
||||
|
||||
// build replace mask
|
||||
std::ostringstream replace_mask;
|
||||
std::string replace_mask;
|
||||
replace_mask.reserve(replacement.size() / 2);
|
||||
for (size_t i = 0; i < replacement.length(); i += 2) {
|
||||
if (replacement[i] == '?') {
|
||||
if (replacement[i + 1] == '?') {
|
||||
replace_mask << '?';
|
||||
replace_mask += '?';
|
||||
} else {
|
||||
return false;
|
||||
return 0;
|
||||
}
|
||||
} else {
|
||||
replace_mask << 'X';
|
||||
replace_mask += 'X';
|
||||
}
|
||||
}
|
||||
|
||||
@@ -262,11 +264,11 @@ intptr_t replace_pattern(HMODULE module, const std::string &signature,
|
||||
return replace_pattern(
|
||||
module,
|
||||
pattern_bin.get(),
|
||||
signature_mask.str().c_str(),
|
||||
signature_mask.c_str(),
|
||||
offset,
|
||||
usage,
|
||||
replace_data_bin.get(),
|
||||
replace_mask.str().c_str()
|
||||
replace_mask.c_str()
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -9,7 +9,7 @@ namespace tapeledutils {
|
||||
}
|
||||
|
||||
// for bi2x-style byte array of all colors and LEDs at once
|
||||
rgb_float3_t pick_color_from_led_tape(uint8_t *data, size_t data_size) {
|
||||
static rgb_float3_t pick_color_from_led_tape_internal(uint8_t *data, size_t data_size, uint8_t divisor) {
|
||||
rgb_float3_t result = {0.f, 0.f, 0.f};
|
||||
if (TAPE_LED_ALGORITHM == TAPE_LED_USE_AVERAGE) {
|
||||
|
||||
@@ -25,7 +25,7 @@ namespace tapeledutils {
|
||||
}
|
||||
|
||||
// normalize
|
||||
const float avg_mult = 1.f / (data_size * 255);
|
||||
const float avg_mult = 1.f / (data_size * divisor);
|
||||
result.r = avg_ri * avg_mult;
|
||||
result.g = avg_gi * avg_mult;
|
||||
result.b = avg_bi * avg_mult;
|
||||
@@ -50,7 +50,7 @@ namespace tapeledutils {
|
||||
}
|
||||
|
||||
// normalize
|
||||
const float single_mult = 1.f / 255;
|
||||
const float single_mult = 1.f / divisor;
|
||||
result.r = color[0] * single_mult;
|
||||
result.g = color[1] * single_mult;
|
||||
result.b = color[2] * single_mult;
|
||||
@@ -58,6 +58,15 @@ namespace tapeledutils {
|
||||
return result;
|
||||
}
|
||||
|
||||
rgb_float3_t pick_color_from_led_tape(tape_led &light, uint8_t *data, size_t data_size) {
|
||||
const auto max_value = (light.max_value > 0) ? light.max_value : 0xFF;
|
||||
return pick_color_from_led_tape_internal(data, data_size, max_value);
|
||||
}
|
||||
|
||||
rgb_float3_t pick_color_from_led_tape(uint8_t *data, size_t data_size) {
|
||||
return pick_color_from_led_tape_internal(data, data_size, 0xFF);
|
||||
}
|
||||
|
||||
// for bi2a-style that calls for each individual LED
|
||||
size_t get_led_index_using_avg_algo(size_t data_size) {
|
||||
size_t index_to_use;
|
||||
|
||||
@@ -25,13 +25,33 @@ namespace tapeledutils {
|
||||
struct tape_led {
|
||||
std::vector<rgb_float3_t> data;
|
||||
int index_r, index_g, index_b; // Averaged RGB light output indexes
|
||||
uint8_t max_value;
|
||||
std::string lightName;
|
||||
|
||||
tape_led(size_t data_size, int index_r, int index_g, int index_b, std::string lightName)
|
||||
: data(std::vector<rgb_float3_t>(data_size)), index_r(index_r), index_g(index_g), index_b(index_b), lightName(std::move(lightName)) {}
|
||||
tape_led(
|
||||
size_t data_size,
|
||||
int index_r, int index_g, int index_b,
|
||||
std::string lightName)
|
||||
: data(
|
||||
std::vector<rgb_float3_t>(data_size)),
|
||||
index_r(index_r), index_g(index_g), index_b(index_b),
|
||||
max_value(0),
|
||||
lightName(std::move(lightName)) {}
|
||||
|
||||
tape_led(
|
||||
size_t data_size,
|
||||
int index_r, int index_g, int index_b,
|
||||
uint8_t max_value,
|
||||
std::string lightName)
|
||||
: data(
|
||||
std::vector<rgb_float3_t>(data_size)),
|
||||
index_r(index_r), index_g(index_g), index_b(index_b),
|
||||
max_value(max_value),
|
||||
lightName(std::move(lightName)) {}
|
||||
};
|
||||
|
||||
bool is_enabled();
|
||||
rgb_float3_t pick_color_from_led_tape(tape_led &light, uint8_t *data, size_t data_size);
|
||||
rgb_float3_t pick_color_from_led_tape(uint8_t *data, size_t data_size);
|
||||
size_t get_led_index_using_avg_algo(size_t data_size);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user