Skip to content

Commit 7896a55

Browse files
authored
Merge pull request #3507 from oddbookworm/SDL_JoystickSetLED
Added set_led method for Joystick and Controller objects
2 parents 89b4af6 + 026ed2e commit 7896a55

File tree

8 files changed

+113
-0
lines changed

8 files changed

+113
-0
lines changed

buildconfig/stubs/pygame/_sdl2/controller.pyi

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
from typing import final
22

33
from pygame.joystick import JoystickType
4+
from pygame.typing import ColorLike
45

56
def init() -> None: ...
67
def get_init() -> bool: ...
@@ -30,3 +31,4 @@ class Controller:
3031
self, low_frequency: float, high_frequency: float, duration: int
3132
) -> bool: ...
3233
def stop_rumble(self) -> None: ...
34+
def set_led(self, color: ColorLike) -> bool: ...

buildconfig/stubs/pygame/joystick.pyi

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
from typing import final
22

3+
from pygame.typing import ColorLike
34
from typing_extensions import deprecated # added in 3.13
45

56
def init() -> None: ...
@@ -31,6 +32,7 @@ class JoystickType:
3132
self, low_frequency: float, high_frequency: float, duration: int
3233
) -> bool: ...
3334
def stop_rumble(self) -> None: ...
35+
def set_led(self, color: ColorLike) -> bool: ...
3436

3537
# according to the current implementation, Joystick is a function that returns
3638
# a JoystickType instance. In the future, when the C implementation is fixed to

docs/reST/ref/joystick.rst

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -356,6 +356,22 @@ variable. See :ref:`environment variables <environment-variables>` for more deta
356356

357357
.. ## Joystick.stop_rumble ##
358358
359+
.. method:: set_led
360+
361+
| :sl:`Set the LED color of the joystick`
362+
| :sg:`set_led(color_arg) -> bool`
363+
364+
Set the color of the LED on the joystick. The argument is a
365+
``pygame.Color``-compatible value (alpha being ignored). The
366+
joystick's LED, if it has one, will be set to the input color.
367+
If the joystick does not have an addressable LED, then this
368+
method will do nothing and return False. Returns True if the
369+
LED was set successfully.
370+
371+
.. versionadded:: 2.5.6
372+
373+
.. ## Joystick.set_led ##
374+
359375
.. ## pygame.joystick.Joystick ##
360376
361377
.. ## pygame.joystick ##

docs/reST/ref/sdl2_controller.rst

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -288,4 +288,20 @@ events related to controllers.
288288

289289
.. ## Controller.stop_rumble ##
290290
291+
.. method:: set_led
292+
293+
| :sl:`Set the LED color of the controller`
294+
| :sg:`set_led(color_arg) -> bool`
295+
296+
Set the color of the LED on the controller. The argument is a
297+
``pygame.Color``-compatible value (alpha being ignored). The
298+
controller's LED, if it has one, will be set to the input color.
299+
If the controller does not have an addressable LED, then this
300+
method will do nothing and return False. Returns True if the
301+
LED was set successfully.
302+
303+
.. versionadded:: 2.5.6
304+
305+
.. ## Controller.set_led ##
306+
291307
.. ## pygame._sdl2.controller ##

src_c/_sdl2/controller.c

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -388,6 +388,35 @@ controller_stop_rumble(pgControllerObject *self, PyObject *_null)
388388
Py_RETURN_NONE;
389389
}
390390

