forked from ares-emulator/ares
-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathsdl.cpp
132 lines (113 loc) · 4.11 KB
/
sdl.cpp
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
#pragma once
struct InputJoypadSDL {
Input& input;
InputJoypadSDL(Input& input) : input(input) {}
struct Joypad {
shared_pointer<HID::Joypad> hid{new HID::Joypad};
vector<bool> axisPolled;
u32 id = 0;
SDL_Joystick* handle = nullptr;
};
vector<Joypad> joypads;
auto assign(Joypad& joypad, u32 groupID, u32 inputID, s16 value) -> void {
auto& group = joypad.hid->group(groupID);
if(group.input(inputID).value() == value) return;
if(groupID == HID::Joypad::GroupID::Axis && !joypad.axisPolled(inputID)) {
//suppress the first axis polling event, because the value can change dramatically.
//SDL seems to return 0 for all axes, until the first movement, where it jumps to the real value.
//this triggers onChange handlers to instantly bind inputs erroneously if not suppressed.
joypad.axisPolled[inputID] = true;
} else {
input.doChange(joypad.hid, groupID, inputID, group.input(inputID).value(), value);
}
group.input(inputID).setValue(value);
}
auto poll(vector<shared_pointer<HID::Device>>& devices) -> void {
SDL_UpdateJoysticks();
SDL_Event event;
while(SDL_PollEvent(&event)) {
if(event.type == SDL_EVENT_JOYSTICK_ADDED || event.type == SDL_EVENT_JOYSTICK_REMOVED) {
enumerate();
}
}
for(auto& jp : joypads) {
for(u32 n : range(jp.hid->axes().size())) {
assign(jp, HID::Joypad::GroupID::Axis, n, (s16)SDL_GetJoystickAxis(jp.handle, n));
}
for(s32 n = 0; n < (s32)jp.hid->hats().size() - 1; n += 2) {
u8 state = SDL_GetJoystickHat(jp.handle, n >> 1);
assign(jp, HID::Joypad::GroupID::Hat, n + 0, state & SDL_HAT_LEFT ? -32767 : state & SDL_HAT_RIGHT ? +32767 : 0);
assign(jp, HID::Joypad::GroupID::Hat, n + 1, state & SDL_HAT_UP ? -32767 : state & SDL_HAT_DOWN ? +32767 : 0);
}
for(u32 n : range(jp.hid->buttons().size())) {
assign(jp, HID::Joypad::GroupID::Button, n, (bool)SDL_GetJoystickButton(jp.handle, n));
}
devices.append(jp.hid);
}
}
auto rumble(u64 id, u16 strong, u16 weak) -> bool {
for(auto& jp : joypads) {
if(jp.hid->id() != id) continue;
SDL_RumbleJoystick(jp.handle, strong, weak, 0);
return true;
}
return false;
}
auto initialize() -> bool {
terminate();
SDL_Init(SDL_INIT_EVENTS);
SDL_InitSubSystem(SDL_INIT_JOYSTICK);
//SDL_JoystickEventState(1);
enumerate();
return true;
}
auto terminate() -> void {
for(auto& jp : joypads) {
SDL_CloseJoystick(jp.handle);
}
joypads.reset();
SDL_QuitSubSystem(SDL_INIT_JOYSTICK);
}
private:
auto enumerate() -> void {
for(auto& joypad : joypads) {
SDL_CloseJoystick(joypad.handle);
}
joypads.reset();
int num_joysticks;
SDL_JoystickID *joysticks = SDL_GetJoysticks(&num_joysticks);
for(int i = 0; i < num_joysticks; i++) {
SDL_JoystickID id = joysticks[i];
Joypad jp;
jp.id = id;
jp.handle = SDL_OpenJoystick(jp.id);
if(!jp.handle) {
const char *err = SDL_GetError();
print("Error opening SDL joystick id ", id, ": ", err);
continue;
}
s32 axes = SDL_GetNumJoystickAxes(jp.handle);
s32 hats = SDL_GetNumJoystickHats(jp.handle) * 2;
s32 buttons = SDL_GetNumJoystickButtons(jp.handle);
if(axes < 0 || hats < 0 || buttons < 0) {
const char *err = SDL_GetError();
print("Error retrieving SDL joystick information for device ", jp.handle, " at index ", id, ": ", err);
continue;
}
u16 vid = SDL_GetJoystickVendor(jp.handle);
u16 pid = SDL_GetJoystickProduct(jp.handle);
if(vid == 0) vid = HID::Joypad::GenericVendorID;
if(pid == 0) pid = HID::Joypad::GenericProductID;
jp.hid->setVendorID(vid);
jp.hid->setProductID(pid);
jp.hid->setPathID(jp.id);
for(u32 n : range(axes)) jp.hid->axes().append(n);
for(u32 n : range(hats)) jp.hid->hats().append(n);
for(u32 n : range(buttons)) jp.hid->buttons().append(n);
jp.hid->setRumble(true);
joypads.append(jp);
}
SDL_free(joysticks);
SDL_UpdateJoysticks();
}
};