-
Notifications
You must be signed in to change notification settings - Fork 172
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
tools: add a debug-device utility (#666)
This one simply prints all return values for a device from our API, making it easier to figure out the exact behavior of a device. This is a debug utility so it is not installed. Example output: libwacom_get_name() -> "Wacom Cintiq 24HD touch" libwacom_get_model_name() -> "DTH-2400" libwacom_get_layout_filename() -> "data/layouts/cintiq-24hd.svg" libwacom_get_vendor_id() -> 0x56a libwacom_get_product_id() -> 0xf8 libwacom_get_bustype() -> USB libwacom_get_width() -> 21 libwacom_get_height() -> 13 libwacom_is_reversible() -> 0
- Loading branch information
Showing
2 changed files
with
373 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,365 @@ | ||
/* | ||
* Copyright © 2024 Red Hat, Inc. | ||
* | ||
* Permission to use, copy, modify, distribute, and sell this software | ||
* and its documentation for any purpose is hereby granted without | ||
* fee, provided that the above copyright notice appear in all copies | ||
* and that both that copyright notice and this permission notice | ||
* appear in supporting documentation, and that the name of Red Hat | ||
* not be used in advertising or publicity pertaining to distribution | ||
* of the software without specific, written prior permission. Red | ||
* Hat makes no representations about the suitability of this software | ||
* for any purpose. It is provided "as is" without express or implied | ||
* warranty. | ||
* | ||
* THE AUTHORS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, | ||
* INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN | ||
* NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY SPECIAL, INDIRECT OR | ||
* CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS | ||
* OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, | ||
* NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN | ||
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | ||
* | ||
* Authors: | ||
* Peter Hutterer <[email protected]> | ||
*/ | ||
|
||
#include "config.h" | ||
|
||
#include <stdio.h> | ||
#include <stdlib.h> | ||
#include <string.h> | ||
#include <unistd.h> | ||
#include <assert.h> | ||
#include <glib/gi18n.h> | ||
#include <glib.h> | ||
#include "libwacom.h" | ||
|
||
static char *database_path; | ||
static gboolean with_styli; | ||
|
||
static GOptionEntry opts[] = { | ||
{"database", 0, 0, G_OPTION_ARG_FILENAME, &database_path, N_("Path to device database"), NULL }, | ||
{"with-styli", 0, 0, G_OPTION_ARG_NONE, &with_styli, N_("Select to also list styli for this device"), NULL }, | ||
{ .long_name = NULL} | ||
}; | ||
|
||
static int indent = 0; | ||
|
||
#define push() indent += 2 | ||
#define pop() indent -= 2 | ||
|
||
#define ip(fmt_, ...) \ | ||
printf("%-*s" fmt_, indent, "", __VA_ARGS__); | ||
/* Usage: p("function_name", "return value is %d", a) */ | ||
#define p(f_, fmt_, ...) \ | ||
printf("%-*s%-*s -> " fmt_ "\n", indent, "", (46 - indent), f_, __VA_ARGS__) | ||
|
||
/* Usage: func(myfunc, "return value is %d", a) */ | ||
#define func(f_, fmt_, ...) \ | ||
p(#f_"()", fmt_, __VA_ARGS__) | ||
|
||
/* Usage: func(myfunc, "%d", argval, "return value is %d", a) */ | ||
#define func_arg(f_, arg_fmt_, arg_val_, fmt_, ...) \ | ||
{ \ | ||
char buf_[256]; \ | ||
snprintf(buf_, sizeof(buf_), #f_"(" arg_fmt_ ")", arg_val_); \ | ||
p(buf_, fmt_, __VA_ARGS__); \ | ||
} | ||
|
||
#define strfunc(f_, dev_) \ | ||
func(f_, "\"%s\"", f_(dev_)) | ||
|
||
#define hexfunc(f_, dev_) \ | ||
func(f_, "0x%04x", f_(dev_)) | ||
|
||
#define intfunc(f_, dev_) \ | ||
func(f_, "%d", f_(dev_)) | ||
|
||
static void | ||
handle_match(const WacomMatch *m) | ||
{ | ||
if (m == NULL) { | ||
printf(" <none>\n"); | ||
return; | ||
} | ||
push(); | ||
ip("%s\n", "{"); | ||
push(); | ||
strfunc(libwacom_match_get_match_string, m); | ||
strfunc(libwacom_match_get_name, m); | ||
strfunc(libwacom_match_get_uniq, m); | ||
hexfunc(libwacom_match_get_bustype, m); | ||
hexfunc(libwacom_match_get_vendor_id, m); | ||
hexfunc(libwacom_match_get_product_id, m); | ||
pop(); | ||
ip("%s\n", "}"); | ||
pop(); | ||
} | ||
|
||
static int | ||
handle_device(WacomDeviceDatabase *db, const char *path) | ||
{ | ||
WacomDevice *device; | ||
|
||
device = libwacom_new_from_path(db, path, WFALLBACK_NONE, NULL); | ||
if (!device) { | ||
fprintf(stderr, "Device not known to libwacom\n"); | ||
return EXIT_FAILURE; | ||
} | ||
|
||
strfunc(libwacom_get_name, device); | ||
strfunc(libwacom_get_model_name, device); | ||
strfunc(libwacom_get_layout_filename, device); | ||
|
||
hexfunc(libwacom_get_vendor_id, device); | ||
hexfunc(libwacom_get_product_id, device); | ||
{ | ||
char *busstr = NULL; | ||
switch (libwacom_get_bustype(device)) { | ||
case WBUSTYPE_UNKNOWN: busstr = "UNKNOWN"; break; | ||
case WBUSTYPE_USB: busstr = "USB"; break; | ||
case WBUSTYPE_SERIAL: busstr = "SERIAL"; break; | ||
case WBUSTYPE_BLUETOOTH: busstr = "BLUETOOTH"; break; | ||
case WBUSTYPE_I2C: busstr = "I2C"; break; | ||
} | ||
func(libwacom_get_bustype, "%s", busstr); | ||
} | ||
|
||
intfunc(libwacom_get_width, device); | ||
intfunc(libwacom_get_height, device); | ||
|
||
intfunc(libwacom_is_reversible, device); | ||
|
||
{ | ||
const WacomMatch **matches = libwacom_get_matches(device); | ||
const WacomMatch **m; | ||
|
||
printf("libwacom_get_matches() -> {\n"); | ||
for (m = matches; *m; m++) { | ||
handle_match(*m); | ||
} | ||
printf("}\n"); | ||
} | ||
|
||
strfunc(libwacom_get_match, device); | ||
|
||
printf("libwacom_get_paired_device() -> {"); | ||
handle_match(libwacom_get_paired_device(device)); | ||
printf("}\n"); | ||
|
||
intfunc(libwacom_has_stylus, device); | ||
intfunc(libwacom_has_touch, device); | ||
intfunc(libwacom_get_num_buttons, device); | ||
intfunc(libwacom_get_num_keys, device); | ||
intfunc(libwacom_has_ring, device); | ||
intfunc(libwacom_has_ring2, device); | ||
intfunc(libwacom_has_touchswitch, device); | ||
intfunc(libwacom_get_ring_num_modes, device); | ||
intfunc(libwacom_get_ring2_num_modes, device); | ||
intfunc(libwacom_get_num_strips, device); | ||
intfunc(libwacom_get_strips_num_modes, device); | ||
|
||
{ | ||
WacomIntegrationFlags flags = libwacom_get_integration_flags(device); | ||
func(libwacom_get_integration_flags, "%s%s %s", | ||
flags == WACOM_DEVICE_INTEGRATED_NONE ? "NONE" : "", | ||
flags == WACOM_DEVICE_INTEGRATED_DISPLAY ? "DISPLAY" : "", | ||
flags == WACOM_DEVICE_INTEGRATED_SYSTEM ? "SYSTEM" : "" | ||
); | ||
} | ||
|
||
{ | ||
for (int i = 0; i < libwacom_get_num_buttons(device); i++) { | ||
char b = 'A' + i; | ||
func_arg(libwacom_get_button_led_group, "%c", b, "%d", | ||
libwacom_get_button_led_group(device, b)); | ||
} | ||
|
||
for (int i = 0; i < libwacom_get_num_buttons(device); i++) { | ||
char b = 'A' + i; | ||
func_arg(libwacom_get_button_evdev_code, "%c", b, "0x%x", | ||
libwacom_get_button_evdev_code(device, b)); | ||
} | ||
|
||
for (int i = 0; i < libwacom_get_num_buttons(device); i++) { | ||
char b = 'A' + i; | ||
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", | ||
flags == WACOM_BUTTON_NONE ? "NONE" : "", | ||
flags & WACOM_BUTTON_POSITION_LEFT ? "POSITION_LEFT|" : "", | ||
flags & WACOM_BUTTON_POSITION_RIGHT ? "POSITION_RIGHT|" : "", | ||
flags & WACOM_BUTTON_POSITION_TOP ? "POSITION_TOP|" : "", | ||
flags & WACOM_BUTTON_POSITION_BOTTOM ? "POSITION_BOTTOM|" : "", | ||
flags & WACOM_BUTTON_RING_MODESWITCH ? "RING_MODESWITCH|" : "", | ||
flags & WACOM_BUTTON_RING2_MODESWITCH ? "RING2_MODESWITCH|" : "", | ||
flags & WACOM_BUTTON_TOUCHSTRIP_MODESWITCH ? "TOUCHSTRIP_MODESWITCH|" : "", | ||
flags & WACOM_BUTTON_TOUCHSTRIP2_MODESWITCH ? "TOUCHSTRIP2_MODESWITCH|" : "", | ||
flags & WACOM_BUTTON_OLED ? "OLED " : ""); | ||
|
||
} | ||
} | ||
|
||
{ | ||
char buf[1024] = {0}; | ||
int nleds; | ||
const WacomStatusLEDs *leds = libwacom_get_status_leds(device, &nleds); | ||
|
||
for (int i = 0; i < nleds; i++) { | ||
char *ledstr = NULL; | ||
switch (leds[i]) { | ||
case WACOM_STATUS_LED_UNAVAILABLE: ledstr = "UNAVAILABLE"; break; | ||
case WACOM_STATUS_LED_RING: ledstr = "RING"; break; | ||
case WACOM_STATUS_LED_RING2: ledstr = "RING2"; break; | ||
case WACOM_STATUS_LED_TOUCHSTRIP: ledstr = "TOUCHSTRIP"; break; | ||
case WACOM_STATUS_LED_TOUCHSTRIP2: ledstr = "TOUCHSTRIP2"; break; | ||
} | ||
snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), "%s%s", i > 0 ? ", " : "", ledstr); | ||
} | ||
func(libwacom_get_status_leds, "[%s]", buf); | ||
} | ||
|
||
{ | ||
int nstyli; | ||
const int *styli = libwacom_get_supported_styli(device, &nstyli); | ||
|
||
{ | ||
char buf[1024] = {0}; | ||
for (int i = 0; i < nstyli; i++) | ||
snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), "%s0x%06x", i > 0 ? ", " : "", styli[i]); | ||
|
||
func(libwacom_get_supported_styli, "[%s]", buf); | ||
} | ||
|
||
|
||
if (with_styli) { | ||
printf("\n---------- Listing styli for this device ----------\n"); | ||
|
||
for (int i = 0; i < nstyli; i++) { | ||
int id = styli[i]; | ||
const WacomStylus *stylus = libwacom_stylus_get_for_id (db, id); | ||
|
||
ip("%s\n", "{"); | ||
push(); | ||
func_arg(libwacom_stylus_get_id, "0x%04x", id, "0x%04x", libwacom_stylus_get_id(stylus)); | ||
func_arg(libwacom_stylus_get_name, "0x%04x", id, "%s", libwacom_stylus_get_name(stylus)); | ||
func_arg(libwacom_stylus_get_num_buttons, "0x%04x", id, "%d", libwacom_stylus_get_num_buttons(stylus)); | ||
func_arg(libwacom_stylus_has_eraser, "0x%04x", id, "%d", libwacom_stylus_has_eraser(stylus)); | ||
func_arg(libwacom_stylus_is_eraser, "0x%04x", id, "%d", libwacom_stylus_is_eraser(stylus)); | ||
func_arg(libwacom_stylus_has_lens, "0x%04x", id, "%d", libwacom_stylus_has_lens(stylus)); | ||
func_arg(libwacom_stylus_has_wheel, "0x%04x", id, "%d", libwacom_stylus_has_wheel(stylus)); | ||
|
||
{ | ||
char buf[1024] = {0}; | ||
int npaired; | ||
const int *paired = libwacom_stylus_get_paired_ids(stylus, &npaired); | ||
|
||
for (int i = 0; i < npaired; i++) | ||
snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), "%s0x%06x", i > 0 ? ", " : "", paired[i]); | ||
func_arg(libwacom_stylus_get_paired_ids, "0x%04x", id, "[%s]", buf); | ||
} | ||
|
||
{ | ||
WacomAxisTypeFlags flags = libwacom_stylus_get_axes(stylus); | ||
func_arg(libwacom_stylus_has_wheel, "0x%04x", id, "%s%s%s%s%s%s", | ||
flags == WACOM_AXIS_TYPE_NONE ? "NONE" : "", | ||
flags & WACOM_AXIS_TYPE_TILT ? "TILT|" : "", | ||
flags & WACOM_AXIS_TYPE_ROTATION_Z ? "ROTATION_Z|" : "", | ||
flags & WACOM_AXIS_TYPE_DISTANCE ? "DISTANCE|" : "", | ||
flags & WACOM_AXIS_TYPE_PRESSURE ? "PRESSURE|" : "", | ||
flags & WACOM_AXIS_TYPE_SLIDER ? "SLIDER" : ""); | ||
} | ||
|
||
{ | ||
const char *typestr = NULL; | ||
switch (libwacom_stylus_get_type(stylus)) { | ||
case WSTYLUS_UNKNOWN: typestr = "UNKNOWN"; break; | ||
case WSTYLUS_GENERAL: typestr = "GENERAL"; break; | ||
case WSTYLUS_INKING: typestr = "INKING"; break; | ||
case WSTYLUS_AIRBRUSH: typestr = "AIRBRUSH"; break; | ||
case WSTYLUS_CLASSIC: typestr = "CLASSIC"; break; | ||
case WSTYLUS_MARKER: typestr = "MARKER"; break; | ||
case WSTYLUS_STROKE: typestr = "STROKE"; break; | ||
case WSTYLUS_PUCK: typestr = "PUCK"; break; | ||
case WSTYLUS_3D: typestr = "3D"; break; | ||
case WSTYLUS_MOBILE: typestr = "MOBILE"; break; | ||
} | ||
|
||
func_arg(libwacom_stylus_get_type, "0x%04x", id, "%s", typestr); | ||
} | ||
|
||
{ | ||
const char *eraserstr = NULL; | ||
switch (libwacom_stylus_get_eraser_type(stylus)) { | ||
case WACOM_ERASER_UNKNOWN: eraserstr = "UNKNOWN"; break; | ||
case WACOM_ERASER_NONE: eraserstr = "NONE"; break; | ||
case WACOM_ERASER_INVERT: eraserstr = "INVERT"; break; | ||
case WACOM_ERASER_BUTTON: eraserstr = "BUTTON"; break; | ||
} | ||
|
||
func_arg(libwacom_stylus_get_type, "0x%04x", id, "%s", eraserstr); | ||
} | ||
pop(); | ||
ip("%s\n", "}"); | ||
} | ||
} | ||
} | ||
|
||
libwacom_destroy(device); | ||
|
||
return EXIT_SUCCESS; | ||
} | ||
|
||
int main(int argc, char **argv) | ||
{ | ||
WacomDeviceDatabase *db; | ||
GOptionContext *context; | ||
GError *error; | ||
int rc; | ||
|
||
context = g_option_context_new (NULL); | ||
|
||
g_option_context_add_main_entries (context, opts, NULL); | ||
error = NULL; | ||
|
||
if (!g_option_context_parse (context, &argc, &argv, &error)) { | ||
if (error != NULL) { | ||
fprintf (stderr, "%s\n", error->message); | ||
g_error_free (error); | ||
} | ||
return EXIT_FAILURE; | ||
} | ||
|
||
g_option_context_free (context); | ||
|
||
if (database_path) { | ||
db = libwacom_database_new_for_path(database_path); | ||
g_free (database_path); | ||
} else { | ||
#ifdef DATABASEPATH | ||
db = libwacom_database_new_for_path(DATABASEPATH); | ||
#else | ||
db = libwacom_database_new(); | ||
#endif | ||
} | ||
|
||
if (!db) { | ||
fprintf(stderr, "Failed to initialize device database\n"); | ||
return EXIT_FAILURE; | ||
} | ||
|
||
if (argc <= 1) { | ||
fprintf(stderr, "Missing device node\n"); | ||
libwacom_database_destroy (db); | ||
return EXIT_FAILURE; | ||
} | ||
|
||
rc = handle_device(db, argv[1]); | ||
|
||
libwacom_database_destroy (db); | ||
return rc; | ||
} | ||
|
||
/* vim: set noexpandtab tabstop=8 shiftwidth=8: */ |