-
Notifications
You must be signed in to change notification settings - Fork 16
/
Copy pathgamecontroller.c.m4
409 lines (381 loc) · 13.7 KB
/
gamecontroller.c.m4
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
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
/* -*- mode: C -*- */
#include "rubysdl2_internal.h"
#include <SDL_gamecontroller.h>
static VALUE cGameController;
static VALUE mAxis;
static VALUE mButton;
typedef struct GameController {
SDL_GameController* controller;
} GameController;
static void GameController_free(GameController* g)
{
if (rubysdl2_is_active() && g->controller)
SDL_GameControllerClose(g->controller);
free(g);
}
/*
* Document-class: SDL2::GameController
*
* This class represents a "Game Controller".
*
* In SDL2, there is a gamecontroller framework to
* hide the details of joystick types. This framework
* is built on the existing joystick API.
*
* The framework consists of two parts:
*
* * Mapping joysticks to game controllers
* * Aquire input from game controllers
*
* Mapping information is a string, and described as:
*
* GUID,name,mapping
*
* GUID is a unique ID of a type of joystick and
* given by {Joystick#GUID}. name is the human readable
* string for the device, and mappings are contorller mappings
* to joystick ones.
*
* This mappings abstract the details of joysticks, for exmaple,
* the number of buttons, the number of axes, and the position
* of these buttons a on pad.
* You can use unified interface
* with this framework theoretically.
* Howerver, we need to prepare the
* database of many joysticks that users will use. A database
* is available at https://github.com/gabomdq/SDL_GameControllerDB,
* but perhaps this is not sufficient for your usage.
* In fact, Steam prepares its own database for Steam games,
* so if you will create a game for Steam, this framework is
* useful. Otherwise, it is a better way to use joystick API
* directly.
*
* @!method destroy?
* Return true if the gamecontroller is already closed.
*/
static VALUE GameController_new(SDL_GameController* controller)
{
GameController* g = ALLOC(GameController);
g->controller = controller;
return Data_Wrap_Struct(cGameController, 0, GameController_free, g);
}
DEFINE_WRAPPER(SDL_GameController, GameController, controller, cGameController,
"SDL2::GameController");
/*
* @overload add_mapping(string)
*
* Add suuport for controolers that SDL is unaware of or to cause an
* existing controller to have a different binding.
*
* "GUID,name,mapping", where GUID is
* the string value from SDL_JoystickGetGUIDString(), name is the human
* readable string for the device and mappings are controller mappings to
* joystick ones. Under Windows there is a reserved GUID of "xinput" that
* covers all XInput devices. The mapping format for joystick is:
*
* * bX: a joystick button, index X
* * hX.Y: hat X with value Y
* * aX: axis X of the joystick
*
* Buttons can be used as a controller axes and vice versa.
*
* This string shows an example of a valid mapping for a controller:
* "341a3608000000000000504944564944,Afterglow PS3 Controller,a:b1,b:b2,y:b3,x:b0,start:b9,guide:b12,back:b8,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftshoulder:b4,,rightshoulder:b5,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b6,righttrigger:b7"
*
* @param string [String] mapping string
* @return [Integer] 1 if a new mapping, 0 if an existing mapping is updated.
*/
static VALUE GameController_s_add_mapping(VALUE self, VALUE string)
{
int ret = HANDLE_ERROR(SDL_GameControllerAddMapping(StringValueCStr(string)));
return INT2NUM(ret);
}
/*
* @overload axis_name_of(axis)
*
* Get a string representing **axis**.
*
* @param axis [Integer] axis constant in {Axis}
* @return [String]
*/
static VALUE GameController_s_axis_name_of(VALUE self, VALUE axis)
{
const char* name = SDL_GameControllerGetStringForAxis(NUM2INT(axis));
if (!name) {
SDL_SetError("Unknown axis %d", NUM2INT(axis));
SDL_ERROR();
}
return utf8str_new_cstr(name);
}
/*
* @overload button_name_of(button)
*
* Get a string representing **button**.
*
* @param button [Integer] button constant in {Button}
* @return [String]
*/
static VALUE GameController_s_button_name_of(VALUE self, VALUE button)
{
const char* name = SDL_GameControllerGetStringForButton(NUM2INT(button));
if (!name) {
SDL_SetError("Unknown axis %d", NUM2INT(button));
SDL_ERROR();
}
return utf8str_new_cstr(name);
}
/*
* @overload axis_from_name(name)
*
* Get a integer representation of the axis
* whose string representation is **name**.
*
* The return value is the value of one of the constants in {Axis}
*
* @param name [String] a string representing an axis
* @return [Integer]
*/
static VALUE GameController_s_axis_from_name(VALUE self, VALUE name)
{
int axis = SDL_GameControllerGetAxisFromString(StringValueCStr(name));
if (axis < 0) {
SDL_SetError("Unknown axis name \"%s\"", StringValueCStr(name));
SDL_ERROR();
}
return INT2FIX(axis);
}
/*
* @overload button_from_name(name)
*
* Get a integer representation of the button
* whose string representation is **name**.
*
* The return value is the value of one of the constants in {Button}
*
* @param name [String] a string representing a button
* @return [Integer]
*/
static VALUE GameController_s_button_from_name(VALUE self, VALUE name)
{
int button = SDL_GameControllerGetButtonFromString(StringValueCStr(name));
if (button < 0) {
SDL_SetError("Unknown button name \"%s\"", StringValueCStr(name));
SDL_ERROR();
}
return INT2FIX(button);
}
/*
* Get the implementation dependent name for the game controllers
* connected to the machine.
*
* The number of elements of returning array is same as
* {Joystick.num_connected_joysticks}.
*
* @return [Array<String,nil>]
*/
static VALUE GameController_s_device_names(VALUE self)
{
int num_joysticks = SDL_NumJoysticks();
int i;
VALUE device_names = rb_ary_new2(num_joysticks);
for (i=0; i<num_joysticks; ++i) {
const char* name = SDL_GameControllerNameForIndex(i);
if (name)
rb_ary_push(device_names, utf8str_new_cstr(name));
else
rb_ary_push(device_names, Qnil);
}
return device_names;
}
/*
* @overload mapping_for(guid_string)
* Get the game controller mapping string for a given GUID.
*
* @param guid_string [String] GUID string
*
* @return [String]
*/
static VALUE GameController_s_mapping_for(VALUE self, VALUE guid_string)
{
SDL_JoystickGUID guid = SDL_JoystickGetGUIDFromString(StringValueCStr(guid_string));
return utf8str_new_cstr(SDL_GameControllerMappingForGUID(guid));
}
/*
* @overload open(index)
* Open a game controller and return the opened GameController object.
*
* @param index [Integer] device index, up to the return value of {Joystick.num_connected_joysticks}.
* @return [SDL2::GameController]
*
* @raise [SDL2::Error] raised when device open is failed.
* For exmaple, **index** is out of range.
*/
static VALUE GameController_s_open(VALUE self, VALUE index)
{
SDL_GameController* controller = SDL_GameControllerOpen(NUM2INT(index));
if (!controller)
SDL_ERROR();
return GameController_new(controller);
}
/*
* Get the name of an opened game controller.
*
* @return [String]
*/
static VALUE GameController_name(VALUE self)
{
const char* name = SDL_GameControllerName(Get_SDL_GameController(self));
if (!name)
SDL_ERROR();
return utf8str_new_cstr(name);
}
/*
* Return true if **self** is opened and attached.
*/
static VALUE GameController_attached_p(VALUE self)
{
return INT2BOOL(SDL_GameControllerGetAttached(Get_SDL_GameController(self)));
}
/*
* Close the game controller.
*
* @return nil
*/
static VALUE GameController_destroy(VALUE self)
{
GameController* g = Get_GameController(self);
if (g->controller)
SDL_GameControllerClose(g->controller);
g->controller = NULL;
return Qnil;
}
/*
* Get the mapping string of **self**.
*
* @return [String]
* @see .add_mapping
* @see .mapping_for
*/
static VALUE GameController_mapping(VALUE self)
{
return utf8str_new_cstr(SDL_GameControllerMapping(Get_SDL_GameController(self)));
}
/*
* @overload axis(axis)
* Get the state of an axis control.
*
* The state is an integer from -32768 to 32767.
* The state of trigger never returns negative value (from 0 to 32767).
*
* @param axis [Integer] the index of an axis, one of the constants in {Axis}
* @return [Integer]
*/
static VALUE GameController_axis(VALUE self, VALUE axis)
{
return INT2FIX(SDL_GameControllerGetAxis(Get_SDL_GameController(self),
NUM2INT(axis)));
}
/*
* @overload button_pressed?(button)
* Return true if a button is pressed.
*
* @param button [Integer] the index of a button, one of the constants in {Button}
* @return [Boolean]
*/
static VALUE GameController_button_pressed_p(VALUE self, VALUE button)
{
return INT2BOOL(SDL_GameControllerGetButton(Get_SDL_GameController(self),
NUM2INT(button)));
}
/*
* Document-module: SDL2::GameController::Axis
*
* This module provides constants of gamecontroller's axis indices used by
* {SDL2::GameController} class.
*/
/*
* Document-module: SDL2::GameController::Button
*
* This module provides constants of gamecontroller's button indices used by
* {SDL2::GameController} class.
*/
void rubysdl2_init_gamecontorller(void)
{
cGameController = rb_define_class_under(mSDL2, "GameController", rb_cObject);
rb_define_singleton_method(cGameController, "add_mapping",
GameController_s_add_mapping, 1);
rb_define_singleton_method(cGameController, "device_names",
GameController_s_device_names, 0);
rb_define_singleton_method(cGameController, "axis_name_of",
GameController_s_axis_name_of, 1);
rb_define_singleton_method(cGameController, "button_name_of",
GameController_s_button_name_of, 1);
rb_define_singleton_method(cGameController, "mapping_for",
GameController_s_mapping_for, 1);
rb_define_singleton_method(cGameController, "button_from_name",
GameController_s_button_from_name, 1);
rb_define_singleton_method(cGameController, "axis_from_name",
GameController_s_axis_from_name, 1);
rb_define_singleton_method(cGameController, "open", GameController_s_open, 1);
rb_define_method(cGameController, "destroy?", GameController_destroy_p, 0);
rb_define_method(cGameController, "destroy", GameController_destroy, 0);
rb_define_method(cGameController, "name", GameController_name, 0);
rb_define_method(cGameController, "attached?", GameController_attached_p, 0);
rb_define_method(cGameController, "mapping", GameController_mapping, 0);
rb_define_method(cGameController, "axis", GameController_axis, 1);
rb_define_method(cGameController, "button_pressed?", GameController_button_pressed_p, 1);
mAxis = rb_define_module_under(cGameController, "Axis");
mButton = rb_define_module_under(cGameController, "Button");
/* define(`DEFINE_CONTROLLER_AXIS_CONST',`rb_define_const(mAxis, "$1", INT2NUM(SDL_CONTROLLER_AXIS_$1))') */
/* @return [Integer] index for invalid axis*/
DEFINE_CONTROLLER_AXIS_CONST(INVALID);
/* @return [Integer] index for Left X axis */
DEFINE_CONTROLLER_AXIS_CONST(LEFTX);
/* @return [Integer] index for Left Y axis */
DEFINE_CONTROLLER_AXIS_CONST(LEFTY);
/* @return [Integer] index for Right X axis */
DEFINE_CONTROLLER_AXIS_CONST(RIGHTX);
/* @return [Integer] index for Right Y axis */
DEFINE_CONTROLLER_AXIS_CONST(RIGHTY);
/* @return [Integer] index for Left trigger axis */
DEFINE_CONTROLLER_AXIS_CONST(TRIGGERLEFT);
/* @return [Integer] index for Right trigger axis */
DEFINE_CONTROLLER_AXIS_CONST(TRIGGERRIGHT);
/* @return [Integer] the max value of axis indices */
DEFINE_CONTROLLER_AXIS_CONST(MAX);
/* define(`DEFINE_CONTROLLER_BUTTON_CONST',`rb_define_const(mButton, "$1", INT2NUM(SDL_CONTROLLER_BUTTON_$1))') */
/* @return [Integer] index for Invalid button */
DEFINE_CONTROLLER_BUTTON_CONST(INVALID);
/* @return [Integer] index for Button A */
DEFINE_CONTROLLER_BUTTON_CONST(A);
/* @return [Integer] index for Button B */
DEFINE_CONTROLLER_BUTTON_CONST(B);
/* @return [Integer] index for Button X */
DEFINE_CONTROLLER_BUTTON_CONST(X);
/* @return [Integer] index for Button Y */
DEFINE_CONTROLLER_BUTTON_CONST(Y);
/* @return [Integer] index for Back Button */
DEFINE_CONTROLLER_BUTTON_CONST(BACK);
/* @return [Integer] index for Guide Button */
DEFINE_CONTROLLER_BUTTON_CONST(GUIDE);
/* @return [Integer] index for Start Button */
DEFINE_CONTROLLER_BUTTON_CONST(START);
/* @return [Integer] index for Left stick Button */
DEFINE_CONTROLLER_BUTTON_CONST(LEFTSTICK);
/* @return [Integer] index for Right stick Button */
DEFINE_CONTROLLER_BUTTON_CONST(RIGHTSTICK);
/* @return [Integer] index for Left shoulder Button */
DEFINE_CONTROLLER_BUTTON_CONST(LEFTSHOULDER);
/* @return [Integer] index for Right shoulder Button */
DEFINE_CONTROLLER_BUTTON_CONST(RIGHTSHOULDER);
/* @return [Integer] index for D-pad UP Button */
DEFINE_CONTROLLER_BUTTON_CONST(DPAD_UP);
/* @return [Integer] index for D-pad DOWN Button */
DEFINE_CONTROLLER_BUTTON_CONST(DPAD_DOWN);
/* @return [Integer] index for D-pad LEFT Button */
DEFINE_CONTROLLER_BUTTON_CONST(DPAD_LEFT);
/* @return [Integer] index for D-pad RIGHT Button */
DEFINE_CONTROLLER_BUTTON_CONST(DPAD_RIGHT);
/* @return [Integer] The max value of button indices */
DEFINE_CONTROLLER_BUTTON_CONST(MAX);
}