Skip to content

Commit

Permalink
Add support for relative dials (#665)
Browse files Browse the repository at this point in the history
We already have a number of tablets with a relative dial that sends
mouse wheel events (UCLOGIC/Huion/XP Pen devices, primarily) so let's
add support for these in our description files.

This is copy/paste from the touch strip and ring support.
  • Loading branch information
whot authored May 2, 2024
1 parent 5b3a3a8 commit b6b82e4
Show file tree
Hide file tree
Showing 10 changed files with 186 additions and 6 deletions.
15 changes: 14 additions & 1 deletion data/wacom.example
Original file line number Diff line number Diff line change
Expand Up @@ -167,10 +167,14 @@ TouchSwitch=false

# This tablet has one or more touch rings (Intuos4 and Cintiq 24HD)
# A touch ring is a circular button that responds to touch
# (rather than clicks):
# (rather than clicks) and sends absolute events:
# http://intuos.wacom.com/americas/touch-ring.php
NumRings=1

# This tablet's number of dials/rotary toggles that send relative events
# similar to a mouse wheel.
NumDials=1

# This tablet's number of touch strips (e.g. Cintiq 22HD), default is zero
NumStrips=1

Expand Down Expand Up @@ -220,6 +224,15 @@ Touchstrip2=J
# if there is more than one
StripsNumModes=4

# If the dials have mode toggling through a button
Dial=A
# The number of modes we can toggle through.
DialNumModes=4
# Buttons associated with the second dial, if any.
Dial2=B
# Number of modes on the second dial, if any
Dial2NumModes=4


# Metadata about the keys on the tablet
[Keys]
Expand Down
8 changes: 7 additions & 1 deletion libwacom/libwacom-database.c
Original file line number Diff line number Diff line change
Expand Up @@ -408,7 +408,9 @@ static const struct {
{ "Ring2", WACOM_BUTTON_RING2_MODESWITCH },
{ "Touchstrip", WACOM_BUTTON_TOUCHSTRIP_MODESWITCH },
{ "Touchstrip2", WACOM_BUTTON_TOUCHSTRIP2_MODESWITCH },
{ "OLEDs", WACOM_BUTTON_OLED }
{ "OLEDs", WACOM_BUTTON_OLED },
{ "Dial", WACOM_BUTTON_DIAL_MODESWITCH },
{ "Dial2", WACOM_BUTTON_DIAL2_MODESWITCH },
};

static const struct {
Expand Down Expand Up @@ -671,6 +673,8 @@ libwacom_parse_buttons(WacomDevice *device,
device->ring_num_modes = libwacom_parse_num_modes(device, keyfile, "RingNumModes", WACOM_BUTTON_RING_MODESWITCH);
device->ring2_num_modes = libwacom_parse_num_modes(device, keyfile, "Ring2NumModes", WACOM_BUTTON_RING2_MODESWITCH);
device->strips_num_modes = libwacom_parse_num_modes(device, keyfile, "StripsNumModes", WACOM_BUTTON_TOUCHSTRIP_MODESWITCH);
device->dial_num_modes = libwacom_parse_num_modes(device, keyfile, "DialNumModes", WACOM_BUTTON_DIAL_MODESWITCH);
device->dial2_num_modes = libwacom_parse_num_modes(device, keyfile, "Dial2NumModes", WACOM_BUTTON_DIAL2_MODESWITCH);
}

static void
Expand Down Expand Up @@ -771,6 +775,7 @@ libwacom_parse_features(WacomDevice *device, GKeyFile *keyfile)

device->num_rings = g_key_file_get_integer(keyfile, FEATURES_GROUP, "NumRings", NULL);
device->num_strips = g_key_file_get_integer(keyfile, FEATURES_GROUP, "NumStrips", NULL);
device->num_dials = g_key_file_get_integer(keyfile, FEATURES_GROUP, "NumDials", NULL);

string_list = g_key_file_get_string_list(keyfile, FEATURES_GROUP, "StatusLEDs", NULL, NULL);
if (string_list) {
Expand Down Expand Up @@ -907,6 +912,7 @@ libwacom_parse_tablet_keyfile(WacomDeviceDatabase *db,
}

device->num_strips = g_key_file_get_integer(keyfile, FEATURES_GROUP, "NumStrips", NULL);
device->num_dials = g_key_file_get_integer(keyfile, FEATURES_GROUP, "NumDials", NULL);
device->buttons = g_hash_table_new_full(g_direct_hash, g_direct_equal,
NULL, g_free);
device->status_leds = g_array_new (FALSE, FALSE, sizeof(WacomStatusLEDs));
Expand Down
38 changes: 38 additions & 0 deletions libwacom/libwacom.c
Original file line number Diff line number Diff line change
Expand Up @@ -404,8 +404,11 @@ libwacom_copy(const WacomDevice *device)
d->cls = device->cls;
d->num_strips = device->num_strips;
d->num_rings = device->num_rings;
d->num_dials = device->num_dials;
d->features = device->features;
d->strips_num_modes = device->strips_num_modes;
d->dial_num_modes = device->dial_num_modes;
d->dial2_num_modes = device->dial2_num_modes;
d->ring_num_modes = device->ring_num_modes;
d->ring2_num_modes = device->ring2_num_modes;
d->styli = g_array_sized_new(FALSE, FALSE, sizeof(int),
Expand Down Expand Up @@ -522,12 +525,21 @@ libwacom_compare(const WacomDevice *a, const WacomDevice *b, WacomCompareFlags f
if (a->num_strips != b->num_strips)
return 1;

if (a->num_dials != b->num_dials)
return 1;

if (a->features != b->features)
return 1;

if (a->strips_num_modes != b->strips_num_modes)
return 1;

if (a->dial_num_modes != b->dial_num_modes)
return 1;

if (a->dial2_num_modes != b->dial2_num_modes)
return 1;

if (a->ring_num_modes != b->ring_num_modes)
return 1;

Expand Down Expand Up @@ -843,13 +855,18 @@ static void print_buttons_for_device (int fd, const WacomDevice *device)
print_button_flag_if(fd, device, "Bottom", WACOM_BUTTON_POSITION_BOTTOM);
print_button_flag_if(fd, device, "Touchstrip", WACOM_BUTTON_TOUCHSTRIP_MODESWITCH);
print_button_flag_if(fd, device, "Touchstrip2", WACOM_BUTTON_TOUCHSTRIP2_MODESWITCH);
print_button_flag_if(fd, device, "Dial", WACOM_BUTTON_DIAL_MODESWITCH);
print_button_flag_if(fd, device, "OLEDs", WACOM_BUTTON_OLED);
print_button_flag_if(fd, device, "Ring", WACOM_BUTTON_RING_MODESWITCH);
print_button_flag_if(fd, device, "Ring2", WACOM_BUTTON_RING2_MODESWITCH);
print_button_flag_if(fd, device, "Dial", WACOM_BUTTON_DIAL_MODESWITCH);
print_button_flag_if(fd, device, "Dial2", WACOM_BUTTON_DIAL2_MODESWITCH);
print_button_evdev_codes(fd, device);
dprintf(fd, "RingNumModes=%d\n", libwacom_get_ring_num_modes(device));
dprintf(fd, "Ring2NumModes=%d\n", libwacom_get_ring2_num_modes(device));
dprintf(fd, "StripsNumModes=%d\n", libwacom_get_strips_num_modes(device));
dprintf(fd, "DialNumModes=%d\n", libwacom_get_dial_num_modes(device));
dprintf(fd, "Dial2NumModes=%d\n", libwacom_get_dial2_num_modes(device));

dprintf(fd, "\n");
}
Expand Down Expand Up @@ -953,6 +970,9 @@ libwacom_print_device_description(int fd, const WacomDevice *device)
dprintf(fd, "NumStrips=%d\n", libwacom_get_num_strips(device));
dprintf(fd, "\n");

dprintf(fd, "NumDials=%d\n", libwacom_get_num_dials(device));
dprintf(fd, "\n");

print_buttons_for_device(fd, device);
}

Expand Down Expand Up @@ -1244,6 +1264,24 @@ libwacom_get_strips_num_modes(const WacomDevice *device)
return device->strips_num_modes;
}

LIBWACOM_EXPORT int
libwacom_get_num_dials(const WacomDevice *device)
{
return device->num_dials;
}

LIBWACOM_EXPORT int
libwacom_get_dial_num_modes(const WacomDevice *device)
{
return device->dial_num_modes;
}

LIBWACOM_EXPORT int
libwacom_get_dial2_num_modes(const WacomDevice *device)
{
return device->dial2_num_modes;
}

LIBWACOM_EXPORT const WacomStatusLEDs *
libwacom_get_status_leds(const WacomDevice *device, int *num_leds)
{
Expand Down
30 changes: 29 additions & 1 deletion libwacom/libwacom.h
Original file line number Diff line number Diff line change
Expand Up @@ -231,10 +231,13 @@ typedef enum {
WACOM_BUTTON_TOUCHSTRIP_MODESWITCH = (1 << 7),
WACOM_BUTTON_TOUCHSTRIP2_MODESWITCH = (1 << 8),
WACOM_BUTTON_OLED = (1 << 9),
WACOM_BUTTON_MODESWITCH = (WACOM_BUTTON_RING_MODESWITCH | WACOM_BUTTON_RING2_MODESWITCH | WACOM_BUTTON_TOUCHSTRIP_MODESWITCH | WACOM_BUTTON_TOUCHSTRIP2_MODESWITCH),
WACOM_BUTTON_DIAL_MODESWITCH = (1 << 10),
WACOM_BUTTON_DIAL2_MODESWITCH = (1 << 11),
WACOM_BUTTON_MODESWITCH = (WACOM_BUTTON_RING_MODESWITCH | WACOM_BUTTON_RING2_MODESWITCH | WACOM_BUTTON_TOUCHSTRIP_MODESWITCH | WACOM_BUTTON_TOUCHSTRIP2_MODESWITCH | WACOM_BUTTON_DIAL_MODESWITCH | WACOM_BUTTON_DIAL2_MODESWITCH),
WACOM_BUTTON_DIRECTION = (WACOM_BUTTON_POSITION_LEFT | WACOM_BUTTON_POSITION_RIGHT | WACOM_BUTTON_POSITION_TOP | WACOM_BUTTON_POSITION_BOTTOM),
WACOM_BUTTON_RINGS_MODESWITCH = (WACOM_BUTTON_RING_MODESWITCH | WACOM_BUTTON_RING2_MODESWITCH),
WACOM_BUTTON_TOUCHSTRIPS_MODESWITCH = (WACOM_BUTTON_TOUCHSTRIP_MODESWITCH | WACOM_BUTTON_TOUCHSTRIP2_MODESWITCH),
WACOM_BUTTON_DIALS_MODESWITCH = (WACOM_BUTTON_DIAL_MODESWITCH | WACOM_BUTTON_DIAL2_MODESWITCH),
} WacomButtonFlags;

/**
Expand Down Expand Up @@ -682,6 +685,31 @@ int libwacom_get_num_strips(const WacomDevice *device);
*/
int libwacom_get_strips_num_modes(const WacomDevice *device);

/**
* @param device The tablet to query
* @return the number of rotary dials on the tablet
* otherwise
*
* @ingroup devices
*/
int libwacom_get_num_dials(const WacomDevice *device);

/**
* @param device The tablet to query
* @return the number of modes for the dial, if any
*
* @ingroup devices
*/
int libwacom_get_dial_num_modes(const WacomDevice *device);

/**
* @param device The tablet to query
* @return the number of modes for the second dial, if any
*
* @ingroup devices
*/
int libwacom_get_dial2_num_modes(const WacomDevice *device);

/**
* @param device The tablet to query
* @param num_leds Return location for the number of supported status LEDs
Expand Down
5 changes: 4 additions & 1 deletion libwacom/libwacom.sym
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,9 @@ LIBWACOM_2.9 {
} LIBWACOM_2.0;

LIBWACOM_2.12 {
libwacom_match_get_uniq;
libwacom_get_dial_num_modes;
libwacom_get_dial2_num_modes;
libwacom_get_num_dials;
libwacom_get_num_rings;
libwacom_match_get_uniq;
} LIBWACOM_2.9;
3 changes: 3 additions & 0 deletions libwacom/libwacomint.h
Original file line number Diff line number Diff line change
Expand Up @@ -88,10 +88,13 @@ struct _WacomDevice {
WacomClass cls;
int num_strips;
int num_rings;
int num_dials;
uint32_t features;
uint32_t integration_flags;

int strips_num_modes;
int dial_num_modes;
int dial2_num_modes;
int ring_num_modes;
int ring2_num_modes;

Expand Down
2 changes: 2 additions & 0 deletions test/test-load.c
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,7 @@ test_intuos4(struct fixture *f, gconstpointer user_data)
g_assert_cmpint(libwacom_get_num_rings(device), ==, 1);
g_assert_false(libwacom_has_touchswitch(device));
g_assert_cmpint(libwacom_get_num_strips(device), ==, 0);
g_assert_cmpint(libwacom_get_num_dials(device), ==, 0);
g_assert_cmpint(libwacom_get_integration_flags (device), ==, WACOM_DEVICE_INTEGRATED_NONE);
g_assert_cmpint(libwacom_get_width(device), ==, 8);
g_assert_cmpint(libwacom_get_height(device), ==, 5);
Expand Down Expand Up @@ -177,6 +178,7 @@ test_cintiq21ux(struct fixture *f, gconstpointer user_data)
g_assert_nonnull(device);

g_assert_cmpint(libwacom_get_num_strips(device), ==, 2);
g_assert_cmpint(libwacom_get_num_dials(device), ==, 0);
libwacom_destroy(device);
}

Expand Down
63 changes: 63 additions & 0 deletions test/test-tablet-svg-validity.c
Original file line number Diff line number Diff line change
Expand Up @@ -176,6 +176,56 @@ check_touchstrip (xmlNodePtr cur, gchar *id)
g_free (class);
}

static void
check_dial (xmlNodePtr cur, gchar *id)
{
char *sub;
char *class;
xmlNodePtr node;

node = verify_has_sub (cur, id);
g_assert (node != NULL);

class = g_strdup_printf ("%s %s", id, "Dial");
verify_has_class (node, class);
g_free (class);

sub = g_strdup_printf ("Label%sUp", id);
node = verify_has_sub (cur, sub);
g_assert (node != NULL);
g_free (sub);

class = g_strdup_printf ("%sUp %s Label", id, id);
verify_has_class (node, class);
g_free (class);

sub = g_strdup_printf ("Label%sDown", id);
node = verify_has_sub (cur, sub);
g_assert (node != NULL);
g_free (sub);

class = g_strdup_printf ("%sDown %s Label", id, id);
verify_has_class (node, class);
g_free (class);

sub = g_strdup_printf ("Leader%sUp", id);
node = verify_has_sub (cur, sub);
g_assert (node != NULL);
g_free (sub);

class = g_strdup_printf ("%sUp %s Leader", id, id);
verify_has_class (node, class);
g_free (class);

sub = g_strdup_printf ("Leader%sDown", id);
node = verify_has_sub (cur, sub);
g_assert (node != NULL);
g_free (sub);

class = g_strdup_printf ("%sDown %s Leader", id, id);
verify_has_class (node, class);
g_free (class);
}

static void
check_touchring (xmlNodePtr cur, gchar *id)
Expand Down Expand Up @@ -279,6 +329,17 @@ test_strips(struct fixture *f, gconstpointer data)
check_touchstrip(f->root, "Strip2");
}

static void
test_dials(struct fixture *f, gconstpointer data)
{
const WacomDevice *device = data;

if (libwacom_get_num_dials(device) > 0)
check_dial(f->root, "Dial");
if (libwacom_get_num_dials(device) > 1)
check_dial(f->root, "Dial");
}

static void
test_buttons(struct fixture *f, gconstpointer data)
{
Expand Down Expand Up @@ -366,6 +427,8 @@ static void setup_tests(WacomDevice *device)
add_test(device, test_rings);
if (libwacom_get_num_strips(device) > 0)
add_test(device, test_strips);
if (libwacom_get_num_dials(device) > 0)
add_test(device, test_dials);
}

static WacomDeviceDatabase *
Expand Down
20 changes: 20 additions & 0 deletions test/test-tablet-validity.c
Original file line number Diff line number Diff line change
Expand Up @@ -295,6 +295,25 @@ test_strips(gconstpointer data)
WACOM_BUTTON_TOUCHSTRIP_MODESWITCH));
}

static void
test_dials(gconstpointer data)
{
WacomDevice *device = (WacomDevice*)data;

g_assert_cmpint(libwacom_get_num_dials(device), >=, 0);
g_assert_cmpint(libwacom_get_dial_num_modes(device), >=, 0);

if (libwacom_get_num_dials(device) > 0)
g_assert_true(match_mode_switch(device,
libwacom_get_dial_num_modes,
WACOM_BUTTON_DIAL_MODESWITCH));

if (libwacom_get_num_dials(device) > 1)
g_assert_true(match_mode_switch(device,
libwacom_get_dial2_num_modes,
WACOM_BUTTON_DIAL2_MODESWITCH));
}

/* Wrapper function to make adding tests simpler. g_test requires
* a unique test case name so we assemble that from the test function and
* the tablet data.
Expand Down Expand Up @@ -339,6 +358,7 @@ static void setup_tests(WacomDevice *device)
add_test(device, test_styli);
add_test(device, test_rings);
add_test(device, test_strips);
add_test(device, test_dials);

#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
Expand Down
8 changes: 6 additions & 2 deletions tools/debug-device.c
Original file line number Diff line number Diff line change
Expand Up @@ -162,6 +162,9 @@ handle_device(WacomDeviceDatabase *db, const char *path)
intfunc(libwacom_get_ring2_num_modes, device);
intfunc(libwacom_get_num_strips, device);
intfunc(libwacom_get_strips_num_modes, device);
intfunc(libwacom_get_num_dials, device);
intfunc(libwacom_get_dial_num_modes, device);
intfunc(libwacom_get_dial2_num_modes, device);

{
WacomIntegrationFlags flags = libwacom_get_integration_flags(device);
Expand Down Expand Up @@ -190,7 +193,7 @@ handle_device(WacomDeviceDatabase *db, const char *path)
WacomButtonFlags flags;

flags = libwacom_get_button_flag(device, b);
func_arg(libwacom_get_button_flag, "%c", b, "%s%s%s%s%s%s%s%s%s%s",
func_arg(libwacom_get_button_flag, "%c", b, "%s%s%s%s%s%s%s%s%s%s%s%s",
flags == WACOM_BUTTON_NONE ? "NONE" : "",
flags & WACOM_BUTTON_POSITION_LEFT ? "POSITION_LEFT|" : "",
flags & WACOM_BUTTON_POSITION_RIGHT ? "POSITION_RIGHT|" : "",
Expand All @@ -200,8 +203,9 @@ handle_device(WacomDeviceDatabase *db, const char *path)
flags & WACOM_BUTTON_RING2_MODESWITCH ? "RING2_MODESWITCH|" : "",
flags & WACOM_BUTTON_TOUCHSTRIP_MODESWITCH ? "TOUCHSTRIP_MODESWITCH|" : "",
flags & WACOM_BUTTON_TOUCHSTRIP2_MODESWITCH ? "TOUCHSTRIP2_MODESWITCH|" : "",
flags & WACOM_BUTTON_DIAL_MODESWITCH ? "DIAL_MODESWITCH|" : "",
flags & WACOM_BUTTON_DIAL2_MODESWITCH ? "DIAL2_MODESWITCH|" : "",
flags & WACOM_BUTTON_OLED ? "OLED " : "");

}
}

Expand Down

0 comments on commit b6b82e4

Please sign in to comment.