mirror of
https://github.com/marcriera/ddgo-pnp-controller.git
synced 2025-04-11 06:29:29 +02:00
Add button combos
This commit is contained in:
parent
1c7eb05cab
commit
8bd5b463c1
12 changed files with 194 additions and 84 deletions
28
README.md
28
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).
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
|
|
@ -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];
|
||||
|
|
|
@ -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];
|
||||
|
|
|
@ -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"];
|
||||
|
|
|
@ -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];
|
||||
|
|
|
@ -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<Instant>,
|
||||
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,
|
||||
|
|
Loading…
Add table
Reference in a new issue