391+
static PyObject*
392+
controller_set_led(pgControllerObject *self, PyObject *arg)
393+
{
394+
CONTROLLER_INIT_CHECK();
395+
396+
Uint8 colors[4] = {0, 0, 0, 0};
397+
398+
if (!pg_RGBAFromObjEx(arg, colors, PG_COLOR_HANDLE_ALL)) {
399+
// Exception already set
400+
return NULL;
401+
}
402+
403+
#if !SDL_VERSION_ATLEAST(3, 0, 0)
404+
if (SDL_GameControllerSetLED(self->controller, colors[0], colors[1], colors[2]) < 0) {
405+
Py_RETURN_FALSE;
406+
}
407+
Py_RETURN_TRUE;
408+
#else
409+
// SDL3 renames the function and sets an error message on failure
410+
bool result = SDL_SetGamepadLED(self->controller, colors[0], colors[1], colors[2]);
411+
if (!result) {
412+
// Clear the SDL error message that SDL set, for example if it didn't
413+
// have an addressable LED
414+
(void)SDL_GetError();
415+
}
416+
return PyBool_FromLong(result);
417+
#endif
418+
}
419+
391420
static PyMethodDef controller_methods[] = {
392421
{"from_joystick", (PyCFunction)controller_from_joystick,
393422
METH_CLASS | METH_VARARGS | METH_KEYWORDS,
@@ -414,6 +443,7 @@ static PyMethodDef controller_methods[] = {
414443
DOC_SDL2_CONTROLLER_CONTROLLER_RUMBLE},
415444
{"stop_rumble", (PyCFunction)controller_stop_rumble, METH_NOARGS,
416445
DOC_SDL2_CONTROLLER_CONTROLLER_STOPRUMBLE},
446+
{"set_led", (PyCFunction)controller_set_led, METH_O, DOC_SDL2_CONTROLLER_CONTROLLER_SETLED},
417447
{NULL, NULL, 0, NULL}};
418448

419449
static PyMemberDef controller_members[] = {
@@ -569,6 +599,11 @@ MODINIT_DEFINE(controller)
569599
return NULL;
570600
}
571601

602+
import_pygame_color();
603+
if (PyErr_Occurred()) {
604+
return NULL;
605+
}
606+
572607
import_pygame_joystick();
573608
if (PyErr_Occurred()) {
574609
return NULL;

src_c/doc/joystick_doc.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,3 +23,4 @@
2323
#define DOC_JOYSTICK_JOYSTICK_GETHAT "get_hat(hat_number, /) -> x, y\nget the position of a joystick hat"
2424
#define DOC_JOYSTICK_JOYSTICK_RUMBLE "rumble(low_frequency, high_frequency, duration) -> bool\nStart a rumbling effect"
2525
#define DOC_JOYSTICK_JOYSTICK_STOPRUMBLE "stop_rumble() -> None\nStop any rumble effect playing"
26+
#define DOC_JOYSTICK_JOYSTICK_SETLED "set_led(color_arg) -> bool\nSet the LED color of the joystick"

src_c/doc/sdl2_controller_doc.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,3 +21,4 @@
2121
#define DOC_SDL2_CONTROLLER_CONTROLLER_SETMAPPING "set_mapping(mapping) -> int\nAssign a mapping to the controller"
2222
#define DOC_SDL2_CONTROLLER_CONTROLLER_RUMBLE "rumble(low_frequency, high_frequency, duration) -> bool\nStart a rumbling effect"
2323
#define DOC_SDL2_CONTROLLER_CONTROLLER_STOPRUMBLE "stop_rumble() -> None\nStop any rumble effect playing"
24+
#define DOC_SDL2_CONTROLLER_CONTROLLER_SETLED "set_led(color_arg) -> bool\nSet the LED color of the controller"

src_c/joystick.c

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -531,6 +531,40 @@ joy_get_hat(PyObject *self, PyObject *args)
531531
return pg_tuple_couple_from_values_int(px, py);
532532
}
533533

534+
static PyObject *
535+
joy_set_led(PyObject *self, PyObject *arg)
536+
{
537+
SDL_Joystick *joy = pgJoystick_AsSDL(self);
538+
539+
JOYSTICK_INIT_CHECK();
540+
if (!joy) {
541+
return RAISE(pgExc_SDLError, "Joystick not initialized");
542+
}
543+
544+
Uint8 colors[4] = {0, 0, 0, 0};
545+
546+
if (!pg_RGBAFromObjEx(arg, colors, PG_COLOR_HANDLE_ALL)) {
547+
// Exception already set
548+
return NULL;
549+
}
550+
551+
#if !SDL_VERSION_ATLEAST(3, 0, 0)
552+
if (SDL_JoystickSetLED(joy, colors[0], colors[1], colors[2]) < 0) {
553+
Py_RETURN_FALSE;
554+
}
555+
Py_RETURN_TRUE;
556+
#else
557+
// SDL3 renames the function and sets an error message on failure
558+
bool result = SDL_SetJoystickLED(joy, colors[0], colors[1], colors[2]);
559+
if (!result) {
560+
// Clear the SDL error message that SDL set, for example if it didn't
561+
// have an addressable LED
562+
(void)SDL_GetError();
563+
}
564+
return PyBool_FromLong(result);
565+
#endif
566+
}
567+
534568
static PyMethodDef joy_methods[] = {
535569
{"init", joy_init, METH_NOARGS, DOC_JOYSTICK_JOYSTICK_INIT},
536570
{"quit", joy_quit, METH_NOARGS, DOC_JOYSTICK_JOYSTICK_QUIT},
@@ -560,6 +594,7 @@ static PyMethodDef joy_methods[] = {
560594
{"get_numhats", joy_get_numhats, METH_NOARGS,
561595
DOC_JOYSTICK_JOYSTICK_GETNUMHATS},
562596
{"get_hat", joy_get_hat, METH_VARARGS, DOC_JOYSTICK_JOYSTICK_GETHAT},
597+
{"set_led", joy_set_led, METH_O, DOC_JOYSTICK_JOYSTICK_SETLED},
563598

564599
{NULL, NULL, 0, NULL}};
565600

@@ -665,6 +700,11 @@ MODINIT_DEFINE(joystick)
665700
return NULL;
666701
}
667702

703+
import_pygame_color();
704+
if (PyErr_Occurred()) {
705+
return NULL;
706+
}
707+
668708
/* type preparation */
669709
if (PyType_Ready(&pgJoystick_Type) == -1) {
670710
return NULL;

0 commit comments

Comments
 (0)