diff --git a/README.md b/README.md index c9468e5..88d7cb4 100644 --- a/README.md +++ b/README.md @@ -143,7 +143,8 @@ This allows to support a large number of Windows games without any fixes. | Battery | ✅ | PS Vita's battery status is sent to the emulated DualShock 4 | | Any configuration | ✅ | You can choose from [ready-made configurations](#33-configurations) | | DS4Windows support | ✅ | Virtual Controller Support[*] requires activation | -| Sound | ❌ | Probably will never be realized | +| Changing the sound volume | ✅ | Volume Up = Select + R1, Volume Down = Select + L1 | +| Sound sending | ❌ | Probably will never be realized | [*] - Virtual Controller Support can be found in the [schmaldeo DS4Windows fork](https://github.com/schmaldeo/DS4Windows). This option can be found in `Settings -> Device Options -> Virtual Controller Support`. @@ -166,7 +167,8 @@ The behavior is close to how the DualShock 4 (`vendor: 0x054C`, `product: 0x9CC` | DualShock 4 digitizer button | ✅ | Works as a quick tap on the digitizer. Supports front and rear digitizer. Linux itself determines the behaviour | | Battery | ❌ | - | | Any configuration | ✅ | You can choose from [ready-made configurations](#33-configurations) | -| Sound | ❌ | Probably will never be realized | +| Changing the sound volume | ❌ | - | +| Sound sending | ❌ | Probably will never be realized | You can also use a convenient input signal remapper, such as [antimicrox](https://github.com/AntiMicroX/antimicrox/) or [input-remapper](https://github.com/sezanzeb/input-remapper). diff --git a/client/Cargo.lock b/client/Cargo.lock index 34c3769..a838998 100644 --- a/client/Cargo.lock +++ b/client/Cargo.lock @@ -182,9 +182,9 @@ checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" [[package]] name = "bytes" -version = "1.8.0" +version = "1.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ac0150caa2ae65ca5bd83f25c7de183dea78d4d366469f148435e2acfbad0da" +checksum = "325918d6fe32f23b19878fe4b34794ae41fc19ddbe53b10571a4874d44ffd39b" [[package]] name = "cc" @@ -651,7 +651,7 @@ dependencies = [ "iana-time-zone-haiku", "js-sys", "wasm-bindgen", - "windows-core", + "windows-core 0.52.0", ] [[package]] @@ -1119,18 +1119,18 @@ checksum = "61697e0a1c7e512e84a621326239844a24d8207b4669b41bc18b32ea5cbf988b" [[package]] name = "serde" -version = "1.0.214" +version = "1.0.215" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f55c3193aca71c12ad7890f1785d2b73e1b9f63a0bbc353c08ef26fe03fc56b5" +checksum = "6513c1ad0b11a9376da888e3e0baa0077f1aed55c17f50e7b2397136129fb88f" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.214" +version = "1.0.215" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "de523f781f095e28fa605cdce0f8307e451cc0fd14e2eb4cd2e98a355b147766" +checksum = "ad1e866f866923f252f05c889987993144fb74e722403468a4ebd70c3cd756c0" dependencies = [ "proc-macro2", "quote", @@ -1442,6 +1442,7 @@ dependencies = [ "thiserror 2.0.3", "vigem-client", "vita_reports", + "windows", ] [[package]] @@ -1536,6 +1537,16 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" +[[package]] +name = "windows" +version = "0.58.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd04d41d93c4992d421894c18c8b43496aa748dd4c081bac0dc93eb0489272b6" +dependencies = [ + "windows-core 0.58.0", + "windows-targets", +] + [[package]] name = "windows-core" version = "0.52.0" @@ -1545,6 +1556,60 @@ dependencies = [ "windows-targets", ] +[[package]] +name = "windows-core" +version = "0.58.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ba6d44ec8c2591c134257ce647b7ea6b20335bf6379a27dac5f1641fcf59f99" +dependencies = [ + "windows-implement", + "windows-interface", + "windows-result", + "windows-strings", + "windows-targets", +] + +[[package]] +name = "windows-implement" +version = "0.58.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2bbd5b46c938e506ecbce286b6628a02171d56153ba733b6c741fc627ec9579b" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "windows-interface" +version = "0.58.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "053c4c462dc91d3b1504c6fe5a726dd15e216ba718e84a0e46a88fbe5ded3515" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "windows-result" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d1043d8214f791817bab27572aaa8af63732e11bf84aa21a45a78d6c317ae0e" +dependencies = [ + "windows-targets", +] + +[[package]] +name = "windows-strings" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4cd9b125c486025df0eabcb585e62173c6c9eddcec5d117d3b6e8c30e2ee4d10" +dependencies = [ + "windows-result", + "windows-targets", +] + [[package]] name = "windows-sys" version = "0.52.0" diff --git a/client/packages/cli/Cargo.toml b/client/packages/cli/Cargo.toml index eab8e2c..41a3675 100644 --- a/client/packages/cli/Cargo.toml +++ b/client/packages/cli/Cargo.toml @@ -14,7 +14,7 @@ flatbuffers_structs = { version = "0.1.0", path = "../flatbuffers_structs" } protocol = { version = "0.1.0", path = "../protocol" } vita_reports = { version = "0.1.0", path = "../vita_reports" } vita_virtual_device = { version = "0.1.0", path = "../vita_virtual_device" } -serde = { version = "1.0.214", features = ["derive"] } +serde = { version = "1.0.215", features = ["derive"] } config = "0.14.1" toml = "0.8.19" home = "0.5.9" diff --git a/client/packages/protocol/Cargo.toml b/client/packages/protocol/Cargo.toml index f8d0872..303e02f 100644 --- a/client/packages/protocol/Cargo.toml +++ b/client/packages/protocol/Cargo.toml @@ -8,7 +8,7 @@ flatbuffers_structs = { path = "../flatbuffers_structs" } thiserror = "2.0.3" vita_reports = { path = "../vita_reports" } tokio-util = { version = "0.7.12", optional = true, features = ["codec"] } -bytes = { version = "1.8.0", optional = true } +bytes = { version = "1.9.0", optional = true } [features] codec = ["dep:tokio-util", "dep:bytes"] diff --git a/client/packages/vita_reports/src/lib.rs b/client/packages/vita_reports/src/lib.rs index 1a771f9..5434a2d 100644 --- a/client/packages/vita_reports/src/lib.rs +++ b/client/packages/vita_reports/src/lib.rs @@ -12,6 +12,8 @@ pub struct ButtonsData { pub circle: bool, pub cross: bool, pub square: bool, + pub vol_up: bool, + pub vol_down: bool, // timestamp: u64; } @@ -30,6 +32,8 @@ impl From for ButtonsData { circle: buttons.circle(), cross: buttons.cross(), square: buttons.square(), + vol_up: buttons.vol_up(), + vol_down: buttons.vol_down(), // timestamp: buttons.timestamp(), } } diff --git a/client/packages/vita_virtual_device/Cargo.toml b/client/packages/vita_virtual_device/Cargo.toml index e7ea78b..c5e0119 100644 --- a/client/packages/vita_virtual_device/Cargo.toml +++ b/client/packages/vita_virtual_device/Cargo.toml @@ -9,7 +9,7 @@ edition = "2021" cfg-if = "1.0.0" derive_builder = "0.20.2" rstar = { version = "0.12.2", features = ["serde"] } -serde = { version = "1.0.214", features = ["serde_derive"] } +serde = { version = "1.0.215", features = ["serde_derive"] } thiserror = "2.0.3" vita_reports = { version = "0.1.0", path = "../vita_reports" } @@ -18,3 +18,10 @@ input-linux = "0.7.1" [target.'cfg(windows)'.dependencies] vigem-client = { git = "https://github.com/santarl/vigem_client_rust/" } +windows = { version = "0.58", features = [ + "Win32_Foundation", + "Win32_Media_Audio", + "Win32_Media_Audio_Endpoints", + "Win32_System_Com", + "Win32_UI_Input_KeyboardAndMouse", +] } diff --git a/client/packages/vita_virtual_device/src/windows.rs b/client/packages/vita_virtual_device/src/windows.rs index 728a656..0a297c2 100644 --- a/client/packages/vita_virtual_device/src/windows.rs +++ b/client/packages/vita_virtual_device/src/windows.rs @@ -6,12 +6,69 @@ use vigem_client::{ DS4TouchPoint, DS4TouchReport, DpadDirection as VigemDpadDirection, DualShock4Wired, TargetId, }; +use windows::Win32::{ + Media::Audio::Endpoints::IAudioEndpointVolume, + Media::Audio::{eMultimedia, eRender, IMMDevice, IMMDeviceEnumerator, MMDeviceEnumerator}, + System::Com::{CoCreateInstance, CoInitializeEx, CLSCTX_ALL, COINIT_MULTITHREADED}, + UI::Input::KeyboardAndMouse::{ + SendInput, INPUT, INPUT_0, INPUT_KEYBOARD, KEYBDINPUT, KEYBD_EVENT_FLAGS, KEYEVENTF_KEYUP, + VIRTUAL_KEY, VK_VOLUME_DOWN, VK_VOLUME_UP, + }, +}; + use crate::virtual_button::{Button, DpadDirection}; use crate::virtual_config::{Config, ConfigBuilder, TouchConfig, TriggerConfig}; use crate::virtual_touch::{Point, TouchAction}; use crate::virtual_utils::{compute_dpad_direction, get_pressed_buttons}; use crate::{f32_to_i16, VitaVirtualDevice, FRONT_TOUCHPAD_RECT, REAR_TOUCHPAD_RECT}; +unsafe fn simulate_key_press(vk: VIRTUAL_KEY) -> windows::core::Result<()> { + let inputs = &mut [ + INPUT { + r#type: INPUT_KEYBOARD, + Anonymous: INPUT_0 { + ki: KEYBDINPUT { + wVk: vk, + wScan: 0, + dwFlags: KEYBD_EVENT_FLAGS(0), + time: 0, + dwExtraInfo: 0, + }, + }, + }, + INPUT { + r#type: INPUT_KEYBOARD, + Anonymous: INPUT_0 { + ki: KEYBDINPUT { + wVk: vk, + wScan: 0, + dwFlags: KEYEVENTF_KEYUP, + time: 0, + dwExtraInfo: 0, + }, + }, + }, + ]; + + let result = SendInput(inputs, std::mem::size_of::() as i32); + if result == 0 { + Err(windows::core::Error::from_win32()) + } else { + Ok(()) + } +} + +fn change_volume_by_key(delta: f32) -> windows::core::Result<()> { + unsafe { + if delta > 0.0 { + simulate_key_press(VK_VOLUME_UP)?; + } else if delta < 0.0 { + simulate_key_press(VK_VOLUME_DOWN)?; + } + Ok(()) + } +} + #[derive(Debug, thiserror::Error)] pub enum Error { #[error("Failed to connect to the client")] @@ -197,6 +254,12 @@ impl VitaVirtualDevice<&ConfigBuilder> for VitaDevice { // Get the pressed buttons let pressed_buttons = get_pressed_buttons(&report.buttons, self.config.trigger_config); + if report.buttons.vol_up { + change_volume_by_key(0.02).expect("Failed to increase volume"); + } + if report.buttons.vol_down { + change_volume_by_key(-0.02).expect("Failed to increase volume"); + } // Create DS4Buttons object let mut buttons = DS4Buttons::new().dpad(ds4_dpad); diff --git a/common/netprotocol.fbs b/common/netprotocol.fbs index 317fcc7..7bf33b0 100644 --- a/common/netprotocol.fbs +++ b/common/netprotocol.fbs @@ -34,6 +34,8 @@ struct ButtonsData circle: bool; cross: bool; square: bool; + vol_up: bool; + vol_down: bool; } struct Vector3 diff --git a/server/src/ctrl.cpp b/server/src/ctrl.cpp index 27e6d3c..6b9c530 100644 --- a/server/src/ctrl.cpp +++ b/server/src/ctrl.cpp @@ -13,7 +13,9 @@ NetProtocol::ButtonsData convert_pad_data(const SceCtrlData &data) { (data.buttons & SCE_CTRL_DOWN) > 0, (data.buttons & SCE_CTRL_LEFT) > 0, (data.buttons & SCE_CTRL_LTRIGGER) > 0, (data.buttons & SCE_CTRL_RTRIGGER) > 0, (data.buttons & SCE_CTRL_TRIANGLE) > 0, (data.buttons & SCE_CTRL_CIRCLE) > 0, - (data.buttons & SCE_CTRL_CROSS) > 0, (data.buttons & SCE_CTRL_SQUARE) > 0); + (data.buttons & SCE_CTRL_CROSS) > 0, (data.buttons & SCE_CTRL_SQUARE) > 0, + (data.buttons & SCE_CTRL_VOLUP) > 0, (data.buttons & SCE_CTRL_VOLDOWN) > 0 + ); } flatbuffers::Offset @@ -38,6 +40,15 @@ void get_ctrl_as_netprotocol(flatbuffers::FlatBufferBuilder &builder, SharedData while (pad.timeStamp <= last_ts) { sceCtrlPeekBufferPositive(0, &pad, 1); } + if (pad.buttons & SCE_CTRL_SELECT && pad.buttons & SCE_CTRL_LTRIGGER){ + sceKernelDelayThread(20 * 1000); + pad.buttons |= SCE_CTRL_VOLDOWN; + } + if (pad.buttons & SCE_CTRL_SELECT && pad.buttons & SCE_CTRL_RTRIGGER){ + sceKernelDelayThread(20 * 1000); + pad.buttons |= SCE_CTRL_VOLUP; + } + auto buttons = convert_pad_data(pad); sceTouchPeek(SCE_TOUCH_PORT_FRONT, &touch_data_front, 1); diff --git a/server/src/net.cpp b/server/src/net.cpp index 20faadf..6ade166 100644 --- a/server/src/net.cpp +++ b/server/src/net.cpp @@ -346,6 +346,7 @@ int net_thread(__attribute__((unused)) unsigned int arglen, void *argp) { } timeout = client->remaining_polling_time(); + sceKernelDelayThread(10 * 1000); } sceNetCtlInetUnregisterCallback(cbid);