mirror of
https://github.com/spice2x/spice2x.github.io.git
synced 2026-08-01 22:30:42 -07:00
Compare commits
9 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 1e6b4c16cc | |||
| d6eb8f7125 | |||
| dc6850e479 | |||
| 2d623e179b | |||
| 884d665c1c | |||
| 2842fe7ec6 | |||
| 954e6022d9 | |||
| 955c50a9f3 | |||
| dc82c980b1 |
@@ -7,7 +7,7 @@
|
||||
>
|
||||
> Feel free to remove this section after you have read it.
|
||||
|
||||
## Link to GitHub Issue, if one exists
|
||||
## Link to GitHub Issue or related Pull Request, if one exists
|
||||
#0
|
||||
|
||||
## Description of change
|
||||
|
||||
@@ -34,7 +34,7 @@ namespace api::modules {
|
||||
void DRS::touch_set(Request &req, Response &res) {
|
||||
|
||||
// get all touch points
|
||||
games::drs::drs_touch_t touches[16];
|
||||
auto touches = std::make_unique<games::drs::drs_touch_t[]>(req.params.Size());
|
||||
size_t i = 0;
|
||||
for (Value ¶m : req.params.GetArray()) {
|
||||
|
||||
@@ -86,6 +86,6 @@ namespace api::modules {
|
||||
}
|
||||
|
||||
// apply touch points
|
||||
games::drs::fire_touches(touches, i);
|
||||
games::drs::fire_touches(touches.get(), i);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,6 +13,15 @@ enum class OptionType {
|
||||
Hex,
|
||||
};
|
||||
|
||||
enum class OptionPickerType {
|
||||
None,
|
||||
AsioDriver,
|
||||
EACard,
|
||||
CpuAffinity,
|
||||
FilePath,
|
||||
DirectoryPath,
|
||||
};
|
||||
|
||||
struct OptionDefinition {
|
||||
std::string title;
|
||||
// unique identifier used for flag matching but also stored in config files
|
||||
@@ -32,6 +41,10 @@ struct OptionDefinition {
|
||||
bool sensitive = false;
|
||||
std::vector<std::pair<std::string, std::string>> elements = {};
|
||||
bool disabled = false;
|
||||
OptionPickerType picker = OptionPickerType::None;
|
||||
|
||||
// for OptionPickerType::FilePath
|
||||
std::string file_extension = "";
|
||||
};
|
||||
|
||||
class Option {
|
||||
|
||||
@@ -82,6 +82,7 @@ namespace games::iidx {
|
||||
bool IIDXIO_LED_TICKER_READONLY = false;
|
||||
std::mutex IIDX_LED_TICKER_LOCK;
|
||||
bool IIDX_TDJ_MONITOR_WARNING = false;
|
||||
iidx_aio_emulation_state CURRENT_IO_EMULATION_STATE = iidx_aio_emulation_state::unknown;
|
||||
|
||||
// io
|
||||
static bool HAS_LIBAIO; // this is how we detect iidx27+
|
||||
@@ -453,7 +454,7 @@ namespace games::iidx {
|
||||
}
|
||||
|
||||
// windowed subscreen, enabled by default, unless turned off by user
|
||||
if (GRAPHICS_WINDOWED && !options->at(launcher::Options::spice2x_IIDXNoSub).value_bool()) {
|
||||
if (GRAPHICS_WINDOWED && !options->at(launcher::Options::spice2x_IIDXNoSub).value_bool() && TDJ_MODE) {
|
||||
GRAPHICS_IIDX_WSUB = true;
|
||||
}
|
||||
|
||||
@@ -934,6 +935,8 @@ namespace games::iidx {
|
||||
return;
|
||||
}
|
||||
|
||||
CURRENT_IO_EMULATION_STATE = state;
|
||||
|
||||
// log_warning below could be turned into log_fatal in the future once we gain confidence
|
||||
// that this isn't triggering when it's not supposed to
|
||||
if (state == iidx_aio_emulation_state::bi2a_com2 && TDJ_MODE) {
|
||||
|
||||
@@ -11,6 +11,12 @@
|
||||
|
||||
namespace games::iidx {
|
||||
|
||||
enum class iidx_aio_emulation_state {
|
||||
unknown,
|
||||
bi2a_com2,
|
||||
bi2x_hook
|
||||
};
|
||||
|
||||
// settings
|
||||
|
||||
extern bool FLIP_CAMS;
|
||||
@@ -38,6 +44,7 @@ namespace games::iidx {
|
||||
constexpr int IIDX_TAPELED_TOTAL = 17;
|
||||
// data mapping
|
||||
extern tapeledutils::tape_led TAPELED_MAPPING[IIDX_TAPELED_TOTAL];
|
||||
extern iidx_aio_emulation_state CURRENT_IO_EMULATION_STATE;
|
||||
|
||||
class IIDXGame : public games::Game {
|
||||
public:
|
||||
@@ -64,9 +71,5 @@ namespace games::iidx {
|
||||
bool is_tdj_fhd();
|
||||
void apply_audio_hacks();
|
||||
|
||||
enum class iidx_aio_emulation_state {
|
||||
bi2a_com2,
|
||||
bi2x_hook
|
||||
};
|
||||
void update_io_emulation_state(iidx_aio_emulation_state state);
|
||||
}
|
||||
|
||||
@@ -21,8 +21,9 @@
|
||||
#include "util/socd_cleaner.h"
|
||||
#include "util/time.h"
|
||||
#include "util/libutils.h"
|
||||
#include "misc/wintouchemu.h"
|
||||
#include "misc/eamuse.h"
|
||||
#include "misc/nativetouchhook.h"
|
||||
#include "misc/wintouchemu.h"
|
||||
#include "bi2x_hook.h"
|
||||
#include "camera.h"
|
||||
#include "io.h"
|
||||
@@ -416,9 +417,11 @@ namespace games::sdvx {
|
||||
}
|
||||
|
||||
if (is_valkyrie_model()) {
|
||||
// hook touch window
|
||||
// in windowed mode, game can accept mouse input on the second screen
|
||||
if (!NATIVETOUCH && !GRAPHICS_WINDOWED) {
|
||||
if (NATIVETOUCH) {
|
||||
nativetouchhook::hook(avs::game::DLL_INSTANCE);
|
||||
} else if (!NATIVETOUCH && !GRAPHICS_WINDOWED) {
|
||||
// hook touch window
|
||||
// in windowed mode, game can accept mouse input on the second screen
|
||||
wintouchemu::FORCE = true;
|
||||
wintouchemu::INJECT_MOUSE_AS_WM_TOUCH = true;
|
||||
wintouchemu::hook_title_ends(
|
||||
|
||||
@@ -42,7 +42,8 @@ namespace hooks::audio {
|
||||
bool USE_DUMMY = false;
|
||||
WAVEFORMATEXTENSIBLE FORMAT {};
|
||||
std::optional<Backend> BACKEND = std::nullopt;
|
||||
size_t ASIO_DRIVER_ID = 0;
|
||||
std::optional<size_t> ASIO_DRIVER_ID = std::nullopt;
|
||||
std::string ASIO_DRIVER_NAME = "";
|
||||
bool ASIO_FORCE_UNLOAD_ON_STOP = false;
|
||||
|
||||
// private globals
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include <optional>
|
||||
#include <string>
|
||||
|
||||
#include <windows.h>
|
||||
#include <mmreg.h>
|
||||
@@ -20,7 +21,8 @@ namespace hooks::audio {
|
||||
extern bool USE_DUMMY;
|
||||
extern WAVEFORMATEXTENSIBLE FORMAT;
|
||||
extern std::optional<Backend> BACKEND;
|
||||
extern size_t ASIO_DRIVER_ID;
|
||||
extern std::optional<size_t> ASIO_DRIVER_ID;
|
||||
extern std::string ASIO_DRIVER_NAME;
|
||||
extern bool ASIO_FORCE_UNLOAD_ON_STOP;
|
||||
extern bool LOW_LATENCY_SHARED_WASAPI;
|
||||
|
||||
|
||||
@@ -218,13 +218,40 @@ void AsioBackend::set_thread_state(AsioThreadState state) {
|
||||
bool AsioBackend::load_driver() {
|
||||
AsioDriverList asio_driver_list;
|
||||
|
||||
for (const auto &driver : asio_driver_list.driver_list) {
|
||||
log_info("audio::asio", "Driver {}", driver.id);
|
||||
log_info("audio::asio", "... Name : {}", driver.name);
|
||||
log_info("audio::asio", "... Path : {}", driver.dll_path);
|
||||
size_t driver_id = 0;
|
||||
std::string driver_name = "";
|
||||
if (hooks::audio::ASIO_DRIVER_ID.has_value()) {
|
||||
driver_id = hooks::audio::ASIO_DRIVER_ID.value();
|
||||
}
|
||||
|
||||
const auto driver_id = hooks::audio::ASIO_DRIVER_ID;
|
||||
for (const auto &driver : asio_driver_list.driver_list) {
|
||||
log_info("audio::asio", " Driver ID : {}", driver.id);
|
||||
log_info("audio::asio", " ... Name : {}", driver.name);
|
||||
log_info("audio::asio", " ... Path : {}", driver.dll_path);
|
||||
|
||||
if (!hooks::audio::ASIO_DRIVER_NAME.empty()) {
|
||||
// match on driver name
|
||||
if (driver.name == hooks::audio::ASIO_DRIVER_NAME) {
|
||||
driver_id = driver.id;
|
||||
driver_name = driver.name;
|
||||
}
|
||||
} else if (driver.id == driver_id) {
|
||||
// match on driver index (0 for default or user-specified)
|
||||
driver_name = driver.name;
|
||||
}
|
||||
}
|
||||
|
||||
if (driver_name.empty()) {
|
||||
if (!hooks::audio::ASIO_DRIVER_NAME.empty()) {
|
||||
log_warning(
|
||||
"audio::asio",
|
||||
"tried to look for ASIO driver but failed: {}", hooks::audio::ASIO_DRIVER_NAME);
|
||||
}
|
||||
log_fatal(
|
||||
"audio::asio",
|
||||
"could not find ASIO driver to use for conversion, fix your audio options and try again");
|
||||
}
|
||||
log_info("audio::asio", "will attempt to use the following ASIO driver: ID = {}, Name = {}", driver_id, driver_name);
|
||||
|
||||
IAsio *driver = nullptr;
|
||||
auto ret = asio_driver_list.open_driver(driver_id, reinterpret_cast<void **>(&driver));
|
||||
|
||||
@@ -1011,18 +1011,26 @@ int main_implementation(int argc, char *argv[]) {
|
||||
if (options[launcher::Options::spice2x_DisableVolumeHook].value_bool()) {
|
||||
hooks::audio::VOLUME_HOOK_ENABLED = false;
|
||||
}
|
||||
|
||||
if (options[launcher::Options::AudioBackend].is_active()) {
|
||||
auto &name = options[launcher::Options::AudioBackend].value_text();
|
||||
auto backend = hooks::audio::name_to_backend(name.c_str());
|
||||
if (!backend.has_value() && !cfg::CONFIGURATOR_STANDALONE) {
|
||||
log_fatal("launcher", "invalid audio backend: {}", name);
|
||||
}
|
||||
|
||||
hooks::audio::BACKEND = backend;
|
||||
}
|
||||
|
||||
if (options[launcher::Options::AsioDriverId].is_active()) {
|
||||
hooks::audio::ASIO_DRIVER_ID = options[launcher::Options::AsioDriverId].value_uint32();
|
||||
}
|
||||
if (options[launcher::Options::AsioDriverName].is_active()) {
|
||||
hooks::audio::BACKEND = hooks::audio::name_to_backend("asio");
|
||||
hooks::audio::ASIO_DRIVER_NAME = options[launcher::Options::AsioDriverName].value_text();
|
||||
// this new option overrides the old one
|
||||
hooks::audio::ASIO_DRIVER_ID.reset();
|
||||
}
|
||||
|
||||
if (options[launcher::Options::AudioDummy].value_bool()) {
|
||||
hooks::audio::USE_DUMMY = true;
|
||||
}
|
||||
|
||||
@@ -71,6 +71,7 @@ static const std::vector<OptionDefinition> OPTION_DEFINITIONS = {
|
||||
.type = OptionType::Text,
|
||||
.setting_name = "*.dll",
|
||||
.category = "Path Overrides",
|
||||
// intentionally not setting a file picker here to discourage people setting this without a good reason
|
||||
},
|
||||
{
|
||||
.title = "Open Configurator",
|
||||
@@ -121,6 +122,7 @@ static const std::vector<OptionDefinition> OPTION_DEFINITIONS = {
|
||||
.setting_name = "E004010000000000",
|
||||
.category = "Network",
|
||||
.sensitive = true,
|
||||
.picker = OptionPickerType::EACard,
|
||||
},
|
||||
{
|
||||
.title = "Player 2 Card",
|
||||
@@ -130,6 +132,7 @@ static const std::vector<OptionDefinition> OPTION_DEFINITIONS = {
|
||||
.setting_name = "E004010000000000",
|
||||
.category = "Network",
|
||||
.sensitive = true,
|
||||
.picker = OptionPickerType::EACard,
|
||||
},
|
||||
{
|
||||
// Player1PinMacro
|
||||
@@ -618,6 +621,7 @@ static const std::vector<OptionDefinition> OPTION_DEFINITIONS = {
|
||||
.type = OptionType::Text,
|
||||
.game_name = "Beatmania IIDX",
|
||||
.category = "Game Options",
|
||||
.picker = OptionPickerType::AsioDriver,
|
||||
},
|
||||
{
|
||||
.title = "IIDX BIO2 Firmware Update",
|
||||
@@ -778,6 +782,7 @@ static const std::vector<OptionDefinition> OPTION_DEFINITIONS = {
|
||||
.type = OptionType::Text,
|
||||
.game_name = "Sound Voltex",
|
||||
.category = "Game Options (Advanced)",
|
||||
.picker = OptionPickerType::DirectoryPath,
|
||||
},
|
||||
{
|
||||
.title = "SDVX Printer Output Clear",
|
||||
@@ -884,11 +889,12 @@ static const std::vector<OptionDefinition> OPTION_DEFINITIONS = {
|
||||
.display_name = "sdvxasio",
|
||||
.aliases= "sdvxasio",
|
||||
.desc = "ASIO driver name to use, replacing XONAR SOUND CARD(64). "
|
||||
"String should match registry key under HLKM\\SOFTWARE\\ASIO\\ \n\n"
|
||||
"String should match registry key under HKLM\\SOFTWARE\\ASIO\\ \n\n"
|
||||
"SDVX is EXTREMELY picky about ASIO devices it can support!",
|
||||
.type = OptionType::Text,
|
||||
.game_name = "Sound Voltex",
|
||||
.category = "Game Options",
|
||||
.picker = OptionPickerType::AsioDriver,
|
||||
},
|
||||
{
|
||||
// spice2x_SDVXSubPos
|
||||
@@ -1284,6 +1290,7 @@ static const std::vector<OptionDefinition> OPTION_DEFINITIONS = {
|
||||
.desc = "Sets a custom path to the modules folder.",
|
||||
.type = OptionType::Text,
|
||||
.category = "Path Overrides",
|
||||
// intentionally not setting a folder picker here to discourage people setting this without a good reason
|
||||
},
|
||||
{
|
||||
.title = "Screenshot Folder Override",
|
||||
@@ -1291,6 +1298,7 @@ static const std::vector<OptionDefinition> OPTION_DEFINITIONS = {
|
||||
.desc = "Sets a custom path to the screenshots folder.",
|
||||
.type = OptionType::Text,
|
||||
.category = "Path Overrides",
|
||||
.picker = OptionPickerType::DirectoryPath,
|
||||
},
|
||||
{
|
||||
.title = "Configuration Path Override",
|
||||
@@ -1310,6 +1318,8 @@ static const std::vector<OptionDefinition> OPTION_DEFINITIONS = {
|
||||
"If left empty, %appdata%\\spice2x\\spicetools_screen_resize.json will be used.",
|
||||
.type = OptionType::Text,
|
||||
.category = "Path Overrides",
|
||||
.picker = OptionPickerType::FilePath,
|
||||
.file_extension = "JSON",
|
||||
},
|
||||
{
|
||||
// PatchManagerConfigPath
|
||||
@@ -1319,6 +1329,8 @@ static const std::vector<OptionDefinition> OPTION_DEFINITIONS = {
|
||||
"If left empty, %appdata%\\spice2x\\spicetools_patch_manager.json will be used.",
|
||||
.type = OptionType::Text,
|
||||
.category = "Path Overrides",
|
||||
.picker = OptionPickerType::FilePath,
|
||||
.file_extension = "JSON",
|
||||
},
|
||||
{
|
||||
.title = "Intel SDE",
|
||||
@@ -1326,6 +1338,7 @@ static const std::vector<OptionDefinition> OPTION_DEFINITIONS = {
|
||||
.desc = "Path to Intel SDE kit path for automatic attaching.",
|
||||
.type = OptionType::Text,
|
||||
.category = "Development",
|
||||
.picker = OptionPickerType::DirectoryPath
|
||||
},
|
||||
{
|
||||
.title = "ea3-config.xml Override",
|
||||
@@ -1333,6 +1346,8 @@ static const std::vector<OptionDefinition> OPTION_DEFINITIONS = {
|
||||
.desc = "Sets a custom path to ea3-config.xml.",
|
||||
.type = OptionType::Text,
|
||||
.category = "Path Overrides",
|
||||
.picker = OptionPickerType::FilePath,
|
||||
.file_extension = "XML",
|
||||
},
|
||||
{
|
||||
.title = "app-config.xml Override",
|
||||
@@ -1340,6 +1355,8 @@ static const std::vector<OptionDefinition> OPTION_DEFINITIONS = {
|
||||
.desc = "Sets a custom path to app-config.xml.",
|
||||
.type = OptionType::Text,
|
||||
.category = "Path Overrides",
|
||||
.picker = OptionPickerType::FilePath,
|
||||
.file_extension = "XML",
|
||||
},
|
||||
{
|
||||
.title = "avs-config.xml Override",
|
||||
@@ -1347,6 +1364,8 @@ static const std::vector<OptionDefinition> OPTION_DEFINITIONS = {
|
||||
.desc = "Sets a custom path to avs-config.xml.",
|
||||
.type = OptionType::Text,
|
||||
.category = "Path Overrides",
|
||||
.picker = OptionPickerType::FilePath,
|
||||
.file_extension = "XML",
|
||||
},
|
||||
{
|
||||
.title = "bootstrap.xml Override",
|
||||
@@ -1354,6 +1373,8 @@ static const std::vector<OptionDefinition> OPTION_DEFINITIONS = {
|
||||
.desc = "Sets a custom path to bootstrap.xml.",
|
||||
.type = OptionType::Text,
|
||||
.category = "Path Overrides",
|
||||
.picker = OptionPickerType::FilePath,
|
||||
.file_extension = "XML",
|
||||
},
|
||||
{
|
||||
.title = "log.txt Override",
|
||||
@@ -1361,6 +1382,8 @@ static const std::vector<OptionDefinition> OPTION_DEFINITIONS = {
|
||||
.desc = "Sets a custom path to log.txt.",
|
||||
.type = OptionType::Text,
|
||||
.category = "Path Overrides",
|
||||
.picker = OptionPickerType::FilePath,
|
||||
.file_extension = "TXT",
|
||||
},
|
||||
{
|
||||
.title = "API TCP Port",
|
||||
@@ -1670,6 +1693,7 @@ static const std::vector<OptionDefinition> OPTION_DEFINITIONS = {
|
||||
"Must provide a hexadecimal mask (e.g., 0x1ff00).",
|
||||
.type = OptionType::Hex,
|
||||
.category = "Performance",
|
||||
.picker = OptionPickerType::CpuAffinity,
|
||||
},
|
||||
{
|
||||
// spice2x_ProcessorEfficiencyClass
|
||||
@@ -1742,11 +1766,13 @@ static const std::vector<OptionDefinition> OPTION_DEFINITIONS = {
|
||||
.category = "Audio (Hacks)",
|
||||
},
|
||||
{
|
||||
.title = "Spice Audio Hook Backend",
|
||||
// AudioBackend
|
||||
.title = "Spice Audio Hook Backend (DEPRECATED - use -asioconvert instead)",
|
||||
.name = "audiobackend",
|
||||
.desc = "Selects the audio backend to use when spice audio hook is enabled, overriding exclusive WASAPI. "
|
||||
"Does nothing for games that do not output to exclusive WASAPI.",
|
||||
.type = OptionType::Enum,
|
||||
.hidden = true,
|
||||
.category = "Audio",
|
||||
.elements = {
|
||||
{"asio", "ASIO"},
|
||||
@@ -1754,12 +1780,26 @@ static const std::vector<OptionDefinition> OPTION_DEFINITIONS = {
|
||||
},
|
||||
},
|
||||
{
|
||||
.title = "Spice Audio Hook ASIO Driver ID",
|
||||
// AsioDriverId
|
||||
.title = "Spice Audio Hook ASIO Driver ID (DEPRECATED - use -asioconvert instead)",
|
||||
.name = "asiodriverid",
|
||||
.desc = "Selects the ASIO driver id to use when Spice Audio Backend is set to ASIO.",
|
||||
.type = OptionType::Integer,
|
||||
.hidden = true,
|
||||
.category = "Audio",
|
||||
},
|
||||
{
|
||||
// AsioDriverName
|
||||
.title = "WASAPI Exclusive to ASIO Conversion",
|
||||
.name = "asioconvert",
|
||||
.desc = "Converts WASAPI Exclusive audio output to ASIO. Value here should match registry key under HKLM\\SOFTWARE\\ASIO\\\n\n"
|
||||
"Use this if the game is configured to use WASAPI Exclusive but you want to use your ASIO driver instead.\n\n"
|
||||
"This should only be used as last resort if your audio device does not support WASAPI Exclusive.\n\n"
|
||||
"Does nothing for games that do not output to exclusive WASAPI.",
|
||||
.type = OptionType::Text,
|
||||
.category = "Audio",
|
||||
.picker = OptionPickerType::AsioDriver,
|
||||
},
|
||||
{
|
||||
.title = "WASAPI Dummy Context",
|
||||
.name = "audiodummy",
|
||||
@@ -2592,6 +2632,7 @@ static const std::vector<OptionDefinition> OPTION_DEFINITIONS = {
|
||||
.type = OptionType::Text,
|
||||
.game_name = "LovePlus",
|
||||
.category = "Game Options (Advanced)",
|
||||
.picker = OptionPickerType::DirectoryPath,
|
||||
},
|
||||
{
|
||||
.title = "LovePlus Printer Output Clear",
|
||||
|
||||
@@ -187,6 +187,7 @@ namespace launcher {
|
||||
spice2x_DisableVolumeHook,
|
||||
AudioBackend,
|
||||
AsioDriverId,
|
||||
AsioDriverName,
|
||||
AudioDummy,
|
||||
DelayBy5Seconds,
|
||||
spice2x_DelayByNSeconds,
|
||||
|
||||
@@ -2,7 +2,10 @@
|
||||
// mingw otherwise doesn't load touch stuff
|
||||
#define _WIN32_WINNT 0x0601
|
||||
|
||||
#include "avs/game.h"
|
||||
#include "wintouchemu.h"
|
||||
#include "rawinput/touch.h"
|
||||
#include "hooks/graphics/graphics.h"
|
||||
|
||||
#include "util/detour.h"
|
||||
#include "util/logging.h"
|
||||
@@ -63,6 +66,11 @@ namespace nativetouchhook {
|
||||
point->cyContact = 0;
|
||||
}
|
||||
|
||||
static void flip_touch_points(PTOUCHINPUT point) {
|
||||
point->x = rawinput::touch::DISPLAY_SIZE_X * 100 - point->x;
|
||||
point->y = rawinput::touch::DISPLAY_SIZE_Y * 100 - point->y;
|
||||
}
|
||||
|
||||
static BOOL WINAPI GetTouchInputInfoHook(
|
||||
HTOUCHINPUT hTouchInput, UINT cInputs, PTOUCHINPUT pInputs, int cbSize) {
|
||||
|
||||
@@ -72,9 +80,28 @@ namespace nativetouchhook {
|
||||
return result;
|
||||
}
|
||||
|
||||
bool flip_values = false;
|
||||
if (avs::game::is_model("KFC") && rawinput::touch::DISPLAY_INITIALIZED) {
|
||||
log_debug(
|
||||
"touch::native", "DISPLAY_ORIENTATION = {}, DISPLAY_SIZE_X = {}, DISPLAY_SIZE_Y = {}",
|
||||
rawinput::touch::DISPLAY_ORIENTATION,
|
||||
rawinput::touch::DISPLAY_SIZE_X,
|
||||
rawinput::touch::DISPLAY_SIZE_Y);
|
||||
if (rawinput::touch::DISPLAY_ORIENTATION == DMDO_270) {
|
||||
flip_values = true;
|
||||
}
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < cInputs; i++) {
|
||||
PTOUCHINPUT point = &pInputs[i];
|
||||
strip_contact_size(point);
|
||||
|
||||
if (avs::game::is_model("LDJ")) {
|
||||
strip_contact_size(point);
|
||||
}
|
||||
|
||||
if (flip_values) {
|
||||
flip_touch_points(point);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
#include "util/logging.h"
|
||||
#include "util/time.h"
|
||||
#include "util/utils.h"
|
||||
#include "rawinput/touch.h"
|
||||
|
||||
#include "avs/game.h"
|
||||
|
||||
@@ -126,6 +127,11 @@ namespace wintouchemu {
|
||||
WINDOW_TITLE_END = window_title_end;
|
||||
}
|
||||
|
||||
static void flip_touch_points(PTOUCHINPUT point) {
|
||||
point->x = rawinput::touch::DISPLAY_SIZE_X * 100 - point->x;
|
||||
point->y = rawinput::touch::DISPLAY_SIZE_Y * 100 - point->y;
|
||||
}
|
||||
|
||||
static BOOL WINAPI GetTouchInputInfoHook(HANDLE hTouchInput, UINT cInputs, PTOUCHINPUT pInputs, int cbSize) {
|
||||
|
||||
// check if original should be called
|
||||
@@ -220,6 +226,12 @@ namespace wintouchemu {
|
||||
touch_input->cxContact = 0;
|
||||
touch_input->cyContact = 0;
|
||||
|
||||
if (avs::game::is_model("KFC") &&
|
||||
rawinput::touch::DISPLAY_INITIALIZED &&
|
||||
rawinput::touch::DISPLAY_ORIENTATION == DMDO_270) {
|
||||
flip_touch_points(touch_input);
|
||||
}
|
||||
|
||||
} else if (USE_MOUSE && !mouse_used) {
|
||||
|
||||
// disable further mouse inputs this call
|
||||
|
||||
@@ -142,7 +142,6 @@ namespace ImGui {
|
||||
ImGui::PopStyleVar();
|
||||
ImGui::PopStyleColor();
|
||||
if (!tooltip.empty() && ImGui::IsItemHovered(TOOLTIP_FLAGS)) {
|
||||
ImGui::SameLine();
|
||||
ImGui::HelpTooltip(tooltip.c_str());
|
||||
}
|
||||
ImGui::PopID();
|
||||
@@ -159,7 +158,6 @@ namespace ImGui {
|
||||
bool clicked = ImGui::Button("\u00D7"); // multiplication sign (×)
|
||||
ImGui::PopStyleColor(4);
|
||||
if (!tooltip.empty() && ImGui::IsItemHovered(TOOLTIP_FLAGS)) {
|
||||
ImGui::SameLine();
|
||||
ImGui::HelpTooltip(tooltip.c_str());
|
||||
}
|
||||
ImGui::PopID();
|
||||
|
||||
@@ -283,7 +283,7 @@ void ImGui_ImplSpice_NewFrame() {
|
||||
memset(io.MouseDown, false, sizeof(io.MouseDown));
|
||||
|
||||
// early quit if window not in focus
|
||||
if (!superexit::has_focus()) {
|
||||
if (!superexit::has_focus() || rawinput::OS_WINDOW_ACTIVE) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -4,13 +4,16 @@
|
||||
|
||||
#include <windows.h>
|
||||
#include <shellapi.h>
|
||||
#include <shlobj.h>
|
||||
#include <commdlg.h>
|
||||
|
||||
#include "build/defs.h"
|
||||
#include "build/resource.h"
|
||||
#include "cfg/config.h"
|
||||
#include "cfg/configurator.h"
|
||||
#include "external/asio/asiolist.h"
|
||||
#include "external/imgui/imgui_internal.h"
|
||||
#include "external/imgui/misc/cpp/imgui_stdlib.h"
|
||||
#include "games/io.h"
|
||||
#include "avs/core.h"
|
||||
#include "avs/ea3.h"
|
||||
@@ -26,6 +29,7 @@
|
||||
#include "util/fileutils.h"
|
||||
#include "util/logging.h"
|
||||
#include "util/resutils.h"
|
||||
#include "util/scope_guard.h"
|
||||
#include "util/time.h"
|
||||
#include "util/utils.h"
|
||||
|
||||
@@ -33,6 +37,17 @@
|
||||
#undef min
|
||||
#endif
|
||||
|
||||
static int CALLBACK BrowseCallbackProc(
|
||||
HWND hwnd,
|
||||
UINT uMsg,
|
||||
LPARAM lParam,
|
||||
LPARAM lpData) {
|
||||
if (uMsg == BFFM_INITIALIZED) {
|
||||
SendMessageW(hwnd, BFFM_SETSELECTIONW, TRUE, lpData);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
namespace overlay::windows {
|
||||
|
||||
// same width as dummy marker
|
||||
@@ -41,6 +56,8 @@ namespace overlay::windows {
|
||||
|
||||
constexpr ImVec4 TEXT_COLOR_GREEN(0.f, 1.f, 0.f, 1.f);
|
||||
|
||||
std::unique_ptr<AsioDriverList> asio_driver_list;
|
||||
|
||||
Config::Config(overlay::SpiceOverlay *overlay) : Window(overlay) {
|
||||
this->title = "Configuration";
|
||||
this->toggle_button = games::OverlayButtons::ToggleConfig;
|
||||
@@ -2707,17 +2724,17 @@ namespace overlay::windows {
|
||||
|
||||
// open dialog to get path
|
||||
auto ofn_path = std::make_unique<wchar_t[]>(512);
|
||||
ofn_path[0] = L'\0';
|
||||
OPENFILENAMEW ofn {};
|
||||
memset(&ofn, 0, sizeof(ofn));
|
||||
ofn.lStructSize = sizeof(ofn);
|
||||
ofn.hwndOwner = nullptr;
|
||||
ofn.lpstrFilter = L"";
|
||||
ofn.lpstrFile = ofn_path.get();
|
||||
ofn.nMaxFile = 512;
|
||||
ofn.Flags = OFN_EXPLORER;
|
||||
ofn.Flags = OFN_EXPLORER | OFN_NOCHANGEDIR;
|
||||
ofn.lpstrDefExt = L"txt";
|
||||
ofn.lpstrInitialDir = L".";
|
||||
|
||||
// check for success
|
||||
auto guard = rawinput::set_os_window_focus_guard();
|
||||
if (GetSaveFileNameW(&ofn)) {
|
||||
|
||||
// update card path
|
||||
@@ -2905,6 +2922,255 @@ namespace overlay::windows {
|
||||
ImGui::EndDisabled();
|
||||
}
|
||||
|
||||
std::string Config::build_option_value_picker_title(const OptionDefinition& definition) {
|
||||
// need to make these all unique since they are also used as ID
|
||||
// if not unique, append ## per ImGui rules to create unique ones
|
||||
switch (definition.picker) {
|
||||
case OptionPickerType::AsioDriver:
|
||||
return "ASIO Driver Picker";
|
||||
case OptionPickerType::EACard:
|
||||
return "EA Card Picker";
|
||||
case OptionPickerType::CpuAffinity:
|
||||
return "CPU Affinity Picker";
|
||||
case OptionPickerType::FilePath:
|
||||
return "File Picker";
|
||||
case OptionPickerType::DirectoryPath:
|
||||
return "Folder Picker";
|
||||
default:
|
||||
return "Unknown Picker";
|
||||
};
|
||||
}
|
||||
|
||||
void Config::build_option_value_picker(Option& option) {
|
||||
auto &definition = option.get_definition();
|
||||
if (definition.picker == OptionPickerType::AsioDriver) {
|
||||
if (asio_driver_list == nullptr) {
|
||||
asio_driver_list = std::make_unique<AsioDriverList>();
|
||||
}
|
||||
|
||||
ImGui::TextUnformatted("If your ASIO driver is not shown here, close this");
|
||||
ImGui::TextUnformatted("popup and enter the driver name manually.");
|
||||
ImGui::SameLine();
|
||||
ImGui::HelpMarker(
|
||||
"This list is populated by scanning the registry for ASIO drivers.\n\n"
|
||||
"If your driver is not showing up, it may be because it is not properly registered in the system.\n\n"
|
||||
"For 64-bit games, check in HKLM\\SOFTWARE\\ASIO\\.\n\n"
|
||||
"For 32-bit games on 64-bit Windows, check in HKLM\\SOFTWARE\\WOW6432Node\\ASIO\\.\n\n"
|
||||
"spicecfg runs in 32-bit, so it may not see 64-bit-only drivers.");
|
||||
|
||||
ImGui::TextUnformatted("");
|
||||
if (asio_driver_list->driver_list.empty()) {
|
||||
ImGui::TextUnformatted("No ASIO drivers found.");
|
||||
} else {
|
||||
ImGui::TextUnformatted("Pick from ASIO drivers:");
|
||||
ImGui::SetNextItemWidth(300.f);
|
||||
if (ImGui::BeginListBox("##asiodrivers")) {
|
||||
for (const auto &driver : asio_driver_list->driver_list) {
|
||||
const bool is_selected = option.value == std::string(driver.name);
|
||||
if (ImGui::Selectable(fmt::format("[{}] {}", driver.id, driver.name).c_str(), is_selected)) {
|
||||
option.value = driver.name;
|
||||
}
|
||||
}
|
||||
ImGui::EndListBox();
|
||||
}
|
||||
}
|
||||
} else if (definition.picker == OptionPickerType::EACard) {
|
||||
ImGui::TextUnformatted("Generate a new card number:");
|
||||
if (ImGui::Button("Generate")) {
|
||||
char new_card[17];
|
||||
generate_ea_card(new_card);
|
||||
option.value = new_card;
|
||||
}
|
||||
} else if (definition.picker == OptionPickerType::CpuAffinity) {
|
||||
ImGui::TextUnformatted("Requires restart! Showing all procs in Group 0.");
|
||||
ImGui::TextUnformatted("");
|
||||
ImGui::TextUnformatted("Pick CPU cores to use:");
|
||||
const uint64_t cpu_count = GetActiveProcessorCount(0);
|
||||
uint64_t affinity = 0;
|
||||
if (!option.value.empty()) {
|
||||
try {
|
||||
affinity = std::stoull(option.value, nullptr, 16);
|
||||
} catch (const std::exception &ex) {
|
||||
option.value = "";
|
||||
affinity = 0;
|
||||
}
|
||||
}
|
||||
ImGui::BeginChild(
|
||||
"##cpuaffinity",
|
||||
ImVec2(
|
||||
0,
|
||||
ImGui::GetFrameHeightWithSpacing() * std::clamp(cpu_count / 4, 2ull, 4ull))
|
||||
);
|
||||
|
||||
bool selection_changed = false;
|
||||
uint64_t set_bits = 0;
|
||||
for (uint64_t i = 0; i < cpu_count; i++) {
|
||||
if (i % 4 != 0) {
|
||||
ImGui::SameLine();
|
||||
}
|
||||
|
||||
bool selected = (affinity & (1ULL << i)) != 0;
|
||||
if (ImGui::Checkbox(fmt::format("CPU {}", i).c_str(), &selected)) {
|
||||
selection_changed = true;
|
||||
if (selected) {
|
||||
affinity |= (1ULL << i);
|
||||
} else {
|
||||
affinity &= ~(1ULL << i);
|
||||
}
|
||||
}
|
||||
if (selected) {
|
||||
set_bits++;
|
||||
}
|
||||
}
|
||||
if (selection_changed) {
|
||||
if (set_bits == 0) {
|
||||
option.value = "";
|
||||
} else {
|
||||
option.value = fmt::format("0x{:X}", affinity);
|
||||
}
|
||||
}
|
||||
|
||||
ImGui::EndChild();
|
||||
if (option.value.empty()) {
|
||||
ImGui::TextUnformatted("Using all CPUs (option default).");
|
||||
} else {
|
||||
ImGui::TextUnformatted("Using selected CPUs.");
|
||||
}
|
||||
} else if (definition.picker == OptionPickerType::FilePath) {
|
||||
if (!cfg::CONFIGURATOR_STANDALONE) {
|
||||
ImGui::BeginDisabled();
|
||||
ImGui::TextUnformatted("File browser only works in spicecfg.");
|
||||
}
|
||||
if (ImGui::Button("Select File...")) {
|
||||
// run in separate thread otherwise we get a crash
|
||||
if (!file_picker_thread) {
|
||||
file_picker_done = false;
|
||||
file_picker_path = "";
|
||||
file_picker_thread = new std::thread([this, &definition] {
|
||||
|
||||
std::wstring extensions;
|
||||
if (!definition.file_extension.empty()) {
|
||||
const std::wstring ext = s2ws(definition.file_extension);
|
||||
// filter to file extension preferred by the option (e.g., DLL)
|
||||
extensions = ext + L" Files (*." + ext + L")";
|
||||
extensions.push_back(L'\0');
|
||||
extensions += L"*." + ext;
|
||||
extensions.push_back(L'\0');
|
||||
// also add "All files" filter
|
||||
extensions += L"All Files (*.*)";
|
||||
extensions.push_back(L'\0');
|
||||
extensions += L"*.*";
|
||||
extensions.push_back(L'\0');
|
||||
// eol
|
||||
extensions.push_back(L'\0');
|
||||
} else {
|
||||
extensions = L"All Files (*.*)";
|
||||
extensions.push_back(L'\0');
|
||||
extensions += L"*.*";
|
||||
extensions.push_back(L'\0');
|
||||
extensions.push_back(L'\0');
|
||||
}
|
||||
|
||||
// open dialog to get path
|
||||
auto ofn_path = std::make_unique<wchar_t[]>(512);
|
||||
ofn_path[0] = L'\0';
|
||||
OPENFILENAMEW ofn{};
|
||||
ofn.lStructSize = sizeof(ofn);
|
||||
ofn.lpstrFilter = extensions.c_str();
|
||||
ofn.lpstrFile = ofn_path.get();
|
||||
ofn.nMaxFile = 512;
|
||||
ofn.nFilterIndex = 1;
|
||||
ofn.Flags = OFN_EXPLORER | OFN_NOCHANGEDIR;
|
||||
ofn.lpstrInitialDir = L".";
|
||||
|
||||
// check for success
|
||||
auto guard = rawinput::set_os_window_focus_guard();
|
||||
if (GetSaveFileNameW(&ofn)) {
|
||||
file_picker_path = std::filesystem::path(ofn_path.get());
|
||||
}
|
||||
|
||||
// clean up
|
||||
file_picker_done = true;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
if (file_picker_done) {
|
||||
file_picker_done = false;
|
||||
file_picker_thread->join();
|
||||
delete file_picker_thread;
|
||||
file_picker_thread = nullptr;
|
||||
if (!file_picker_path.empty()) {
|
||||
option.value = file_picker_path.string();
|
||||
}
|
||||
}
|
||||
|
||||
if (!cfg::CONFIGURATOR_STANDALONE) {
|
||||
ImGui::EndDisabled();
|
||||
}
|
||||
} else if (definition.picker == OptionPickerType::DirectoryPath) {
|
||||
if (!cfg::CONFIGURATOR_STANDALONE) {
|
||||
ImGui::BeginDisabled();
|
||||
ImGui::TextUnformatted("File browser only works in spicecfg.");
|
||||
}
|
||||
if (ImGui::Button("Browse...")) {
|
||||
// run in separate thread otherwise we get a crash
|
||||
if (!file_picker_thread) {
|
||||
file_picker_done = false;
|
||||
file_picker_path = "";
|
||||
file_picker_thread = new std::thread([this] {
|
||||
CoInitializeEx(nullptr, COINIT_APARTMENTTHREADED);
|
||||
|
||||
const auto spice_bin_path =
|
||||
libutils::module_file_name(nullptr).parent_path().wstring();
|
||||
|
||||
// SHBrowseForFolderW sucks, but the alternatives are:
|
||||
// 1. Use IFileDialog, which requires pulling in more Windows dependencies
|
||||
// 2. use ImGui::FileBrowser
|
||||
// both are acceptable but sticking to legacy UI for now for simplicity
|
||||
BROWSEINFOW info{};
|
||||
info.ulFlags = BIF_RETURNONLYFSDIRS | BIF_NEWDIALOGSTYLE;
|
||||
info.lpfn = BrowseCallbackProc;
|
||||
info.lParam = reinterpret_cast<LPARAM>(spice_bin_path.c_str());
|
||||
auto guard = rawinput::set_os_window_focus_guard();
|
||||
auto pidl = SHBrowseForFolderW(&info);
|
||||
if (pidl) {
|
||||
wchar_t path[MAX_PATH];
|
||||
std::filesystem::path result;
|
||||
if (SHGetPathFromIDListW(pidl, path)) {
|
||||
file_picker_path = path;
|
||||
}
|
||||
CoTaskMemFree(pidl);
|
||||
} else {
|
||||
file_picker_path = "";
|
||||
}
|
||||
|
||||
// clean up
|
||||
file_picker_done = true;
|
||||
CoUninitialize();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
if (file_picker_done) {
|
||||
file_picker_done = false;
|
||||
file_picker_thread->join();
|
||||
delete file_picker_thread;
|
||||
file_picker_thread = nullptr;
|
||||
if (!file_picker_path.empty()) {
|
||||
option.value = file_picker_path.string();
|
||||
}
|
||||
}
|
||||
|
||||
if (!cfg::CONFIGURATOR_STANDALONE) {
|
||||
ImGui::EndDisabled();
|
||||
}
|
||||
|
||||
} else {
|
||||
ImGui::TextUnformatted("No picker available for this option. How did you get here?");
|
||||
}
|
||||
}
|
||||
|
||||
void Config::build_options(
|
||||
std::vector<Option> *options, const std::string &category, const std::string *filter) {
|
||||
int options_count;
|
||||
@@ -3183,12 +3449,24 @@ namespace overlay::windows {
|
||||
::Config::getInstance().updateBinding(games_list[games_selected], option);
|
||||
}
|
||||
}
|
||||
ImGui::PopStyleVar();
|
||||
|
||||
const std::string option_popup_id = build_option_value_picker_title(definition);
|
||||
if (definition.picker != OptionPickerType::None && !option.disabled && !definition.disabled) {
|
||||
ImGui::SameLine();
|
||||
if (ImGui::Button("Pick")) {
|
||||
ImGui::OpenPopup(option_popup_id.c_str());
|
||||
}
|
||||
if (ImGui::IsItemHovered(ImGui::TOOLTIP_FLAGS)) {
|
||||
ImGui::HelpTooltip(definition.desc.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
ImGui::PopStyleVar(); // ImGuiStyleVar_ItemSpacing
|
||||
|
||||
// clean up disabled item flags
|
||||
if (option.disabled || definition.disabled) {
|
||||
ImGui::PopItemFlag();
|
||||
ImGui::PopStyleVar();
|
||||
ImGui::PopItemFlag(); // ImGuiItemFlags_Disabled
|
||||
ImGui::PopStyleVar(); // ImGuiStyleVar_Alpha
|
||||
}
|
||||
|
||||
// disabled help
|
||||
@@ -3199,6 +3477,44 @@ namespace overlay::windows {
|
||||
"Run spicecfg.exe to configure the options and then run spice(64).exe directly.");
|
||||
}
|
||||
|
||||
// value picker
|
||||
if (definition.picker != OptionPickerType::None &&
|
||||
!option.disabled && !definition.disabled) {
|
||||
if (ImGui::BeginPopupModal(option_popup_id.c_str(),
|
||||
nullptr, ImGuiWindowFlags_AlwaysAutoResize)) {
|
||||
// for min width enforcement
|
||||
ImGui::Dummy(ImVec2(320.f, 0.f));
|
||||
ImGui::TextColored(ImVec4(1, 0.7f, 0, 1), "%s", definition.title.c_str());
|
||||
|
||||
ImGui::TextUnformatted("");
|
||||
|
||||
ImGui::TextUnformatted("Current value:");
|
||||
ImGui::BeginDisabled();
|
||||
// keeping it read only; if you want to make this editable, we need to refactor the
|
||||
// input validation logic above (for int/hex) so people don't end up with invalid
|
||||
// values that can crash spicecfg
|
||||
ImGui::InputText("", &option.value, ImGuiInputTextFlags_ReadOnly);
|
||||
ImGui::EndDisabled();
|
||||
ImGui::SameLine();
|
||||
if (ImGui::ClearButton("Reset to default")) {
|
||||
option.value = "";
|
||||
}
|
||||
|
||||
ImGui::TextUnformatted("");
|
||||
|
||||
build_option_value_picker(option);
|
||||
|
||||
ImGui::TextUnformatted("");
|
||||
|
||||
if (ImGui::Button("Save & Close")) {
|
||||
ImGui::CloseCurrentPopup();
|
||||
this->options_dirty = true;
|
||||
::Config::getInstance().updateBinding(games_list[games_selected], option);
|
||||
}
|
||||
ImGui::EndPopup();
|
||||
}
|
||||
}
|
||||
|
||||
// next item
|
||||
ImGui::PopID();
|
||||
}
|
||||
|
||||
@@ -76,6 +76,10 @@ namespace overlay::windows {
|
||||
std::string search_filter = "";
|
||||
std::string search_filter_in_lower_case = "";
|
||||
|
||||
std::filesystem::path file_picker_path;
|
||||
std::thread *file_picker_thread = nullptr;
|
||||
bool file_picker_done = false;
|
||||
|
||||
void build_buttons(const std::string &name, std::vector<Button> *buttons, int min = 0, int max = -1);
|
||||
void build_button(
|
||||
const std::string &name,
|
||||
@@ -104,6 +108,8 @@ namespace overlay::windows {
|
||||
void edit_light_popup(Light &primary_light, Light *light, const int alt_index);
|
||||
|
||||
void build_cards();
|
||||
std::string build_option_value_picker_title(const OptionDefinition& option);
|
||||
void build_option_value_picker(Option& option);
|
||||
void build_options(
|
||||
std::vector<Option> *options, const std::string &category, const std::string *filter=nullptr);
|
||||
void build_about();
|
||||
|
||||
@@ -85,10 +85,12 @@ namespace overlay::windows {
|
||||
}
|
||||
|
||||
void GenericSubScreen::touch_transform(const ImVec2 xy_in, LONG *x_out, LONG *y_out) {}
|
||||
void GenericSubScreen::check_for_errors() {}
|
||||
|
||||
void GenericSubScreen::build_content() {
|
||||
this->flags |= ImGuiWindowFlags_NoBackground;
|
||||
|
||||
check_for_errors();
|
||||
if (this->disabled_message.has_value()) {
|
||||
this->draws_window = true;
|
||||
this->flags &= ~ImGuiWindowFlags_NoBackground;
|
||||
|
||||
@@ -31,6 +31,7 @@ namespace overlay::windows {
|
||||
|
||||
protected:
|
||||
virtual void touch_transform(const ImVec2 xy_in, LONG *x_out, LONG *y_out);
|
||||
virtual void check_for_errors();
|
||||
ImVec2 overlay_content_top_left;
|
||||
ImVec2 overlay_content_size;
|
||||
std::optional<std::string> disabled_message = std::nullopt;
|
||||
|
||||
@@ -14,6 +14,7 @@ namespace overlay::windows {
|
||||
|
||||
static const size_t TICKER_SIZE = 9;
|
||||
static const ImVec4 DARK_GRAY(0.1f, 0.1f, 0.1f, 1.f);
|
||||
static const ImVec4 YELLOW(1.f, 1.f, 0.f, 1.f);
|
||||
static const ImVec4 RED(1.f, 0.f, 0.f, 1.f);
|
||||
static const float PADDING_Y = 8.f;
|
||||
static const float PADDING_X = 4.f;
|
||||
@@ -91,6 +92,23 @@ namespace overlay::windows {
|
||||
}
|
||||
|
||||
void IIDXSegmentDisplay::build_content() {
|
||||
|
||||
// explicitly check if TDJ I/O is enabled to account for the fact that I/O emulation may be
|
||||
// disabled
|
||||
if (games::iidx::CURRENT_IO_EMULATION_STATE == games::iidx::iidx_aio_emulation_state::bi2x_hook) {
|
||||
ImGui::TextUnformatted("");
|
||||
ImGui::TextColored(
|
||||
YELLOW,
|
||||
"%s",
|
||||
"Invalid I/O mode; DLL is configured for TDJ I/O!\n"
|
||||
"Enable -iidxtdj if you want TDJ subscreen overlay.");
|
||||
ImGui::TextUnformatted("");
|
||||
if (ImGui::Button("Close")) {
|
||||
this->set_active(false);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
char input_ticker[TICKER_SIZE];
|
||||
|
||||
// get ticker content from game
|
||||
|
||||
@@ -12,11 +12,9 @@ namespace overlay::windows {
|
||||
this->title = "IIDX TDJ Subscreen";
|
||||
|
||||
if (GRAPHICS_IIDX_WSUB) {
|
||||
this->disabled_message =
|
||||
"Close this overlay and use the second window (ALT+TAB).\n"
|
||||
"If you don't see the window, double check your DLL type and apply TDJ I/O patches as needed.";
|
||||
this->disabled_message = "Close this overlay and use the second window. (try ALT+TAB)";
|
||||
} else if (games::iidx::IIDX_TDJ_MONITOR_WARNING) {
|
||||
this->disabled_message = "TDJ mode subscreen overlay is not compatible with -monitor option";
|
||||
this->disabled_message = "TDJ mode subscreen overlay is not compatible with -monitor option.";
|
||||
}
|
||||
|
||||
float size = 0.5f;
|
||||
@@ -44,6 +42,18 @@ namespace overlay::windows {
|
||||
ImGui::GetIO().DisplaySize.y - this->init_size.y - (ImGui::GetFrameHeight() / 2));
|
||||
}
|
||||
|
||||
void IIDXSubScreen::check_for_errors() {
|
||||
if (games::iidx::CURRENT_IO_EMULATION_STATE ==
|
||||
games::iidx::iidx_aio_emulation_state::bi2a_com2) {
|
||||
|
||||
// explicitly check if LDJ I/O is enabled (as opposed to checking if NOT TDJ I/O)
|
||||
// to account for the fact that I/O emulation may be disabled
|
||||
this->disabled_message =
|
||||
"LDJ I/O detected; TDJ mode subscreen overlay requires TDJ I/O.\n"
|
||||
"Ensure you apply applicable TDJ I/O patches, or run with TDJ DLL.";
|
||||
}
|
||||
}
|
||||
|
||||
void IIDXSubScreen::touch_transform(const ImVec2 xy_in, LONG *x_out, LONG *y_out) {
|
||||
if (!this->get_active()) {
|
||||
return;
|
||||
|
||||
@@ -12,6 +12,7 @@ namespace overlay::windows {
|
||||
|
||||
protected:
|
||||
void touch_transform(const ImVec2 xy_in, LONG *x_out, LONG *y_out) override;
|
||||
void check_for_errors() override;
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -38,6 +38,10 @@ namespace rawinput {
|
||||
uint32_t MIDI_NOTE_SUSTAIN = 20;
|
||||
|
||||
static MidiNoteAlgorithm MIDI_NOTE_ALGORITHM = MidiNoteAlgorithm::V2;
|
||||
|
||||
// the price we pay for making spice overlay consume from raw input
|
||||
// making focus detection a nightmare
|
||||
bool OS_WINDOW_ACTIVE = false;
|
||||
}
|
||||
|
||||
rawinput::MidiNoteAlgorithm rawinput::get_midi_algorithm() {
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
|
||||
#include "device.h"
|
||||
#include "hotplug.h"
|
||||
#include "util/scope_guard.h"
|
||||
|
||||
namespace rawinput {
|
||||
|
||||
@@ -31,6 +32,15 @@ namespace rawinput {
|
||||
extern bool NAIVE_REQUIRE_FOCUS;
|
||||
extern bool RAWINPUT_REQUIRE_FOCUS;
|
||||
|
||||
// while active, prevents overlay from accepting any input
|
||||
// can be used while OS modal dialog is shown on top of overlay/spicecfg
|
||||
// always prefer RAII set_os_window_focus_guard instead of the global bool
|
||||
extern bool OS_WINDOW_ACTIVE;
|
||||
inline scope_guard set_os_window_focus_guard() {
|
||||
rawinput::OS_WINDOW_ACTIVE = true;
|
||||
return scope_guard {[]() { rawinput::OS_WINDOW_ACTIVE = false; }};
|
||||
}
|
||||
|
||||
struct DeviceCallback {
|
||||
void *data;
|
||||
std::function<void(void*, Device*)> f;
|
||||
|
||||
@@ -26,10 +26,10 @@ namespace rawinput::touch {
|
||||
bool INVERTED = false;
|
||||
|
||||
// state
|
||||
static bool DISPLAY_INITIALIZED = false;
|
||||
static DWORD DISPLAY_ORIENTATION = DMDO_DEFAULT;
|
||||
static long DISPLAY_SIZE_X = 1920L;
|
||||
static long DISPLAY_SIZE_Y = 1080L;
|
||||
DWORD DISPLAY_ORIENTATION = DMDO_DEFAULT;
|
||||
long DISPLAY_SIZE_X = 1920L;
|
||||
long DISPLAY_SIZE_Y = 1080L;
|
||||
bool DISPLAY_INITIALIZED = false;
|
||||
|
||||
bool is_touchscreen(Device *device) {
|
||||
|
||||
|
||||
@@ -9,6 +9,12 @@ namespace rawinput::touch {
|
||||
extern bool DISABLED;
|
||||
extern bool INVERTED;
|
||||
|
||||
// global state
|
||||
extern DWORD DISPLAY_ORIENTATION;
|
||||
extern long DISPLAY_SIZE_X;
|
||||
extern long DISPLAY_SIZE_Y;
|
||||
extern bool DISPLAY_INITIALIZED;
|
||||
|
||||
bool is_touchscreen(Device *device);
|
||||
void enable(Device *device);
|
||||
void disable(Device *device);
|
||||
|
||||
Reference in New Issue
Block a user