This repository has been archived by the owner on Jan 18, 2024. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathgamepad.rs
154 lines (127 loc) · 4.81 KB
/
gamepad.rs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
use bitflags::bitflags;
// TODO: this is from the Pinput Rust implementation. Extract it to its own crate.
/// Pinput can fit this many gamepads into the GPIO area.
pub const PINPUT_MAX_GAMEPADS: usize = 8;
bitflags! {
/// Gamepad informational flags.
#[derive(Default)]
pub struct PinputGamepadFlags: u8 {
/// This gamepad is connected.
const CONNECTED = 1 << 0;
/// This gamepad has a battery.
/// If this is true, the `battery` field and the `Charging` flag may be non-zero.
const HAS_BATTERY = 1 << 1;
/// This gamepad is currently charging its battery.
const CHARGING = 1 << 2;
/// Does this controller have a usable guide button?
/// Not all Apple-supported gamepads have a guide button,
/// and versions of Pinput on other platforms might not have access to them
/// (XInput on Windows, for example).
const HAS_GUIDE_BUTTON = 1 << 3;
/// Does this controller have a misc or touchpad-click button?
const HAS_MISC_BUTTON = 1 << 4;
/// Does this controller support vibration?
const HAS_RUMBLE = 1 << 5;
/// Is this gamepad actually a haptic device?
const HAPTIC_DEVICE = 1 << 6;
}
}
bitflags! {
/// Flags indicating which buttons are currently pressed.
/// Same as <https://docs.microsoft.com/en-us/windows/win32/api/xinput/ns-xinput-xinput_gamepad>
/// with the addition of guide and misc buttons in the two unused bits.
#[derive(Default)]
pub struct PinputGamepadButtons: u16 {
const DPAD_UP = 1 << 0;
const DPAD_DOWN = 1 << 1;
const DPAD_LEFT = 1 << 2;
const DPAD_RIGHT = 1 << 3;
const START = 1 << 4;
const BACK = 1 << 5;
const LEFT_STICK = 1 << 6;
const RIGHT_STICK = 1 << 7;
const LEFT_BUMPER = 1 << 8;
const RIGHT_BUMPER = 1 << 9;
const GUIDE = 1 << 10;
/// We map both SDL `Misc1` and `Touchpad` to this.
/// No current controllers have both buttons, and they're in approximately the same spot.
const MISC = 1 << 11;
const A = 1 << 12;
const B = 1 << 13;
const X = 1 << 14;
const Y = 1 << 15;
}
}
/// Structure representing a gamepad to the runtime.
/// Based on <https://docs.microsoft.com/en-us/windows/win32/api/xinput/ns-xinput-xinput_gamepad>
/// and <https://docs.microsoft.com/en-us/windows/win32/api/xinput/ns-xinput-xinput_vibration>
/// but prefixed with controller flags and a battery meter, and with smaller rumble types to fit
/// into a convenient size (16 bytes). All fields are written to the runtime,
/// except for the rumble fields, which are read from the runtime.
#[repr(C, packed)]
#[derive(Copy, Clone, Debug, Default)]
pub struct PinputGamepad {
pub flags: PinputGamepadFlags,
/// 0 for empty or not present, max value for fully charged.
pub battery: u8,
pub buttons: PinputGamepadButtons,
pub left_trigger: u8,
pub right_trigger: u8,
pub left_stick_x: i16,
pub left_stick_y: i16,
pub right_stick_x: i16,
pub right_stick_y: i16,
/// Output from the runtime.
pub lo_freq_rumble: u8,
/// Output from the runtime.
pub hi_freq_rumble: u8,
}
/// Fill GPIO with gamepads.
pub type PinputGamepadArray = [PinputGamepad; PINPUT_MAX_GAMEPADS];
// TODO: this part is mostly copied from the Pinput Lua API.
const GPIO: *mut [u8; 128] = 0x20 as *mut [u8; 128];
pub const PI_GAMEPADS: *mut PinputGamepadArray = 0x20 as *mut PinputGamepadArray;
pub fn pi_init() {
// Pinput magic is `0x02_20_c7_46_77_ab_44_6e_be_dc_7f_d6_d2_77_98_4d`
// but we don't want that literally in our constants.
// (Unless it's guaranteed by WASM + Rust that constants are mapped into non-writable memory?)
unsafe {
(*GPIO)[0xf] = 0x4d;
(*GPIO)[0xe] = 0x98;
(*GPIO)[0xd] = 0x77;
(*GPIO)[0xc] = 0xd2;
(*GPIO)[0xb] = 0xd6;
(*GPIO)[0xa] = 0x7f;
(*GPIO)[0x9] = 0xdc;
(*GPIO)[0x8] = 0xbe;
(*GPIO)[0x7] = 0x6e;
(*GPIO)[0x6] = 0x44;
(*GPIO)[0x5] = 0xab;
(*GPIO)[0x4] = 0x77;
(*GPIO)[0x3] = 0x46;
(*GPIO)[0x2] = 0xc7;
(*GPIO)[0x1] = 0x20;
(*GPIO)[0x0] = 0x02;
}
}
pub fn pi_is_inited() -> bool {
unsafe {
(*GPIO)[0xf] != 0x4d
|| (*GPIO)[0xe] != 0x98
|| (*GPIO)[0xd] != 0x77
|| (*GPIO)[0xc] != 0xd2
|| (*GPIO)[0xb] != 0xd6
|| (*GPIO)[0xa] != 0x7f
|| (*GPIO)[0x9] != 0xdc
|| (*GPIO)[0x8] != 0xbe
|| (*GPIO)[0x7] != 0x6e
|| (*GPIO)[0x6] != 0x44
|| (*GPIO)[0x5] != 0xab
|| (*GPIO)[0x4] != 0x77
|| (*GPIO)[0x3] != 0x46
|| (*GPIO)[0x2] != 0xc7
|| (*GPIO)[0x1] != 0x20
|| (*GPIO)[0x0] != 0x02
}
}
// TODO: implement full Pinput API like PICO-8 version