OXYGENHUB
◆ main x16-emulator / src / joystick.c
8.6 KiB · C · last changed chore(): initial commit 15 days ago source blame history raw
1
#include "joystick.h"
2
3
#include <SDL.h>
4
#include <stdio.h>
5
6
struct joystick_info {
7
	int                 instance_id;
8
	SDL_GameController *controller;
9
	uint16_t            button_mask;
10
	uint16_t            shift_mask;
11
};
12
13
static const uint16_t button_map[SDL_CONTROLLER_BUTTON_MAX] = {
14
    1 << 0,  //SDL_CONTROLLER_BUTTON_A,
15
    1 << 8,  //SDL_CONTROLLER_BUTTON_B,
16
    1 << 1,  //SDL_CONTROLLER_BUTTON_X,
17
    1 << 9,  //SDL_CONTROLLER_BUTTON_Y,
18
    1 << 2,  //SDL_CONTROLLER_BUTTON_BACK,
19
    0,       //SDL_CONTROLLER_BUTTON_GUIDE,
20
    1 << 3,  //SDL_CONTROLLER_BUTTON_START,
21
    0,       //SDL_CONTROLLER_BUTTON_LEFTSTICK,
22
    0,       //SDL_CONTROLLER_BUTTON_RIGHTSTICK,
23
    1 << 10, //SDL_CONTROLLER_BUTTON_LEFTSHOULDER,
24
    1 << 11, //SDL_CONTROLLER_BUTTON_RIGHTSHOULDER,
25
    1 << 4,  //SDL_CONTROLLER_BUTTON_DPAD_UP,
26
    1 << 5,  //SDL_CONTROLLER_BUTTON_DPAD_DOWN,
27
    1 << 6,  //SDL_CONTROLLER_BUTTON_DPAD_LEFT,
28
    1 << 7,  //SDL_CONTROLLER_BUTTON_DPAD_RIGHT,
29
};
30
31
static struct joystick_info *Joystick_controllers     = NULL;
32
static int                   Num_joystick_controllers = 0;
33
34
static void
35
resize_joystick_controllers(int new_size)
36
{
37
	if (new_size == 0) {
38
		free(Joystick_controllers);
39
		Joystick_controllers     = NULL;
40
		Num_joystick_controllers = 0;
41
		return;
42
	}
43
44
	struct joystick_info *old_controllers = Joystick_controllers;
45
	Joystick_controllers                  = (struct joystick_info *)malloc(sizeof(struct joystick_info) * new_size);
46
47
	int min_size = new_size < Num_joystick_controllers ? new_size : Num_joystick_controllers;
48
	if (min_size > 0) {
49
		memcpy(Joystick_controllers, old_controllers, sizeof(struct joystick_info) * min_size);
50
		free(old_controllers);
51
	}
52
53
	for (int i = min_size; i < new_size; ++i) {
54
		Joystick_controllers[i].instance_id = -1;
55
		Joystick_controllers[i].controller  = NULL;
56
		Joystick_controllers[i].button_mask = 0xffff;
57
		Joystick_controllers[i].shift_mask  = 0;
58
	}
59
}
60
61
static void
62
add_joystick_controller(struct joystick_info *info)
63
{
64
	int i;
65
	for (i = 0; i < Num_joystick_controllers; ++i) {
66
		if (Joystick_controllers[i].instance_id == -1) {
67
			memcpy(&Joystick_controllers[i], info, sizeof(struct joystick_info));
68
			return;
69
		}
70
	}
71
72
	i = Num_joystick_controllers;
73
	resize_joystick_controllers(Num_joystick_controllers << 1);
74
75
	memcpy(&Joystick_controllers[i], info, sizeof(struct joystick_info));
76
}
77
78
static void
79
remove_joystick_controller(int instance_id)
80
{
81
	for (int i = 0; i < Num_joystick_controllers; ++i) {
82
		if (Joystick_controllers[i].instance_id == instance_id) {
83
			Joystick_controllers[i].instance_id = -1;
84
			Joystick_controllers[i].controller  = NULL;
85
			return;
86
		}
87
	}
88
}
89
90
static struct joystick_info *
91
find_joystick_controller(int instance_id)
92
{
93
	for (int i = 0; i < Num_joystick_controllers; ++i) {
94
		if (Joystick_controllers[i].instance_id == instance_id) {
95
			return &Joystick_controllers[i];
96
		}
97
	}
98
99
	return NULL;
100
}
101
102
bool Joystick_slots_enabled[NUM_JOYSTICKS] = {false, false, false, false};
103
static int Joystick_slots[NUM_JOYSTICKS];
104
105
static bool Joystick_latch = false;
106
uint8_t Joystick_data  = 0;
107
108
bool
109
joystick_init(void)
110
{
111
	for (int i = 0; i < NUM_JOYSTICKS; ++i) {
112
		Joystick_slots[i] = -1;
113
	}
114
115
	const int num_joysticks = SDL_NumJoysticks();
116
117
	Num_joystick_controllers = num_joysticks > 16 ? num_joysticks : 16;
118
	Joystick_controllers     = malloc(sizeof(struct joystick_info) * Num_joystick_controllers);
119
120
	for (int i = 0; i < Num_joystick_controllers; ++i) {
121
		Joystick_controllers[i].instance_id = -1;
122
		Joystick_controllers[i].controller  = NULL;
123
		Joystick_controllers[i].button_mask = 0xffff;
124
		Joystick_controllers[i].shift_mask  = 0;
125
	}
126
127
	for (int i = 0; i < num_joysticks; ++i) {
128
		joystick_add(i);
129
	}
130
131
	return true;
132
}
133
134
void
135
joystick_add(int index)
136
{
137
	if (!SDL_IsGameController(index)) {
138
		return;
139
	}
140
141
	SDL_GameController *controller = SDL_GameControllerOpen(index);
142
	if (controller == NULL) {
143
		fprintf(stderr, "Could not open controller %d: %s\n", index, SDL_GetError());
144
		return;
145
	}
146
147
	SDL_JoystickID instance_id = SDL_JoystickInstanceID(SDL_GameControllerGetJoystick(controller));
148
	bool           exists      = false;
149
	for (int i = 0; i < NUM_JOYSTICKS; ++i) {
150
		if (!Joystick_slots_enabled[i]) {
151
			continue;
152
		}
153
154
		if (Joystick_slots[i] == instance_id) {
155
			exists = true;
156
			break;
157
		}
158
	}
159
160
	if (!exists) {
161
		for (int i = 0; i < NUM_JOYSTICKS; ++i) {
162
			if (!Joystick_slots_enabled[i]) {
163
				continue;
164
			}
165
166
			if (Joystick_slots[i] == -1) {
167
				Joystick_slots[i] = instance_id;
168
				break;
169
			}
170
		}
171
172
		struct joystick_info new_info;
173
		new_info.instance_id = instance_id;
174
		new_info.controller  = controller;
175
		new_info.button_mask = 0xffff;
176
		new_info.shift_mask  = 0;
177
		add_joystick_controller(&new_info);
178
	}
179
}
180
181
void
182
joystick_remove(int instance_id)
183
{
184
	for (int i = 0; i < NUM_JOYSTICKS; ++i) {
185
		if (Joystick_slots[i] == instance_id) {
186
			Joystick_slots[i] = -1;
187
			break;
188
		}
189
	}
190
191
	SDL_GameController *controller = SDL_GameControllerFromInstanceID(instance_id);
192
	if (controller == NULL) {
193
		fprintf(stderr, "Could not find controller from instance_id %d: %s\n", instance_id, SDL_GetError());
194
	} else {
195
		SDL_GameControllerClose(controller);
196
		remove_joystick_controller(instance_id);
197
	}
198
}
199
200
void
201
joystick_button_down(int instance_id, uint8_t button)
202
{
203
	struct joystick_info *joy = find_joystick_controller(instance_id);
204
	if (joy != NULL) {
205
		joy->button_mask &= ~(button_map[button]);
206
	}
207
}
208
209
void
210
joystick_button_up(int instance_id, uint8_t button)
211
{
212
	struct joystick_info *joy = find_joystick_controller(instance_id);
213
	if (joy != NULL) {
214
		joy->button_mask |= button_map[button];
215
	}
216
}
217
218
static void
219
do_shift()
220
{
221
	for (int i = 0; i < NUM_JOYSTICKS; ++i) {
222
		if (Joystick_slots[i] >= 0) {
223
			struct joystick_info *joy = find_joystick_controller(Joystick_slots[i]);
224
			if (joy != NULL) {
225
				Joystick_data |= ((joy->shift_mask & 1) ? (0x80 >> i) : 0);
226
				joy->shift_mask >>= 1;
227
			} else {
228
				Joystick_data |= 0x80 >> i;
229
			}
230
		} else {
231
			Joystick_data |= 0x80 >> i;
232
		}
233
	}
234
}
235
236
void
237
joystick_set_latch(bool value)
238
{
239
	Joystick_latch = value;
240
	if (value) {
241
		for (int i = 0; i < Num_joystick_controllers; ++i) {
242
			if (Joystick_controllers[i].instance_id != -1) {
243
				Joystick_controllers[i].shift_mask = Joystick_controllers[i].button_mask | 0xF000;
244
			}
245
		}
246
		do_shift();
247
	}
248
}
249
250
void
251
joystick_set_clock(bool value)
252
{
253
	if (!Joystick_latch && value) {
254
		Joystick_data = 0;
255
		do_shift();
256
	}
257
}
258
259
/* --- Virtual pads, for the RRDC control port (contract 0.5) ----------
260
 *
261
 * A harness driving the machine over HTTP has no SDL controller to
262
 * plug in, so it asks for one to be synthesised. The synthetic pad is
263
 * an ordinary entry in Joystick_controllers with no SDL device behind
264
 * it: everything downstream — latch, shift, Joystick_data — treats it
265
 * exactly like real hardware, which is the point. Nothing in the
266
 * read path learns that a pad is virtual.
267
 *
268
 * Instance ids come from a range SDL cannot produce (SDL hands out
269
 * small ascending ints), so a virtual pad and a real one can coexist
270
 * without ever colliding in find_joystick_controller().
271
 * ------------------------------------------------------------------ */
