1 /*
2   pygame - Python Game Library
3   Copyright (C) 2000-2001  Pete Shinners
4 
5   This library is free software; you can redistribute it and/or
6   modify it under the terms of the GNU Library General Public
7   License as published by the Free Software Foundation; either
8   version 2 of the License, or (at your option) any later version.
9 
10   This library is distributed in the hope that it will be useful,
11   but WITHOUT ANY WARRANTY; without even the implied warranty of
12   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13   Library General Public License for more details.
14 
15   You should have received a copy of the GNU Library General Public
16   License along with this library; if not, write to the Free
17   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
18 
19   Pete Shinners
20   pete@shinners.org
21 */
22 
23 #define PYGAMEAPI_JOYSTICK_INTERNAL
24 #include "pygame.h"
25 
26 #include "pgcompat.h"
27 
28 #include "doc/joystick_doc.h"
29 
30 static pgJoystickObject *joylist_head = NULL;
31 static PyObject *joy_instance_map = NULL;
32 static PyTypeObject pgJoystick_Type;
33 static PyObject *pgJoystick_New(int);
34 static int _joy_map_insert(pgJoystickObject *jstick);
35 #define pgJoystick_Check(x) ((x)->ob_type == &pgJoystick_Type)
36 
37 static PyObject *
init(PyObject * self)38 init(PyObject *self)
39 {
40     if (!SDL_WasInit(SDL_INIT_JOYSTICK)) {
41         if (SDL_InitSubSystem(SDL_INIT_JOYSTICK))
42             return RAISE(pgExc_SDLError, SDL_GetError());
43         SDL_JoystickEventState(SDL_ENABLE);
44     }
45     Py_RETURN_NONE;
46 }
47 
48 static PyObject *
quit(PyObject * self)49 quit(PyObject *self)
50 {
51     /* Walk joystick objects to deallocate the stick objects. */
52     pgJoystickObject *cur = joylist_head;
53     while (cur) {
54         if (cur->joy) {
55             SDL_JoystickClose(cur->joy);
56             cur->joy = NULL;
57         }
58         cur = cur->next;
59     }
60 
61     if (SDL_WasInit(SDL_INIT_JOYSTICK)) {
62         SDL_JoystickEventState(SDL_ENABLE);
63         SDL_QuitSubSystem(SDL_INIT_JOYSTICK);
64     }
65     Py_RETURN_NONE;
66 }
67 
68 static PyObject *
get_init(PyObject * self)69 get_init(PyObject *self)
70 {
71     return PyBool_FromLong(SDL_WasInit(SDL_INIT_JOYSTICK) != 0);
72 }
73 
74 /*joystick object funcs*/
75 static void
joy_dealloc(PyObject * self)76 joy_dealloc(PyObject *self)
77 {
78     pgJoystickObject *jstick = (pgJoystickObject *) self;
79 
80     if (jstick->joy) {
81         SDL_JoystickClose(jstick->joy);
82     }
83 
84     if (jstick->prev) {
85         jstick->prev->next = jstick->next;
86     } else {
87         joylist_head = jstick->next;
88     }
89     if (jstick->next) {
90         jstick->next->prev = jstick->prev;
91     }
92 
93     PyObject_DEL(self);
94 }
95 
96 static PyObject *
Joystick(PyObject * self,PyObject * args)97 Joystick(PyObject *self, PyObject *args)
98 {
99     int id;
100     if (!PyArg_ParseTuple(args, "i", &id)) {
101         return NULL;
102     }
103 
104     JOYSTICK_INIT_CHECK();
105 
106     return pgJoystick_New(id);
107 }
108 
109 static PyObject *
get_count(PyObject * self,PyObject * args)110 get_count(PyObject *self, PyObject *args)
111 {
112     JOYSTICK_INIT_CHECK();
113     return PyInt_FromLong(SDL_NumJoysticks());
114 }
115 
116 
117 static PyObject *
joy_init(PyObject * self,PyObject * args)118 joy_init(PyObject *self, PyObject *args)
119 {
120     pgJoystickObject *jstick = (pgJoystickObject *) self;
121 
122     if (!jstick->joy) {
123         jstick->joy = SDL_JoystickOpen(jstick->id);
124         if (!jstick->joy) {
125             return RAISE(pgExc_SDLError, SDL_GetError());
126         }
127     }
128 
129     if (-1 == _joy_map_insert(jstick)) {
130         return NULL;
131     }
132 
133     Py_RETURN_NONE;
134 }
135 
136 static int
_joy_map_insert(pgJoystickObject * jstick)137 _joy_map_insert(pgJoystickObject *jstick) {
138     SDL_JoystickID instance_id;
139     PyObject *k, *v;
140 
141     if (!joy_instance_map) {
142         return -1;
143     }
144 
145     instance_id = SDL_JoystickInstanceID(jstick->joy);
146     if (instance_id < 0) {
147         PyErr_SetString(pgExc_SDLError, SDL_GetError());
148         return -1;
149     }
150     k = PyInt_FromLong(instance_id);
151     v = PyInt_FromLong(jstick->id);
152     if (k && v) {
153         PyDict_SetItem(joy_instance_map, k, v);
154     }
155     Py_XDECREF(k);
156     Py_XDECREF(v);
157 
158     return 0;
159 }
160 
161 static PyObject *
joy_quit(PyObject * self,PyObject * args)162 joy_quit(PyObject *self, PyObject *args)
163 {
164     pgJoystickObject *joy = (pgJoystickObject *) self;
165 
166     JOYSTICK_INIT_CHECK();
167     if (joy->joy) {
168         SDL_JoystickClose(joy->joy);
169         joy->joy = NULL;
170     }
171     Py_RETURN_NONE;
172 }
173 
174 static PyObject *
joy_get_init(PyObject * self,PyObject * args)175 joy_get_init(PyObject *self, PyObject *args)
176 {
177     SDL_Joystick *joy = pgJoystick_AsSDL(self);
178     return PyBool_FromLong(joy != NULL);
179 }
180 
181 static PyObject *
joy_get_id(PyObject * self,PyObject * args)182 joy_get_id(PyObject *self, PyObject *args)
183 {
184     int joy_id = pgJoystick_AsID(self);
185     return PyInt_FromLong(joy_id);
186 }
187 
188 
189 static PyObject *
joy_get_instance_id(PyObject * self,PyObject * args)190 joy_get_instance_id(PyObject *self, PyObject *args)
191 {
192     SDL_Joystick *joy = pgJoystick_AsSDL(self);
193 
194     JOYSTICK_INIT_CHECK();
195     if (!joy) {
196         return RAISE(pgExc_SDLError, "Joystick not initialized");
197     }
198 
199     return PyInt_FromLong(SDL_JoystickInstanceID(joy));
200 }
201 
202 
203 static PyObject *
joy_get_guid(PyObject * self,PyObject * args)204 joy_get_guid(PyObject *self, PyObject *args)
205 {
206     SDL_Joystick *joy = pgJoystick_AsSDL(self);
207     SDL_JoystickGUID guid;
208     char strguid[33];
209 
210     JOYSTICK_INIT_CHECK();
211     if (joy) {
212         guid = SDL_JoystickGetGUID(joy);
213     } else {
214         guid = SDL_JoystickGetDeviceGUID(pgJoystick_AsID(self));
215     }
216 
217     SDL_JoystickGetGUIDString(guid, strguid, 33);
218 
219     return Text_FromUTF8(strguid);
220 }
221 
222 
_pg_powerlevel_string(SDL_JoystickPowerLevel level)223 const char *_pg_powerlevel_string(SDL_JoystickPowerLevel level) {
224     switch (level) {
225         case SDL_JOYSTICK_POWER_EMPTY:
226             return "empty";
227         case SDL_JOYSTICK_POWER_LOW:
228             return "low";
229         case SDL_JOYSTICK_POWER_MEDIUM:
230             return "medium";
231         case SDL_JOYSTICK_POWER_FULL:
232             return "full";
233         case SDL_JOYSTICK_POWER_WIRED:
234             return "wired";
235         case SDL_JOYSTICK_POWER_MAX:
236             return "max";
237         default:
238             return "unknown";
239     }
240 }
241 
242 
243 static PyObject *
joy_get_power_level(PyObject * self,PyObject * args)244 joy_get_power_level(PyObject *self, PyObject *args)
245 {
246     SDL_JoystickPowerLevel level;
247     const char *leveltext;
248     SDL_Joystick *joy = pgJoystick_AsSDL(self);
249 
250     JOYSTICK_INIT_CHECK();
251     if (!joy) {
252         return RAISE(pgExc_SDLError, "Joystick not initialized");
253     }
254 
255     level = SDL_JoystickCurrentPowerLevel(joy);
256     leveltext = _pg_powerlevel_string(level);
257 
258     return Text_FromUTF8(leveltext);
259 }
260 
261 static PyObject *
joy_rumble(pgJoystickObject * self,PyObject * args,PyObject * kwargs)262 joy_rumble(pgJoystickObject *self, PyObject *args, PyObject *kwargs)
263 {
264 #if SDL_VERSION_ATLEAST(2, 0, 9)
265 
266     SDL_Joystick *joy = self->joy;
267     float low;
268     float high;
269     uint32_t duration;
270     int res;
271 
272     char *keywords[] = {
273         "low_frequency",
274         "high_frequency",
275         "duration",
276         NULL,
277     };
278 
279     if (!PyArg_ParseTupleAndKeywords(args, kwargs, "ffI", keywords, &low,
280                                      &high, &duration)) {
281         return NULL;
282     }
283 
284     JOYSTICK_INIT_CHECK();
285     if (!joy) {
286         return RAISE(pgExc_SDLError, "Joystick not initialized");
287     }
288 
289     if (low < 0) {
290         low = 0.f;
291     }
292     else if (low > 1.f) {
293         low = 1.f;
294     }
295 
296     if (high < 0) {
297         high = 0.f;
298     }
299     else if (high > 1.f) {
300         high = 1.f;
301     }
302     low *= 0xFFFF;
303     high *= 0xFFFF;
304 
305     res = SDL_JoystickRumble(joy, low, high, duration);
306     if (res == -1) {
307         Py_RETURN_FALSE;
308     }
309     Py_RETURN_TRUE;
310 
311 #else
312     Py_RETURN_FALSE;
313 #endif
314 }
315 
316 static PyObject *
joy_stop_rumble(pgJoystickObject * self)317 joy_stop_rumble(pgJoystickObject *self)
318 {
319 #if SDL_VERSION_ATLEAST(2, 0, 9)
320     SDL_Joystick *joy = self->joy;
321     SDL_JoystickRumble(joy, 0, 0, 1);
322 #endif
323     Py_RETURN_NONE;
324 }
325 
326 
327 static PyObject *
joy_get_name(PyObject * self,PyObject * args)328 joy_get_name(PyObject *self, PyObject *args)
329 {
330     SDL_Joystick *joy = pgJoystick_AsSDL(self);
331     return Text_FromUTF8(SDL_JoystickName(joy));
332 }
333 
334 static PyObject *
joy_get_numaxes(PyObject * self,PyObject * args)335 joy_get_numaxes(PyObject *self, PyObject *args)
336 {
337     SDL_Joystick *joy = pgJoystick_AsSDL(self);
338     JOYSTICK_INIT_CHECK();
339     if (!joy) {
340         return RAISE(pgExc_SDLError, "Joystick not initialized");
341     }
342 
343     return PyInt_FromLong(SDL_JoystickNumAxes(joy));
344 }
345 
346 static PyObject *
joy_get_axis(PyObject * self,PyObject * args)347 joy_get_axis(PyObject *self, PyObject *args)
348 {
349     SDL_Joystick *joy = pgJoystick_AsSDL(self);
350     int axis, value;
351 
352     if (!PyArg_ParseTuple(args, "i", &axis)) {
353         return NULL;
354     }
355 
356     JOYSTICK_INIT_CHECK();
357     if (!joy) {
358         return RAISE(pgExc_SDLError, "Joystick not initialized");
359     }
360     if (axis < 0 || axis >= SDL_JoystickNumAxes(joy)) {
361         return RAISE(pgExc_SDLError, "Invalid joystick axis");
362     }
363 
364     value = SDL_JoystickGetAxis(joy, axis);
365 #ifdef DEBUG
366     /*printf("SDL_JoystickGetAxis value:%d:\n", value);*/
367 #endif
368 
369     return PyFloat_FromDouble(value / 32768.0);
370 }
371 
372 static PyObject *
joy_get_numbuttons(PyObject * self,PyObject * args)373 joy_get_numbuttons(PyObject *self, PyObject *args)
374 {
375     SDL_Joystick *joy = pgJoystick_AsSDL(self);
376 
377     JOYSTICK_INIT_CHECK();
378     if (!joy) {
379         return RAISE(pgExc_SDLError, "Joystick not initialized");
380     }
381 
382     return PyInt_FromLong(SDL_JoystickNumButtons(joy));
383 }
384 
385 static PyObject *
joy_get_button(PyObject * self,PyObject * args)386 joy_get_button(PyObject *self, PyObject *args)
387 {
388     SDL_Joystick *joy = pgJoystick_AsSDL(self);
389     int _index, value;
390 
391     if (!PyArg_ParseTuple(args, "i", &_index)) {
392         return NULL;
393     }
394 
395     JOYSTICK_INIT_CHECK();
396     if (!joy) {
397         return RAISE(pgExc_SDLError, "Joystick not initialized");
398     }
399     if (_index < 0 || _index >= SDL_JoystickNumButtons(joy)) {
400         return RAISE(pgExc_SDLError, "Invalid joystick button");
401     }
402 
403     value = SDL_JoystickGetButton(joy, _index);
404 #ifdef DEBUG
405     /*printf("SDL_JoystickGetButton value:%d:\n", value);*/
406 #endif
407     return PyInt_FromLong(value);
408 }
409 
410 static PyObject *
joy_get_numballs(PyObject * self,PyObject * args)411 joy_get_numballs(PyObject *self, PyObject *args)
412 {
413     SDL_Joystick *joy = pgJoystick_AsSDL(self);
414 
415     JOYSTICK_INIT_CHECK();
416     if (!joy) {
417         return RAISE(pgExc_SDLError, "Joystick not initialized");
418     }
419 
420     return PyInt_FromLong(SDL_JoystickNumBalls(joy));
421 }
422 
423 static PyObject *
joy_get_ball(PyObject * self,PyObject * args)424 joy_get_ball(PyObject *self, PyObject *args)
425 {
426     SDL_Joystick *joy = pgJoystick_AsSDL(self);
427     int _index, dx, dy;
428     int value;
429 
430     if (!PyArg_ParseTuple(args, "i", &_index)) {
431         return NULL;
432     }
433 
434     JOYSTICK_INIT_CHECK();
435     if (!joy) {
436         return RAISE(pgExc_SDLError, "Joystick not initialized");
437     }
438     value = SDL_JoystickNumBalls(joy);
439 #ifdef DEBUG
440     /*printf("SDL_JoystickNumBalls value:%d:\n", value);*/
441 #endif
442     if (_index < 0 || _index >= value) {
443         return RAISE(pgExc_SDLError, "Invalid joystick trackball");
444     }
445 
446     SDL_JoystickGetBall(joy, _index, &dx, &dy);
447     return Py_BuildValue("(ii)", dx, dy);
448 }
449 
450 static PyObject *
joy_get_numhats(PyObject * self,PyObject * args)451 joy_get_numhats(PyObject *self, PyObject *args)
452 {
453     Uint32 value;
454     SDL_Joystick *joy = pgJoystick_AsSDL(self);
455 
456     JOYSTICK_INIT_CHECK();
457     if (!joy) {
458         return RAISE(pgExc_SDLError, "Joystick not initialized");
459     }
460 
461     value = SDL_JoystickNumHats(joy);
462 #ifdef DEBUG
463     /*printf("SDL_JoystickNumHats value:%d:\n", value);*/
464 #endif
465     return PyInt_FromLong(value);
466 }
467 
468 static PyObject *
joy_get_hat(PyObject * self,PyObject * args)469 joy_get_hat(PyObject *self, PyObject *args)
470 {
471     SDL_Joystick *joy = pgJoystick_AsSDL(self);
472     int _index, px, py;
473     Uint32 value;
474 
475     if (!PyArg_ParseTuple(args, "i", &_index)) {
476         return NULL;
477     }
478 
479     JOYSTICK_INIT_CHECK();
480     if (!joy) {
481         return RAISE(pgExc_SDLError, "Joystick not initialized");
482     }
483     if (_index < 0 || _index >= SDL_JoystickNumHats(joy)) {
484         return RAISE(pgExc_SDLError, "Invalid joystick hat");
485     }
486 
487     px = py = 0;
488     value = SDL_JoystickGetHat(joy, _index);
489 #ifdef DEBUG
490     /*printf("SDL_JoystickGetHat value:%d:\n", value);*/
491 #endif
492     if (value & SDL_HAT_UP) {
493         py = 1;
494     }
495     else if (value & SDL_HAT_DOWN) {
496         py = -1;
497     }
498     if (value & SDL_HAT_RIGHT) {
499         px = 1;
500     }
501     else if (value & SDL_HAT_LEFT) {
502         px = -1;
503     }
504 
505     return Py_BuildValue("(ii)", px, py);
506 }
507 
508 static PyMethodDef joy_methods[] = {
509     {"init", joy_init, METH_NOARGS, DOC_JOYSTICKINIT},
510     {"quit", joy_quit, METH_NOARGS, DOC_JOYSTICKQUIT},
511     {"get_init", joy_get_init, METH_NOARGS, DOC_JOYSTICKGETINIT},
512 
513     {"get_id", joy_get_id, METH_NOARGS, DOC_JOYSTICKGETID},
514     {"get_instance_id", joy_get_instance_id, METH_NOARGS, DOC_JOYSTICKGETINSTANCEID},
515     {"get_guid", joy_get_guid, METH_NOARGS, DOC_JOYSTICKGETGUID},
516     {"get_power_level", joy_get_power_level, METH_NOARGS, DOC_JOYSTICKGETPOWERLEVEL},
517     {"rumble", (PyCFunction)joy_rumble, METH_VARARGS | METH_KEYWORDS, DOC_JOYSTICKRUMBLE},
518     {"stop_rumble", (PyCFunction)joy_stop_rumble, METH_NOARGS, DOC_JOYSTICKSTOPRUMBLE},
519     {"get_name", joy_get_name, METH_NOARGS, DOC_JOYSTICKGETNAME},
520 
521     {"get_numaxes", joy_get_numaxes, METH_NOARGS,
522      DOC_JOYSTICKGETNUMAXES},
523     {"get_axis", joy_get_axis, METH_VARARGS, DOC_JOYSTICKGETAXIS},
524     {"get_numbuttons", joy_get_numbuttons, METH_NOARGS,
525      DOC_JOYSTICKGETNUMBUTTONS},
526     {"get_button", joy_get_button, METH_VARARGS, DOC_JOYSTICKGETBUTTON},
527     {"get_numballs", joy_get_numballs, METH_NOARGS,
528      DOC_JOYSTICKGETNUMBALLS},
529     {"get_ball", joy_get_ball, METH_VARARGS, DOC_JOYSTICKGETBALL},
530     {"get_numhats", joy_get_numhats, METH_NOARGS,
531      DOC_JOYSTICKGETNUMHATS},
532     {"get_hat", joy_get_hat, METH_VARARGS, DOC_JOYSTICKGETHAT},
533 
534     {NULL, NULL, 0, NULL}};
535 
536 static PyTypeObject pgJoystick_Type = {
537     PyVarObject_HEAD_INIT(NULL,0)
538     "Joystick",                    /* name */
539     sizeof(pgJoystickObject),      /* basic size */
540     0,                             /* itemsize */
541     joy_dealloc,                   /* dealloc */
542     0,                             /* print */
543     0,                             /* getattr */
544     0,                             /* setattr */
545     0,                             /* compare */
546     0,                             /* repr */
547     0,                             /* as_number */
548     0,                             /* as_sequence */
549     0,                             /* as_mapping */
550     0,                             /* hash */
551     0,                             /* call */
552     0,                             /* str */
553     0,                             /* tp_getattro */
554     0,                             /* tp_setattro */
555     0,                             /* tp_as_buffer */
556     0,                             /* flags */
557     DOC_PYGAMEJOYSTICKJOYSTICK,    /* Documentation string */
558     0,                             /* tp_traverse */
559     0,                             /* tp_clear */
560     0,                             /* tp_richcompare */
561     0,                             /* tp_weaklistoffset */
562     0,                             /* tp_iter */
563     0,                             /* tp_iternext */
564     joy_methods,                   /* tp_methods */
565     0,                             /* tp_members */
566     0,                             /* tp_getset */
567     0,                             /* tp_base */
568     0,                             /* tp_dict */
569     0,                             /* tp_descr_get */
570     0,                             /* tp_descr_set */
571     0,                             /* tp_dictoffset */
572     0,                             /* tp_init */
573     0,                             /* tp_alloc */
574     0,                             /* tp_new */
575 };
576 
577 static PyObject *
pgJoystick_New(int id)578 pgJoystick_New(int id)
579 {
580     pgJoystickObject *jstick, *cur;
581     SDL_Joystick *joy;
582 
583     JOYSTICK_INIT_CHECK();
584 
585     /* Open the SDL device */
586     if (id >= SDL_NumJoysticks()) {
587         return RAISE(pgExc_SDLError, "Invalid joystick device number");
588     }
589     joy = SDL_JoystickOpen(id);
590     if (!joy) {
591         return RAISE(pgExc_SDLError, SDL_GetError());
592     }
593 
594     /* Search existing joystick objects to see if we already have this stick. */
595     cur = joylist_head;
596     while (cur) {
597         if (cur->joy == joy) {
598             Py_INCREF(cur);
599             return (PyObject *) cur;
600         }
601         cur = cur->next;
602     }
603 
604     /* Construct the Python object */
605     jstick = PyObject_NEW(pgJoystickObject, &pgJoystick_Type);
606     if (!jstick) {
607         return NULL;
608     }
609     jstick->id = id;
610     jstick->joy = joy;
611     jstick->prev = NULL;
612     jstick->next = joylist_head;
613     if (joylist_head) {
614         joylist_head->prev = jstick;
615     }
616     joylist_head = jstick;
617 
618     if (-1 == _joy_map_insert(jstick)) {
619         Py_DECREF(jstick);
620         return NULL;
621     }
622 
623     return (PyObject *)jstick;
624 }
625 
626 static PyMethodDef _joystick_methods[] = {
627     {"init", (PyCFunction)init, METH_NOARGS, DOC_PYGAMEJOYSTICKINIT},
628     {"quit", (PyCFunction)quit, METH_NOARGS, DOC_PYGAMEJOYSTICKQUIT},
629     {"get_init", (PyCFunction)get_init, METH_NOARGS,
630      DOC_PYGAMEJOYSTICKGETINIT},
631     {"get_count", (PyCFunction)get_count, METH_NOARGS,
632      DOC_PYGAMEJOYSTICKGETCOUNT},
633     {"Joystick", Joystick, METH_VARARGS, DOC_PYGAMEJOYSTICKJOYSTICK},
634     {NULL, NULL, 0, NULL}};
635 
MODINIT_DEFINE(joystick)636 MODINIT_DEFINE(joystick)
637 {
638     PyObject *module, *dict, *apiobj;
639     int ecode;
640     static void *c_api[PYGAMEAPI_JOYSTICK_NUMSLOTS];
641 
642     static struct PyModuleDef _module = {PyModuleDef_HEAD_INIT,
643                                          "joystick",
644                                          DOC_PYGAMEJOYSTICK,
645                                          -1,
646                                          _joystick_methods,
647                                          NULL,
648                                          NULL,
649                                          NULL,
650                                          NULL};
651 
652     /* imported needed apis; Do this first so if there is an error
653        the module is not loaded.
654     */
655     import_pygame_base();
656     if (PyErr_Occurred()) {
657         MODINIT_ERROR;
658     }
659 
660     /* type preparation */
661     if (PyType_Ready(&pgJoystick_Type) == -1) {
662         MODINIT_ERROR;
663     }
664 
665     /* Grab the instance -> device id mapping */
666     module = PyImport_ImportModule("pygame.event");
667     if (!module) {
668         MODINIT_ERROR;
669     }
670     joy_instance_map = PyObject_GetAttrString(module, "_joy_instance_map");
671     Py_DECREF(module);
672 
673     /* create the module */
674     module = PyModule_Create(&_module);
675     if (module == NULL) {
676         MODINIT_ERROR;
677     }
678     dict = PyModule_GetDict(module);
679 
680     if (PyDict_SetItemString(dict, "JoystickType",
681                              (PyObject *)&pgJoystick_Type) == -1) {
682         DECREF_MOD(module);
683         MODINIT_ERROR;
684     }
685 
686     /* export the c api */
687     c_api[0] = &pgJoystick_Type;
688     c_api[1] = pgJoystick_New;
689     apiobj = encapsulate_api(c_api, "joystick");
690     if (apiobj == NULL) {
691         DECREF_MOD(module);
692         MODINIT_ERROR;
693     }
694     ecode = PyDict_SetItemString(dict, PYGAMEAPI_LOCAL_ENTRY, apiobj);
695     Py_DECREF(apiobj);
696     if (ecode == -1) {
697         DECREF_MOD(module);
698         MODINIT_ERROR;
699     }
700     MODINIT_RETURN(module);
701 }
702