mirror of
https://github.com/patchzyy/wiicompiled
synced 2026-10-20 21:49:51 -04:00
pass real wii remotes through emulated bluetooth
This commit is contained in:
@@ -57,26 +57,16 @@ struct RuntimeUserConfig {
|
||||
std::optional<bool> audioMuted;
|
||||
std::optional<bool> audioMixWorker;
|
||||
std::optional<bool> attenuateMusicWhenMediaPlays;
|
||||
// Real Wii Remotes (with or without Nunchuk / Classic Controller) and Wii U Pro
|
||||
// Controllers paired over Bluetooth, driven by SDL's HIDAPI Wii driver. The driver
|
||||
// is opt-in on SDL's side, so this decides whether the runtime turns it on.
|
||||
// Real Wii Remotes passed through to the game's own Bluetooth stack. Off hands
|
||||
// Nintendo controllers (e.g. the Wii U Pro Controller) to SDL as plain gamepads.
|
||||
std::optional<bool> wiiRemotes;
|
||||
// Keep re-enumerating Bluetooth HID devices while no Wii controller is connected
|
||||
// (Dolphin's "continuous scanning"), so a remote that dropped or was switched on
|
||||
// after launch shows up without restarting.
|
||||
std::optional<bool> wiiContinuousScan;
|
||||
// Accelerometer zero-point correction for the Bluetooth Wii Remote, in g and in
|
||||
// SDL's sensor frame (x right, y out of the button face, z towards the user).
|
||||
// SDL's Wii driver falls back to a nominal zero point when its read of the
|
||||
// remote's calibration block times out (common over Bluetooth), so this is
|
||||
// measured in the overlay with the remote at rest. Stored per remote under
|
||||
// [controller.wii_accel_offsets]; the old shared
|
||||
// wii_accel_offset_* keys are only detected, to report that they are ignored.
|
||||
std::map<std::string, std::array<double, 3>> wiiAccelOffsets;
|
||||
bool hasLegacyWiiAccelOffset = false;
|
||||
// Debugging aid: append every KPAD sample of the Bluetooth remote (raw and
|
||||
// corrected accelerometer, buttons) to wii_accel_trace.csv next to Config.toml.
|
||||
std::optional<bool> wiiAccelTrace;
|
||||
// Look for remotes in pairing mode (1+2 / SYNC) while none is connected.
|
||||
std::optional<bool> wiiAutoPair;
|
||||
// The console's Wii Remote settings (SYSCONF BT.BAR, BT.SENS, BT.SPKV, BT.MOT).
|
||||
std::optional<bool> wiiSensorBarAbove;
|
||||
std::optional<int32_t> wiiIrSensitivity;
|
||||
std::optional<int32_t> wiiSpeakerVolume;
|
||||
std::optional<bool> wiiRumble;
|
||||
std::optional<bool> networkEnabled;
|
||||
std::optional<bool> discordPresenceEnabled;
|
||||
// The application ID of the WiiCompiled Discord application. This is only
|
||||
@@ -382,28 +372,6 @@ inline void AppendOverlayRoots(RuntimeUserConfig& config, const std::string& roo
|
||||
}
|
||||
|
||||
// Reads every supported setting out of a parsed Config.toml document.
|
||||
// [x, y, z] of finite numbers (integers allowed), else nullopt.
|
||||
inline std::optional<std::array<double, 3>> ParseAccelOffset(const toml::value& value) {
|
||||
if (!value.is_array() || value.as_array().size() != 3) {
|
||||
return std::nullopt;
|
||||
}
|
||||
std::array<double, 3> offset{};
|
||||
for (size_t i = 0; i < 3; ++i) {
|
||||
const toml::value& element = value.as_array()[i];
|
||||
if (element.is_floating()) {
|
||||
offset[i] = element.as_floating();
|
||||
} else if (element.is_integer()) {
|
||||
offset[i] = static_cast<double>(element.as_integer());
|
||||
} else {
|
||||
return std::nullopt;
|
||||
}
|
||||
if (!std::isfinite(offset[i])) {
|
||||
return std::nullopt;
|
||||
}
|
||||
}
|
||||
return offset;
|
||||
}
|
||||
|
||||
inline RuntimeUserConfig ParseConfigDocument(const toml::value& document) {
|
||||
RuntimeUserConfig config;
|
||||
|
||||
@@ -427,13 +395,6 @@ inline RuntimeUserConfig ParseConfigDocument(const toml::value& document) {
|
||||
config.controllerExpressions[key] = value.as_string();
|
||||
}
|
||||
}
|
||||
if (section->contains("wii_accel_offsets") && section->at("wii_accel_offsets").is_table()) {
|
||||
for (const auto& [key, value] : section->at("wii_accel_offsets").as_table()) {
|
||||
if (const auto offset = ParseAccelOffset(value)) {
|
||||
config.wiiAccelOffsets[key] = *offset;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
config.widescreen = FindConfigValue<bool>(document, "video", "widescreen");
|
||||
@@ -494,11 +455,17 @@ inline RuntimeUserConfig ParseConfigDocument(const toml::value& document) {
|
||||
config.attenuateMusicWhenMediaPlays =
|
||||
FindConfigValue<bool>(document, "audio", "attenuate_music_when_media_plays");
|
||||
config.wiiRemotes = FindConfigValue<bool>(document, "controller", "wii_remotes");
|
||||
config.wiiContinuousScan = FindConfigValue<bool>(document, "controller", "wii_continuous_scan");
|
||||
for (const char* key : {"wii_accel_offset_x", "wii_accel_offset_y", "wii_accel_offset_z"}) {
|
||||
config.hasLegacyWiiAccelOffset |= FindConfigValue<double>(document, "controller", key).value_or(0.0) != 0.0;
|
||||
config.wiiAutoPair = FindConfigValue<bool>(document, "controller", "wii_auto_pair");
|
||||
if (const auto bar = FindConfigValue<std::string>(document, "controller", "wii_sensor_bar")) {
|
||||
if (*bar == "above" || *bar == "below") config.wiiSensorBarAbove = *bar == "above";
|
||||
}
|
||||
config.wiiAccelTrace = FindConfigValue<bool>(document, "controller", "wii_accel_trace");
|
||||
if (const auto value = FindConfigInt(document, "controller", "wii_ir_sensitivity"); value && *value >= 1 && *value <= 5) {
|
||||
config.wiiIrSensitivity = *value;
|
||||
}
|
||||
if (const auto value = FindConfigInt(document, "controller", "wii_speaker_volume"); value && *value >= 0 && *value <= 127) {
|
||||
config.wiiSpeakerVolume = *value;
|
||||
}
|
||||
config.wiiRumble = FindConfigValue<bool>(document, "controller", "wii_rumble");
|
||||
config.networkEnabled = FindConfigValue<bool>(document, "network", "enabled");
|
||||
config.discordPresenceEnabled = FindConfigValue<bool>(document, "discord", "enabled");
|
||||
config.discordClientId = FindConfigValue<std::string>(document, "discord", "client_id");
|
||||
@@ -849,51 +816,61 @@ inline bool AttenuateMusicWhenMediaPlays(bool fallback = false) {
|
||||
return Get().attenuateMusicWhenMediaPlays.value_or(fallback);
|
||||
}
|
||||
|
||||
// Bluetooth Wii Remotes / Wii U Pro Controllers. Read once before SDL's joystick
|
||||
// subsystem comes up, so a change only takes effect on the next launch.
|
||||
inline bool WiiRemotesEnabled(bool fallback = true) {
|
||||
// Bluetooth Wii Remotes. Read once before SDL's joystick subsystem comes up, so a
|
||||
// change only takes effect on the next launch.
|
||||
inline bool WiiRemotesEnabled(bool fallback = false) {
|
||||
return Get().wiiRemotes.value_or(fallback);
|
||||
}
|
||||
|
||||
// Persists the Bluetooth Wii Remote driver switch.
|
||||
inline bool SetWiiRemotesEnabled(bool value) {
|
||||
Mutable().wiiRemotes = value;
|
||||
return WriteSetting("controller", "wii_remotes", value ? "true" : "false");
|
||||
}
|
||||
|
||||
// Whether to keep rescanning Bluetooth while no Wii controller is connected.
|
||||
inline bool WiiContinuousScanEnabled(bool fallback = false) {
|
||||
return Get().wiiContinuousScan.value_or(fallback);
|
||||
inline bool WiiAutoPairEnabled(bool fallback = true) {
|
||||
return Get().wiiAutoPair.value_or(fallback);
|
||||
}
|
||||
|
||||
// Persists the continuous scanning switch.
|
||||
inline bool SetWiiContinuousScanEnabled(bool value) {
|
||||
Mutable().wiiContinuousScan = value;
|
||||
return WriteSetting("controller", "wii_continuous_scan", value ? "true" : "false");
|
||||
inline bool SetWiiAutoPairEnabled(bool value) {
|
||||
Mutable().wiiAutoPair = value;
|
||||
return WriteSetting("controller", "wii_auto_pair", value ? "true" : "false");
|
||||
}
|
||||
|
||||
// Stored correction of the remote identified by `remoteKey`, if it has one.
|
||||
inline std::optional<std::array<double, 3>> WiiAccelOffsetFor(const std::string& remoteKey) {
|
||||
const auto it = Get().wiiAccelOffsets.find(remoteKey);
|
||||
if (it == Get().wiiAccelOffsets.end()) {
|
||||
return std::nullopt;
|
||||
}
|
||||
return it->second;
|
||||
// Defaults are the console's.
|
||||
inline bool WiiSensorBarAbove(bool fallback = false) {
|
||||
return Get().wiiSensorBarAbove.value_or(fallback);
|
||||
}
|
||||
|
||||
// Whether to write the per-frame accelerometer trace (off unless asked for).
|
||||
inline bool WiiAccelTraceEnabled(bool fallback = false) {
|
||||
return Get().wiiAccelTrace.value_or(fallback);
|
||||
inline bool SetWiiSensorBarAbove(bool value) {
|
||||
Mutable().wiiSensorBarAbove = value;
|
||||
return WriteSetting("controller", "wii_sensor_bar", value ? "\"above\"" : "\"below\"");
|
||||
}
|
||||
|
||||
// Persists the accelerometer correction of one remote. `remoteKey` must be a bare TOML key.
|
||||
inline bool SetWiiAccelOffsetFor(const std::string& remoteKey, const std::array<double, 3>& offset) {
|
||||
Mutable().wiiAccelOffsets[remoteKey] = offset;
|
||||
// Always float literals, so a whole-number offset does not come back as a TOML integer.
|
||||
std::ostringstream formatted;
|
||||
formatted << std::fixed << std::setprecision(4) << '[' << offset[0] << ", " << offset[1] << ", " << offset[2]
|
||||
<< ']';
|
||||
return WriteSetting("controller.wii_accel_offsets", remoteKey, formatted.str());
|
||||
inline int32_t WiiIrSensitivity(int32_t fallback = 3) {
|
||||
return Get().wiiIrSensitivity.value_or(fallback);
|
||||
}
|
||||
|
||||
inline bool SetWiiIrSensitivity(int32_t value) {
|
||||
Mutable().wiiIrSensitivity = value;
|
||||
return WriteSetting("controller", "wii_ir_sensitivity", std::to_string(value));
|
||||
}
|
||||
|
||||
inline int32_t WiiSpeakerVolume(int32_t fallback = 0x59) {
|
||||
return Get().wiiSpeakerVolume.value_or(fallback);
|
||||
}
|
||||
|
||||
inline bool SetWiiSpeakerVolume(int32_t value) {
|
||||
Mutable().wiiSpeakerVolume = value;
|
||||
return WriteSetting("controller", "wii_speaker_volume", std::to_string(value));
|
||||
}
|
||||
|
||||
inline bool WiiRumbleEnabled(bool fallback = true) {
|
||||
return Get().wiiRumble.value_or(fallback);
|
||||
}
|
||||
|
||||
inline bool SetWiiRumbleEnabled(bool value) {
|
||||
Mutable().wiiRumble = value;
|
||||
return WriteSetting("controller", "wii_rumble", value ? "true" : "false");
|
||||
}
|
||||
|
||||
// Target frame rate for frame interpolation, or 0 to disable it.
|
||||
|
||||
Reference in New Issue
Block a user