272
273
#define JOY_VIRTUAL_ID_BASE (1 << 24)
274
275
bool
276
joystick_virtual_set(int slot, bool connected, bool set_buttons, uint16_t mask)
277
{
278
	if (slot < 0 || slot >= NUM_JOYSTICKS) {
279
		return false;
280
	}
281
282
	const int vid = JOY_VIRTUAL_ID_BASE + slot;
283
284
	if (!connected) {
285
		if (Joystick_slots[slot] == vid) {
286
			Joystick_slots[slot] = -1;
287
		}
288
		remove_joystick_controller(vid);
289
		return true;
290
	}
291
292
	struct joystick_info *joy = find_joystick_controller(vid);
293
	if (joy == NULL) {
294
		struct joystick_info new_info;
295
		new_info.instance_id = vid;
296
		new_info.controller  = NULL;    /* no SDL device behind it */
297
		new_info.button_mask = 0xffff;  /* active low: nothing held */
298
		new_info.shift_mask  = 0;
299
		add_joystick_controller(&new_info);
300
		joy = find_joystick_controller(vid);
301
		if (joy == NULL) {
302
			return false;
303
		}
304
	}
305
306
	if (set_buttons) {
307
		joy->button_mask = mask;
308
	}
309
310
	/* Presenting a pad implies its slot is live: a harness that had to
311
	 * remember -joy1 on the command line as well would be a trap. */
312
	Joystick_slots_enabled[slot] = true;
313
	Joystick_slots[slot]         = vid;
314
	return true;
315
}
316
317
bool
318
joystick_virtual_get(int slot, bool *connected, uint16_t *mask)
319
{
320
	if (slot < 0 || slot >= NUM_JOYSTICKS) {
321
		return false;
322
	}
323
324
	const int id = Joystick_slots[slot];
325
	if (id < 0) {
326
		*connected = false;
327
		*mask      = 0xffff;
328
		return true;
329
	}
330
331
	/* Deliberately not restricted to virtual ids: a real controller
332
	 * bound to this slot reads back the same way, so a test can assert
333
	 * on input regardless of how it got there. */
334
	struct joystick_info *joy = find_joystick_controller(id);
335
	*connected = (joy != NULL);
336
	*mask      = (joy != NULL) ? joy->button_mask : 0xffff;
337
	return true;
338
}