diff --git a/libwacom/libwacom-database.c b/libwacom/libwacom-database.c index e107888a..3e2432c0 100644 --- a/libwacom/libwacom-database.c +++ b/libwacom/libwacom-database.c @@ -440,7 +440,9 @@ static const struct { { "Ring", WACOM_STATUS_LED_RING }, { "Ring2", WACOM_STATUS_LED_RING2 }, { "Touchstrip", WACOM_STATUS_LED_TOUCHSTRIP }, - { "Touchstrip2", WACOM_STATUS_LED_TOUCHSTRIP2 } + { "Touchstrip2", WACOM_STATUS_LED_TOUCHSTRIP2 }, + { "Dial", WACOM_STATUS_LED_DIAL }, + { "Dial2", WACOM_STATUS_LED_DIAL2 }, }; static const struct { diff --git a/libwacom/libwacom.c b/libwacom/libwacom.c index 52755cc6..84d824fb 100644 --- a/libwacom/libwacom.c +++ b/libwacom/libwacom.c @@ -1487,7 +1487,9 @@ static const struct { { WACOM_BUTTON_RING_MODESWITCH, WACOM_STATUS_LED_RING }, { WACOM_BUTTON_RING2_MODESWITCH, WACOM_STATUS_LED_RING2 }, { WACOM_BUTTON_TOUCHSTRIP_MODESWITCH, WACOM_STATUS_LED_TOUCHSTRIP }, - { WACOM_BUTTON_TOUCHSTRIP2_MODESWITCH, WACOM_STATUS_LED_TOUCHSTRIP2 } + { WACOM_BUTTON_TOUCHSTRIP2_MODESWITCH, WACOM_STATUS_LED_TOUCHSTRIP2 }, + { WACOM_BUTTON_DIAL_MODESWITCH, WACOM_STATUS_LED_DIAL }, + { WACOM_BUTTON_DIAL2_MODESWITCH, WACOM_STATUS_LED_DIAL2 }, }; LIBWACOM_EXPORT int diff --git a/libwacom/libwacom.h b/libwacom/libwacom.h index f07ba5f7..01ea968e 100644 --- a/libwacom/libwacom.h +++ b/libwacom/libwacom.h @@ -304,7 +304,9 @@ typedef enum { WACOM_STATUS_LED_RING = 0, WACOM_STATUS_LED_RING2 = 1, WACOM_STATUS_LED_TOUCHSTRIP = 2, - WACOM_STATUS_LED_TOUCHSTRIP2 = 3 + WACOM_STATUS_LED_TOUCHSTRIP2 = 3, + WACOM_STATUS_LED_DIAL = 4, + WACOM_STATUS_LED_DIAL2 = 5, } WacomStatusLEDs; /** diff --git a/test/__init__.py b/test/__init__.py index 43083f10..7d931a87 100644 --- a/test/__init__.py +++ b/test/__init__.py @@ -218,7 +218,7 @@ def instance(cls): _Api( name="libwacom_get_status_leds", args=(c_void_p, c_void_p), - return_type=c_void_p, + return_type=ctypes.POINTER(ctypes.c_int), ), _Api( name="libwacom_get_button_led_group", @@ -394,6 +394,8 @@ def instance(cls): _Enum(name="WACOM_STATUS_LED_RING2", value=2), _Enum(name="WACOM_STATUS_LED_TOUCHSTRIP", value=3), _Enum(name="WACOM_STATUS_LED_TOUCHSTRIP2", value=4), + _Enum(name="WACOM_STATUS_LED_DIAL", value=1), + _Enum(name="WACOM_STATUS_LED_DIAL2", value=2), ] @@ -616,6 +618,16 @@ def get_paired_styli(self) -> List["WacomStylus"]: return styli +class WacomStatusLed(enum.IntEnum): + UNAVAILABLE = -1 + RING = 0 + RING2 = 1 + TOUCHSTRIP = 2 + TOUCHSTRIP2 = 3 + DIAL = 4 + DIAL2 = 5 + + class WacomDevice: """ Convenience wrapper to make using libwacom a bit more pythonic. @@ -795,6 +807,17 @@ def button_flags(self, button: str) -> List[ButtonFlags]: def button_evdev_code(self, button: str) -> int: return self.get_button_evdev_code(button.encode("utf-8")) + def button_led_group(self, button: str) -> List[ButtonFlags]: + return self.get_button_led_group(button.encode("utf-8")) + + @property + def status_leds(self) -> List["WacomStatusLed"]: + nleds = c_int() + leds = self.get_status_leds(ctypes.byref(nleds)) + # leds = ctypes.cast(leds, ctypes.POINTER(ctypes.c_int)) + + return [WacomStatusLed(l) for l in leds[: nleds.value]] + class WacomDatabase: """ diff --git a/test/test_libwacom.py b/test/test_libwacom.py index a8a11db1..04d32f95 100644 --- a/test/test_libwacom.py +++ b/test/test_libwacom.py @@ -8,7 +8,14 @@ import logging import pytest -from . import WacomBuilder, WacomBustype, WacomDatabase, WacomDevice, WacomEraserType +from . import ( + WacomBuilder, + WacomBustype, + WacomDatabase, + WacomDevice, + WacomEraserType, + WacomStatusLed, +) logger = logging.getLogger(__name__) @@ -604,6 +611,76 @@ def test_button_modeswitch(custom_datadir, feature, count): assert expected_flag not in flags +@pytest.mark.parametrize( + "feature", + ("Ring", "Touchstrip", "Dial"), +) +@pytest.mark.parametrize("count", (1, 2)) +def test_status_leds(custom_datadir, feature, count): + USBID = (0x1234, 0x5678) + + # sigh, Touchstrip but StripsNumModes... + num_mode_key = f"{feature}s" if feature != "Touchstrip" else "Strips" + + extra = { + "Buttons": { + "Left": "A;B;C;", + "Right": "D;E;F;", + feature: "A", + }, + "Features": { + "StatusLEDs": f"{feature};{feature}2" if count > 1 else f"{feature}", + num_mode_key: 4, + }, + } + if count > 1: + extra["Buttons"][f"{feature}2"] = "D" + + TabletFile( + name="some tablet", + matches=[f"usb|{USBID[0]:04x}|{USBID[1]:04x}"], + extra=extra, + ).write_to(custom_datadir / "led.tablet") + + db = WacomDatabase(path=custom_datadir) + builder = WacomBuilder.create(usbid=USBID) + device = db.new_from_builder(builder) + assert device is not None + + expected = [ + { + "Ring": WacomStatusLed.RING, + "Touchstrip": WacomStatusLed.TOUCHSTRIP, + "Dial": WacomStatusLed.DIAL, + }[feature] + ] + + if count > 1: + expected.append( + { + "Ring": WacomStatusLed.RING2, + "Touchstrip": WacomStatusLed.TOUCHSTRIP2, + "Dial": WacomStatusLed.DIAL2, + }[feature] + ) + + leds = device.status_leds + assert sorted(leds) == sorted(expected) + + led_group = device.button_led_group("A") + assert led_group == 0 + + led_group = device.button_led_group("D") + if count > 1: + assert led_group == 1 + else: + assert led_group == -1 + + for b in "BCEF": + led_group = device.button_led_group(b) + assert led_group == -1 + + def test_nonwacom_stylus_ids(tmp_path): styli = StylusFile.default() s1 = StylusEntry( diff --git a/tools/debug-device.c b/tools/debug-device.c index 4de74c45..588fd076 100644 --- a/tools/debug-device.c +++ b/tools/debug-device.c @@ -222,6 +222,8 @@ handle_device(WacomDeviceDatabase *db, const char *path) case WACOM_STATUS_LED_RING2: ledstr = "RING2"; break; case WACOM_STATUS_LED_TOUCHSTRIP: ledstr = "TOUCHSTRIP"; break; case WACOM_STATUS_LED_TOUCHSTRIP2: ledstr = "TOUCHSTRIP2"; break; + case WACOM_STATUS_LED_DIAL: ledstr = "DIAL"; break; + case WACOM_STATUS_LED_DIAL2: ledstr = "DIAL2"; break; } snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), "%s%s", i > 0 ? ", " : "", ledstr); }