From 8bd5b463c1b34a5ad1c8f5bce554f854848f371e Mon Sep 17 00:00:00 2001 From: Marc Riera Irigoyen Date: Sun, 30 Apr 2023 21:38:03 +0200 Subject: [PATCH] Add button combos --- README.md | 28 ++++++++----- src/controller/emulated.rs | 3 ++ src/controller/emulated/dgoc44u.rs | 2 +- src/controller/emulated/sotp031201_p4b2b7.rs | 44 ++++++++++++++------ src/controller/emulated/sotp031201_p4b7.rs | 44 ++++++++++++++------ src/controller/emulated/sotp031201_p5b5.rs | 44 ++++++++++++++------ src/controller/emulated/sotp031201_p5b7.rs | 44 ++++++++++++++------ src/controller/emulated/tcpp20009.rs | 2 +- src/controller/emulated/tcpp20011.rs | 2 +- src/controller/emulated/vok00106.rs | 2 +- src/controller/emulated/zkns001.rs | 39 ++++++++++------- src/controller/physical.rs | 24 ++++++++++- 12 files changed, 194 insertions(+), 84 deletions(-) diff --git a/README.md b/README.md index 047256b..95c1a39 100644 --- a/README.md +++ b/README.md @@ -20,16 +20,16 @@ This mod allows you to use your Densha de GO! Plug & Play as a USB controller fo Connect the Plug & Play to a PC or console using the data cable. Press one of the following button combinations to select the controller you want to emulate: -| Controller | Button combination | Notes | -|-----------------------------------------|-----------------------|----------------------------------------------| -| One handle controller (Nintendo Switch) | UP | | -| Two handle controller (PC) | RIGHT | D-Pad is mapped to SELECT+ABCD | -| Two handle controller "Type 2" (PS2) | D | | -| Shinkansen controller (PS2) | B | Power notches are mapped to P2-P4-P7-P10-P13 | -| Multi Train Controller (PS2) - P4/B7 | C + Power handle at 0 | | -| Multi Train Controller (PS2) - P4/B2-B6 | C + Power handle at 1 | Beta, currently undetected by game | -| Multi Train Controller (PS2) - P5/B5 | C + Power handle at 2 | | -| Multi Train Controller (PS2) - P5/B7 | C + Power handle at 3 | Beta, currently undetected by game | +| Controller | Button combination | Notes | +|-----------------------------------------|-----------------------|--------------------------------------------------| +| One handle controller (Nintendo Switch) | UP | SELECT+START=HOME, SELECT+LEFT=L, SELECT+RIGHT=R | +| Two handle controller (PC) | RIGHT | D-Pad is mapped to SELECT+ABCD | +| Two handle controller "Type 2" (PS2) | D | | +| Shinkansen controller (PS2) | B | Power notches are mapped to P2-P4-P7-P10-P13 | +| Multi Train Controller (PS2) - P4/B7 | C + Power handle at 0 | | +| Multi Train Controller (PS2) - P4/B2-B6 | C + Power handle at 1 | | +| Multi Train Controller (PS2) - P5/B5 | C + Power handle at 2 | | +| Multi Train Controller (PS2) - P5/B7 | C + Power handle at 3 | Beta, currently undetected by game | Hold the buttons until the controller vibrates to confirm selection. If no button is pressed, you can play with the Plug & Play as usual. @@ -43,3 +43,11 @@ When no controller is selected, RNDIS access is enabled in the device. You can a - During the first installation, the device's kernel is backed up to a folder named *BACKUP* in the root of the USB drive. Copy its contents to a safe location. - If detected, the [original mod by GMMan](https://github.com/GMMan/dengo-plug-and-play-controller) will be uninstalled to avoid conflicts. + +## Compilation + +To compile the program yourself, you will need Rust and toolchain for Armv7-A. The easiest way is to install [cross](https://github.com/cross-rs/cross) and run: + +```cross build --target arm-unknown-linux-musleabi --release``` + +The Linux kernel source can be found [here](https://github.com/MarcRiera/dengo-plug-and-play-kernel). diff --git a/src/controller/emulated.rs b/src/controller/emulated.rs index c37d28b..a9e8b6f 100644 --- a/src/controller/emulated.rs +++ b/src/controller/emulated.rs @@ -42,6 +42,7 @@ pub struct DeviceDescriptor { b_device_sub_class: u8, id_vendor: u16, id_product: u16, + bcd_device: u16, i_manufacturer: &'static str, i_product: &'static str, i_serial_number: &'static str, @@ -175,6 +176,7 @@ fn init_gadget(model: &ControllerModel, (device, descriptors, strings): (&Device .arg(String::from("bDeviceSubClass=")+&device.b_device_sub_class.to_string()) .arg(String::from("idVendor=")+&device.id_vendor.to_string()) .arg(String::from("idProduct=")+&device.id_product.to_string()) + .arg(String::from("bcdDevice=")+&device.bcd_device.to_string()) .arg(String::from("iManufacturer=")+device.i_manufacturer) .arg(String::from("iProduct=")+device.i_product) .arg(String::from("iSerialNumber=")+device.i_serial_number) @@ -213,6 +215,7 @@ fn init_gadget(model: &ControllerModel, (device, descriptors, strings): (&Device fs::write(gadget.join(Path::new("bDeviceSubClass")), &device.b_device_sub_class.to_string()).ok(); fs::write(gadget.join(Path::new("idVendor")), format!("{:x}", &device.id_vendor)).ok(); fs::write(gadget.join(Path::new("idProduct")), format!("{:x}", &device.id_product)).ok(); + fs::write(gadget.join(Path::new("bcdDevice")), format!("{:x}", &device.bcd_device)).ok(); fs::write(gadget.join(Path::new("iManufacturer")), &device.i_manufacturer.to_string()).ok(); fs::write(gadget.join(Path::new("iProduct")), &device.i_product.to_string()).ok(); fs::write(gadget.join(Path::new("iSerial")), &device.i_serial_number.to_string()).ok(); diff --git a/src/controller/emulated/dgoc44u.rs b/src/controller/emulated/dgoc44u.rs index b75e2be..4168be3 100644 --- a/src/controller/emulated/dgoc44u.rs +++ b/src/controller/emulated/dgoc44u.rs @@ -13,7 +13,7 @@ pub const DESCRIPTORS: [u8; 66] = [0x01, 0x00, 0x00, 0x00, 0x42, 0x00, 0x00, 0x0 0x07, 0x05, 0x81, 0x03, 0x08, 0x00, 0x05]; pub const STRINGS: [u8; 16] = [0x02, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]; -pub const DEVICE_DESCRIPTOR: DeviceDescriptor = DeviceDescriptor{b_device_class: 0x0, b_device_sub_class: 0x0, id_vendor: 0x0AE4, id_product: 0x0003, i_manufacturer: "TAITO", i_product: "Densha de Go! Plug & Play", i_serial_number: "DGOC-44U"}; +pub const DEVICE_DESCRIPTOR: DeviceDescriptor = DeviceDescriptor{b_device_class: 0x0, b_device_sub_class: 0x0, id_vendor: 0x0AE4, id_product: 0x0003, bcd_device: 0x0102, i_manufacturer: "TAITO", i_product: "Densha de Go! Plug & Play", i_serial_number: "DGOC-44U"}; pub const HID_REPORT_DESCRIPTOR: [u8; 63] = [ 0x05, 0x01, // Usage Page (Generic Desktop Ctrls) diff --git a/src/controller/emulated/sotp031201_p4b2b7.rs b/src/controller/emulated/sotp031201_p4b2b7.rs index e5527e4..bc70929 100644 --- a/src/controller/emulated/sotp031201_p4b2b7.rs +++ b/src/controller/emulated/sotp031201_p4b2b7.rs @@ -12,7 +12,7 @@ pub const DESCRIPTORS: [u8; 48] = [0x01, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x0 0x07, 0x05, 0x81, 0x03, 0x08, 0x00, 0x14]; pub const STRINGS: [u8; 16] = [0x02, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]; -pub const DEVICE_DESCRIPTOR: DeviceDescriptor = DeviceDescriptor{b_device_class: 0x00, b_device_sub_class: 0x0, id_vendor: 0x0AE4, id_product: 0x0101, i_manufacturer: "TAITO", i_product: "Densha de Go! Plug & Play (MTC P4/B2-B7 mode)", i_serial_number: "SOTP-031201"}; +pub const DEVICE_DESCRIPTOR: DeviceDescriptor = DeviceDescriptor{b_device_class: 0x00, b_device_sub_class: 0x0, id_vendor: 0x0AE4, id_product: 0x0101, bcd_device: 0x0400, i_manufacturer: "TAITO", i_product: "Densha de Go! Plug & Play (MTC P4/B2-B7 mode)", i_serial_number: "SOTP-031201"}; const POWER_NOTCHES: [u8; 6] = [0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0C]; const BRAKE_NOTCHES: [u8; 10] = [0x08, 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x02, 0x02, 0x01]; @@ -45,24 +45,42 @@ pub fn update_gadget(state: &mut ControllerState) { handle = BRAKE_NOTCHES[state.brake as usize]; } - // Calculate data for buttons 1 + // Calculate data for buttons let mut buttons1 = Buttons1::NONE; - if state.button_a { buttons1.insert(Buttons1::A) } - if state.button_b { buttons1.insert(Buttons1::B) } - if state.button_c { buttons1.insert(Buttons1::C) } - if state.button_d { buttons1.insert(Buttons1::D) } - - // Calculate data for buttons 2 let mut buttons2 = Buttons2::NONE; - if state.button_up { buttons2.insert(Buttons2::UP) } - if state.button_down { buttons2.insert(Buttons2::DOWN) } - if state.button_left { buttons2.insert(Buttons2::LEFT) } + if !state.button_select_hold && state.button_select && state.button_a { + buttons1.insert(Buttons1::A2); + state.combo = true; + } + if !state.button_select_hold && state.button_select && state.button_d { + buttons1.insert(Buttons1::S); + state.combo = true; + } + if !state.button_select_hold && state.button_select && state.button_up { + state.reverser = 0x80; + state.combo = true; + } + if !state.button_select_hold && state.button_select && state.button_left { + state.reverser = 0x00; + state.combo = true; + } + if !state.button_select_hold && state.button_select && state.button_down { + state.reverser = 0x40; + state.combo = true; + } + if !state.combo && state.button_a { buttons1.insert(Buttons1::A) } + if state.button_b { buttons1.insert(Buttons1::B) } + if !state.combo && state.button_c { buttons1.insert(Buttons1::C) } + if state.button_d { buttons1.insert(Buttons1::D) } + if !state.combo && state.button_up { buttons2.insert(Buttons2::UP) } + if !state.combo && state.button_down { buttons2.insert(Buttons2::DOWN) } + if !state.combo && state.button_left { buttons2.insert(Buttons2::LEFT) } if state.button_right { buttons2.insert(Buttons2::RIGHT) } if state.button_start { buttons2.insert(Buttons2::START) } - if state.button_select { buttons2.insert(Buttons2::SELECT) } + if !state.combo && state.button_select_hold { buttons2.insert(Buttons2::SELECT) } // Assemble data and send it to endpoint - let data = [0x1, handle, buttons1.bits, buttons2.bits]; + let data = [0x1, state.reverser + handle, buttons1.bits, buttons2.bits]; if let Ok(mut file) = File::create(ENDPOINT1) { file.write(&data).ok(); } diff --git a/src/controller/emulated/sotp031201_p4b7.rs b/src/controller/emulated/sotp031201_p4b7.rs index e2f7e04..ad38922 100644 --- a/src/controller/emulated/sotp031201_p4b7.rs +++ b/src/controller/emulated/sotp031201_p4b7.rs @@ -12,7 +12,7 @@ pub const DESCRIPTORS: [u8; 48] = [0x01, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x0 0x07, 0x05, 0x81, 0x03, 0x08, 0x00, 0x14]; pub const STRINGS: [u8; 16] = [0x02, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]; -pub const DEVICE_DESCRIPTOR: DeviceDescriptor = DeviceDescriptor{b_device_class: 0x00, b_device_sub_class: 0x0, id_vendor: 0x0AE4, id_product: 0x0101, i_manufacturer: "TAITO", i_product: "Densha de Go! Plug & Play (MTC P4/B7 mode)", i_serial_number: "SOTP-031201"}; +pub const DEVICE_DESCRIPTOR: DeviceDescriptor = DeviceDescriptor{b_device_class: 0x00, b_device_sub_class: 0x0, id_vendor: 0x0AE4, id_product: 0x0101, bcd_device: 0x0102, i_manufacturer: "TAITO", i_product: "Densha de Go! Plug & Play (MTC P4/B7 mode)", i_serial_number: "SOTP-031201"}; const POWER_NOTCHES: [u8; 6] = [0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0D]; const BRAKE_NOTCHES: [u8; 10] = [0x09, 0x08, 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x02, 0x01]; @@ -45,24 +45,42 @@ pub fn update_gadget(state: &mut ControllerState) { handle = BRAKE_NOTCHES[state.brake as usize]; } - // Calculate data for buttons 1 + // Calculate data for buttons let mut buttons1 = Buttons1::NONE; - if state.button_a { buttons1.insert(Buttons1::A) } - if state.button_b { buttons1.insert(Buttons1::B) } - if state.button_c { buttons1.insert(Buttons1::C) } - if state.button_d { buttons1.insert(Buttons1::D) } - - // Calculate data for buttons 2 let mut buttons2 = Buttons2::NONE; - if state.button_up { buttons2.insert(Buttons2::UP) } - if state.button_down { buttons2.insert(Buttons2::DOWN) } - if state.button_left { buttons2.insert(Buttons2::LEFT) } + if !state.button_select_hold && state.button_select && state.button_a { + buttons1.insert(Buttons1::A2); + state.combo = true; + } + if !state.button_select_hold && state.button_select && state.button_d { + buttons1.insert(Buttons1::S); + state.combo = true; + } + if !state.button_select_hold && state.button_select && state.button_up { + state.reverser = 0x80; + state.combo = true; + } + if !state.button_select_hold && state.button_select && state.button_left { + state.reverser = 0x00; + state.combo = true; + } + if !state.button_select_hold && state.button_select && state.button_down { + state.reverser = 0x40; + state.combo = true; + } + if !state.combo && state.button_a { buttons1.insert(Buttons1::A) } + if state.button_b { buttons1.insert(Buttons1::B) } + if !state.combo && state.button_c { buttons1.insert(Buttons1::C) } + if state.button_d { buttons1.insert(Buttons1::D) } + if !state.combo && state.button_up { buttons2.insert(Buttons2::UP) } + if !state.combo && state.button_down { buttons2.insert(Buttons2::DOWN) } + if !state.combo && state.button_left { buttons2.insert(Buttons2::LEFT) } if state.button_right { buttons2.insert(Buttons2::RIGHT) } if state.button_start { buttons2.insert(Buttons2::START) } - if state.button_select { buttons2.insert(Buttons2::SELECT) } + if !state.combo && state.button_select_hold { buttons2.insert(Buttons2::SELECT) } // Assemble data and send it to endpoint - let data = [0x1, handle, buttons1.bits, buttons2.bits]; + let data = [0x1, state.reverser + handle, buttons1.bits, buttons2.bits]; if let Ok(mut file) = File::create(ENDPOINT1) { file.write(&data).ok(); } diff --git a/src/controller/emulated/sotp031201_p5b5.rs b/src/controller/emulated/sotp031201_p5b5.rs index 5dc9e7b..a5f6c3e 100644 --- a/src/controller/emulated/sotp031201_p5b5.rs +++ b/src/controller/emulated/sotp031201_p5b5.rs @@ -12,7 +12,7 @@ pub const DESCRIPTORS: [u8; 48] = [0x01, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x0 0x07, 0x05, 0x81, 0x03, 0x08, 0x00, 0x14]; pub const STRINGS: [u8; 16] = [0x02, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]; -pub const DEVICE_DESCRIPTOR: DeviceDescriptor = DeviceDescriptor{b_device_class: 0x00, b_device_sub_class: 0x0, id_vendor: 0x1C06, id_product: 0x77A7, i_manufacturer: "TAITO", i_product: "Densha de Go! Plug & Play (MTC P5/B5 mode)", i_serial_number: "SOTP-031201"}; +pub const DEVICE_DESCRIPTOR: DeviceDescriptor = DeviceDescriptor{b_device_class: 0x00, b_device_sub_class: 0x0, id_vendor: 0x1C06, id_product: 0x77A7, bcd_device: 0x0102, i_manufacturer: "TAITO", i_product: "Densha de Go! Plug & Play (MTC P5/B5 mode)", i_serial_number: "SOTP-031201"}; const POWER_NOTCHES: [u8; 6] = [0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C]; const BRAKE_NOTCHES: [u8; 10] = [0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x02, 0x02, 0x02, 0x01]; @@ -45,24 +45,42 @@ pub fn update_gadget(state: &mut ControllerState) { handle = BRAKE_NOTCHES[state.brake as usize]; } - // Calculate data for buttons 1 + // Calculate data for buttons let mut buttons1 = Buttons1::NONE; - if state.button_a { buttons1.insert(Buttons1::A) } - if state.button_b { buttons1.insert(Buttons1::B) } - if state.button_c { buttons1.insert(Buttons1::C) } - if state.button_d { buttons1.insert(Buttons1::D) } - - // Calculate data for buttons 2 let mut buttons2 = Buttons2::NONE; - if state.button_up { buttons2.insert(Buttons2::UP) } - if state.button_down { buttons2.insert(Buttons2::DOWN) } - if state.button_left { buttons2.insert(Buttons2::LEFT) } + if !state.button_select_hold && state.button_select && state.button_a { + buttons1.insert(Buttons1::A2); + state.combo = true; + } + if !state.button_select_hold && state.button_select && state.button_d { + buttons1.insert(Buttons1::S); + state.combo = true; + } + if !state.button_select_hold && state.button_select && state.button_up { + state.reverser = 0x20; + state.combo = true; + } + if !state.button_select_hold && state.button_select && state.button_left { + state.reverser = 0x00; + state.combo = true; + } + if !state.button_select_hold && state.button_select && state.button_down { + state.reverser = 0x10; + state.combo = true; + } + if !state.combo && state.button_a { buttons1.insert(Buttons1::A) } + if state.button_b { buttons1.insert(Buttons1::B) } + if !state.combo && state.button_c { buttons1.insert(Buttons1::C) } + if state.button_d { buttons1.insert(Buttons1::D) } + if !state.combo && state.button_up { buttons2.insert(Buttons2::UP) } + if !state.combo && state.button_down { buttons2.insert(Buttons2::DOWN) } + if !state.combo && state.button_left { buttons2.insert(Buttons2::LEFT) } if state.button_right { buttons2.insert(Buttons2::RIGHT) } if state.button_start { buttons2.insert(Buttons2::START) } - if state.button_select { buttons2.insert(Buttons2::SELECT) } + if !state.combo && state.button_select_hold { buttons2.insert(Buttons2::SELECT) } // Assemble data and send it to endpoint - let data = [0x1, handle, buttons1.bits, buttons2.bits]; + let data = [0x1, state.reverser + handle, buttons1.bits, buttons2.bits]; if let Ok(mut file) = File::create(ENDPOINT1) { file.write(&data).ok(); } diff --git a/src/controller/emulated/sotp031201_p5b7.rs b/src/controller/emulated/sotp031201_p5b7.rs index 503b26b..e1654af 100644 --- a/src/controller/emulated/sotp031201_p5b7.rs +++ b/src/controller/emulated/sotp031201_p5b7.rs @@ -12,7 +12,7 @@ pub const DESCRIPTORS: [u8; 48] = [0x01, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x0 0x07, 0x05, 0x81, 0x03, 0x08, 0x00, 0x14]; pub const STRINGS: [u8; 16] = [0x02, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]; -pub const DEVICE_DESCRIPTOR: DeviceDescriptor = DeviceDescriptor{b_device_class: 0x00, b_device_sub_class: 0x0, id_vendor: 0x0AE4, id_product: 0x0101, i_manufacturer: "TAITO", i_product: "Densha de Go! Plug & Play (MTC P5/B7 mode)", i_serial_number: "SOTP-031201"}; +pub const DEVICE_DESCRIPTOR: DeviceDescriptor = DeviceDescriptor{b_device_class: 0x00, b_device_sub_class: 0x0, id_vendor: 0x0AE4, id_product: 0x0101, bcd_device: 0x0102, i_manufacturer: "TAITO", i_product: "Densha de Go! Plug & Play (MTC P5/B7 mode)", i_serial_number: "SOTP-031201"}; const POWER_NOTCHES: [u8; 6] = [0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E]; const BRAKE_NOTCHES: [u8; 10] = [0x09, 0x08, 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x02, 0x01]; @@ -45,24 +45,42 @@ pub fn update_gadget(state: &mut ControllerState) { handle = BRAKE_NOTCHES[state.brake as usize]; } - // Calculate data for buttons 1 + // Calculate data for buttons let mut buttons1 = Buttons1::NONE; - if state.button_a { buttons1.insert(Buttons1::A) } - if state.button_b { buttons1.insert(Buttons1::B) } - if state.button_c { buttons1.insert(Buttons1::C) } - if state.button_d { buttons1.insert(Buttons1::D) } - - // Calculate data for buttons 2 let mut buttons2 = Buttons2::NONE; - if state.button_up { buttons2.insert(Buttons2::UP) } - if state.button_down { buttons2.insert(Buttons2::DOWN) } - if state.button_left { buttons2.insert(Buttons2::LEFT) } + if !state.button_select_hold && state.button_select && state.button_a { + buttons1.insert(Buttons1::A2); + state.combo = true; + } + if !state.button_select_hold && state.button_select && state.button_d { + buttons1.insert(Buttons1::S); + state.combo = true; + } + if !state.button_select_hold && state.button_select && state.button_up { + state.reverser = 0x80; + state.combo = true; + } + if !state.button_select_hold && state.button_select && state.button_left { + state.reverser = 0x00; + state.combo = true; + } + if !state.button_select_hold && state.button_select && state.button_down { + state.reverser = 0x40; + state.combo = true; + } + if !state.combo && state.button_a { buttons1.insert(Buttons1::A) } + if state.button_b { buttons1.insert(Buttons1::B) } + if !state.combo && state.button_c { buttons1.insert(Buttons1::C) } + if state.button_d { buttons1.insert(Buttons1::D) } + if !state.combo && state.button_up { buttons2.insert(Buttons2::UP) } + if !state.combo && state.button_down { buttons2.insert(Buttons2::DOWN) } + if !state.combo && state.button_left { buttons2.insert(Buttons2::LEFT) } if state.button_right { buttons2.insert(Buttons2::RIGHT) } if state.button_start { buttons2.insert(Buttons2::START) } - if state.button_select { buttons2.insert(Buttons2::SELECT) } + if !state.combo && state.button_select_hold { buttons2.insert(Buttons2::SELECT) } // Assemble data and send it to endpoint - let data = [0x1, handle, buttons1.bits, buttons2.bits]; + let data = [0x1, state.reverser + handle, buttons1.bits, buttons2.bits]; if let Ok(mut file) = File::create(ENDPOINT1) { file.write(&data).ok(); } diff --git a/src/controller/emulated/tcpp20009.rs b/src/controller/emulated/tcpp20009.rs index 3442ba2..f36217d 100644 --- a/src/controller/emulated/tcpp20009.rs +++ b/src/controller/emulated/tcpp20009.rs @@ -12,7 +12,7 @@ pub const DESCRIPTORS: [u8; 48] = [0x01, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x0 0x07, 0x05, 0x81, 0x03, 0x08, 0x00, 0x14]; pub const STRINGS: [u8; 16] = [0x02, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]; -pub const DEVICE_DESCRIPTOR: DeviceDescriptor = DeviceDescriptor{b_device_class: 0xFF, b_device_sub_class: 0x4, id_vendor: 0x0AE4, id_product: 0x0004, i_manufacturer: "TAITO", i_product: "Densha de Go! Plug & Play (Type 2 mode)", i_serial_number: "TCPP20010"}; +pub const DEVICE_DESCRIPTOR: DeviceDescriptor = DeviceDescriptor{b_device_class: 0xFF, b_device_sub_class: 0x4, id_vendor: 0x0AE4, id_product: 0x0004, bcd_device: 0x0102, i_manufacturer: "TAITO", i_product: "Densha de Go! Plug & Play (Type 2 mode)", i_serial_number: "TCPP20010"}; const POWER_NOTCHES: [u8; 6] = [0x81, 0x6D, 0x54, 0x3F, 0x21, 0x00]; const BRAKE_NOTCHES: [u8; 10] = [0x79, 0x8A, 0x94, 0x9A, 0xA2, 0xA8, 0xAF, 0xB2, 0xB5, 0xB9]; diff --git a/src/controller/emulated/tcpp20011.rs b/src/controller/emulated/tcpp20011.rs index 6437a53..5136585 100644 --- a/src/controller/emulated/tcpp20011.rs +++ b/src/controller/emulated/tcpp20011.rs @@ -12,7 +12,7 @@ pub const DESCRIPTORS: [u8; 48] = [0x01, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x0 0x07, 0x05, 0x81, 0x03, 0x08, 0x00, 0x14]; pub const STRINGS: [u8; 16] = [0x02, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]; -pub const DEVICE_DESCRIPTOR: DeviceDescriptor = DeviceDescriptor{b_device_class: 0xFF, b_device_sub_class: 0x5, id_vendor: 0x0AE4, id_product: 0x0005, i_manufacturer: "TAITO", i_product: "Densha de Go! Plug & Play (Shinkansen mode)", i_serial_number: "TCPP20011"}; +pub const DEVICE_DESCRIPTOR: DeviceDescriptor = DeviceDescriptor{b_device_class: 0xFF, b_device_sub_class: 0x5, id_vendor: 0x0AE4, id_product: 0x0005, bcd_device: 0x0102, i_manufacturer: "TAITO", i_product: "Densha de Go! Plug & Play (Shinkansen mode)", i_serial_number: "TCPP20011"}; const POWER_NOTCHES: [u8; 6] = [0x12, 0x36, 0x5A, 0x90, 0xC6, 0xFB]; const BRAKE_NOTCHES: [u8; 10] = [0x1C, 0x38, 0x54, 0x70, 0x8B, 0xA7, 0xC3, 0xDF, 0xDF, 0xFB]; diff --git a/src/controller/emulated/vok00106.rs b/src/controller/emulated/vok00106.rs index 11f0fab..0206f29 100644 --- a/src/controller/emulated/vok00106.rs +++ b/src/controller/emulated/vok00106.rs @@ -12,7 +12,7 @@ pub const DESCRIPTORS: [u8; 76] = [0x01, 0x00, 0x00, 0x00, 0x4C, 0x00, 0x00, 0x0 0x07, 0x05, 0x81, 0x03, 0x08, 0x00, 0x01,]; pub const STRINGS: [u8; 16] = [0x02, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]; -pub const DEVICE_DESCRIPTOR: DeviceDescriptor = DeviceDescriptor{b_device_class: 0x02, b_device_sub_class: 0x0, id_vendor: 0x067B, id_product: 0x2303, i_manufacturer: "TAITO", i_product: "Densha de Go! Plug & Play (Master Controller II mode)", i_serial_number: "VOK-00106"}; +pub const DEVICE_DESCRIPTOR: DeviceDescriptor = DeviceDescriptor{b_device_class: 0x02, b_device_sub_class: 0x0, id_vendor: 0x067B, id_product: 0x2303, bcd_device: 0x0102, i_manufacturer: "TAITO", i_product: "Densha de Go! Plug & Play (Master Controller II mode)", i_serial_number: "VOK-00106"}; const POWER_NOTCHES: [&str; 6] = ["TSA50", "TSA55", "TSA65", "TSA75", "TSA85", "TSA95"]; diff --git a/src/controller/emulated/zkns001.rs b/src/controller/emulated/zkns001.rs index 40f7d11..211b7fd 100644 --- a/src/controller/emulated/zkns001.rs +++ b/src/controller/emulated/zkns001.rs @@ -15,7 +15,7 @@ pub const DESCRIPTORS: [u8; 80] = [0x01, 0x00, 0x00, 0x00, 0x50, 0x00, 0x00, 0x0 0x07, 0x05, 0x81, 0x03, 0x40, 0x00, 0x05]; pub const STRINGS: [u8; 16] = [0x02, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]; -pub const DEVICE_DESCRIPTOR: DeviceDescriptor = DeviceDescriptor{b_device_class: 0x0, b_device_sub_class: 0x0, id_vendor: 0x33DD, id_product: 0x0001, i_manufacturer: "TAITO", i_product: "Densha de Go! Plug & Play (NS One Handle mode)", i_serial_number: "ZKNS-001"}; +pub const DEVICE_DESCRIPTOR: DeviceDescriptor = DeviceDescriptor{b_device_class: 0x0, b_device_sub_class: 0x0, id_vendor: 0x33DD, id_product: 0x0001, bcd_device: 0x0106, i_manufacturer: "TAITO", i_product: "Densha de Go! Plug & Play (NS One Handle mode)", i_serial_number: "ZKNS-001"}; pub const HID_REPORT_DESCRIPTOR: [u8; 94] = [ 0x05, 0x01, // Usage Page (Generic Desktop Ctrls) @@ -94,32 +94,39 @@ pub fn update_gadget(state: &mut ControllerState) { handle = BRAKE_NOTCHES[state.brake as usize]; } - // Calculate data for buttons 1 + // Calculate data for buttons let mut buttons1 = Buttons1::NONE; + let mut buttons2 = Buttons2::NONE; + if !state.button_select_hold && state.button_select && state.button_left { + buttons1.insert(Buttons1::L); + state.combo = true; + } + if !state.button_select_hold && state.button_select && state.button_right { + buttons1.insert(Buttons1::R); + state.combo = true; + } + if !state.button_select_hold && state.button_start && state.button_select { + buttons2.insert(Buttons2::HOME); + state.combo = true; + } if state.button_a { buttons1.insert(Buttons1::Y) } if state.button_b { buttons1.insert(Buttons1::B) } if state.button_c { buttons1.insert(Buttons1::A) } if state.button_d { buttons1.insert(Buttons1::X) } if state.brake == 9 { buttons1.insert(Buttons1::ZL) } - if state.button_select && state.button_left { buttons1.insert(Buttons1::L) } - if state.button_select && state.button_right { buttons1.insert(Buttons1::R) } - - // Calculate data for buttons 2 - let mut buttons2 = Buttons2::NONE; - if state.button_start && !state.button_select { buttons2.insert(Buttons2::START) } - if state.button_select && !state.button_start { buttons2.insert(Buttons2::SELECT) } - if state.button_start && state.button_select { buttons2.insert(Buttons2::HOME) } + if !state.combo && state.button_start { buttons2.insert(Buttons2::START) } + if !state.combo && state.button_select_hold { buttons2.insert(Buttons2::SELECT) } // Calculate data for D-pad let mut dpad: u8 = 0xF; if state.button_up { dpad = 0x0 } if state.button_down { dpad = 0x4 } - if state.button_left { dpad = 0x6 } - if state.button_right { dpad = 0x2 } - if state.button_up & state.button_left { dpad = 0x7 } - if state.button_up & state.button_right { dpad = 0x1 } - if state.button_down & state.button_left { dpad = 0x5 } - if state.button_down & state.button_right { dpad = 0x3 } + if !state.combo && state.button_left { dpad = 0x6 } + if !state.combo && state.button_right { dpad = 0x2 } + if !state.combo && state.button_up & state.button_left { dpad = 0x7 } + if !state.combo && state.button_up & state.button_right { dpad = 0x1 } + if !state.combo && state.button_down & state.button_left { dpad = 0x5 } + if !state.combo && state.button_down & state.button_right { dpad = 0x3 } // Assemble data and send it to gadget let data = [buttons1.bits, buttons2.bits, dpad, 0x80, handle, 0x80, 0x80, 0x00]; diff --git a/src/controller/physical.rs b/src/controller/physical.rs index f3818fe..c995b9f 100644 --- a/src/controller/physical.rs +++ b/src/controller/physical.rs @@ -1,6 +1,7 @@ use std::fs::File; use std::io::Write; use std::io::Result; +use std::time::{Instant,Duration}; use evdev::Device; use evdev::Key; @@ -10,6 +11,8 @@ pub struct ControllerState { pub power: u8, pub brake: u8, pub button_select: bool, + pub button_select_hold: bool, + pub button_select_time: Option, pub button_start: bool, pub button_a: bool, pub button_b: bool, @@ -21,8 +24,12 @@ pub struct ControllerState { pub button_right: bool, pub lamp: bool, pub rumble: bool, + pub combo: bool, + pub reverser: u8, } +const HOLD_DELAY: Duration = Duration::from_millis(750); + const USED_KEYS: [Key; 26] = [Key::KEY_0, Key::KEY_1, Key::KEY_2, Key::KEY_3, Key::KEY_4, Key::KEY_5, Key::KEY_B, Key::KEY_C, Key::KEY_D, Key::KEY_E, Key::KEY_F, Key::KEY_G, Key::KEY_H, Key::KEY_I, Key::KEY_J, Key::KEY_P, Key::KEY_SPACE, Key::KEY_ENTER, Key::KEY_A, Key::KEY_Z, Key::KEY_X, Key::KEY_S, Key::KEY_UP, Key::KEY_DOWN, Key::KEY_LEFT, Key::KEY_RIGHT]; @@ -47,7 +54,7 @@ pub fn get_state(state: &mut ControllerState, dev: &[Device; 2]) { fn read_input(controller: &mut ControllerState, key: Key, value: bool) { // Save input status to object for processing - match key{ + match key { Key::KEY_0=>if value {controller.power = 0}, Key::KEY_1=>if value {controller.power = 1}, Key::KEY_2=>if value {controller.power = 2}, @@ -64,7 +71,20 @@ fn read_input(controller: &mut ControllerState, key: Key, value: bool) { Key::KEY_I=>if value {controller.brake = 7}, Key::KEY_J=>if value {controller.brake = 8}, Key::KEY_P=>if value {controller.brake = 9}, - Key::KEY_SPACE=>controller.button_select = value, + Key::KEY_SPACE=> { + if !controller.button_select && value { + controller.button_select_time = Some(Instant::now()); + } + else if !value { + controller.button_select_time = None; + controller.combo = false; + } + controller.button_select = value; + controller.button_select_hold = value; + if let Some(time) = controller.button_select_time { + controller.button_select_hold = time.elapsed() > HOLD_DELAY && !controller.combo; + } + }, Key::KEY_ENTER=>controller.button_start = value, Key::KEY_A=>controller.button_a = value, Key::KEY_Z=>controller.button_b = value,