From c05d522a1d840b801c6bdaf635b61a9cd6a991b3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?P=C5=99emysl=20Janouch?= Date: Sun, 2 Jun 2013 23:50:33 +0200 Subject: [PATCH] Add a GTK+ GUI --- CMakeLists.txt | 67 +++++- config.h.in | 9 +- org.sensei-raw-ctl.policy.in | 17 ++ quote-file.cmake | 4 + sensei-raw-ctl-gui.c | 379 ++++++++++++++++++++++++++++++++++ sensei-raw-ctl-gui.desktop.in | 8 + sensei-raw-ctl-gui.svg | 37 ++++ sensei-raw-ctl-gui.ui | 199 ++++++++++++++++++ sensei-raw-ctl.c | 16 +- sensei-raw.svg | 37 ++++ 10 files changed, 756 insertions(+), 17 deletions(-) create mode 100644 org.sensei-raw-ctl.policy.in create mode 100644 quote-file.cmake create mode 100644 sensei-raw-ctl-gui.c create mode 100644 sensei-raw-ctl-gui.desktop.in create mode 100644 sensei-raw-ctl-gui.svg create mode 100644 sensei-raw-ctl-gui.ui create mode 100644 sensei-raw.svg diff --git a/CMakeLists.txt b/CMakeLists.txt index e34375c..35b3ce6 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -6,13 +6,66 @@ find_package (PkgConfig REQUIRED) pkg_check_modules (dependencies REQUIRED libusb-1.0) include_directories (${dependencies_INCLUDE_DIRS}) -configure_file (${CMAKE_CURRENT_SOURCE_DIR}/config.h.in - ${CMAKE_CURRENT_BINARY_DIR}/config.h) -include_directories (${CMAKE_CURRENT_BINARY_DIR}) - -add_executable (${CMAKE_PROJECT_NAME} ${CMAKE_PROJECT_NAME}.c) -target_link_libraries (${CMAKE_PROJECT_NAME} ${dependencies_LIBRARIES}) +option (DEVELOPER_MODE "Developer mode" OFF) include (GNUInstallDirs) -install (TARGETS ${CMAKE_PROJECT_NAME} DESTINATION ${CMAKE_INSTALL_BINDIR}) +configure_file (${PROJECT_SOURCE_DIR}/config.h.in + ${PROJECT_BINARY_DIR}/config.h) +include_directories (${PROJECT_BINARY_DIR}) +add_executable (${PROJECT_NAME} ${PROJECT_NAME}.c) +target_link_libraries (${PROJECT_NAME} ${dependencies_LIBRARIES}) +install (TARGETS ${PROJECT_NAME} DESTINATION ${CMAKE_INSTALL_BINDIR}) + +pkg_check_modules (gtk3 gtk+-3.0) +set (BUILD_GUI ${gtk3_FOUND} CACHE BOOL "Whether to build the GTK+ frontend") + +if (BUILD_GUI) + include_directories (${gtk3_INCLUDE_DIRS}) + link_directories (${gtk3_LIBRARY_DIRS}) + + set (ui_in ${PROJECT_SOURCE_DIR}/${PROJECT_NAME}-gui.ui) + set (ui_out ${PROJECT_BINARY_DIR}/${PROJECT_NAME}-gui-ui.c) + add_custom_command (OUTPUT ${ui_out} + COMMAND ${CMAKE_COMMAND} -D "input=${ui_in}" -D "output=${ui_out}" + -D var_name=ui -P "${PROJECT_SOURCE_DIR}/quote-file.cmake" + DEPENDS ${ui_in} + COMMENT "Wrapping the UI file into a source file" VERBATIM) + + configure_file (${PROJECT_SOURCE_DIR}/${PROJECT_NAME}-gui.desktop.in + ${PROJECT_BINARY_DIR}/${PROJECT_NAME}-gui.desktop) + install (FILES ${PROJECT_BINARY_DIR}/${PROJECT_NAME}-gui.desktop + DESTINATION ${CMAKE_INSTALL_DATADIR}/applications) + install (FILES ${PROJECT_SOURCE_DIR}/${PROJECT_NAME}-gui.svg + DESTINATION ${CMAKE_INSTALL_DATADIR}/icons/hicolor/scalable/apps) + + set (polkit_id "org.${PROJECT_NAME}.policy") + configure_file (${PROJECT_SOURCE_DIR}/${polkit_id}.in + ${PROJECT_BINARY_DIR}/${polkit_id}) + install (FILES ${PROJECT_BINARY_DIR}/${polkit_id} + DESTINATION ${CMAKE_INSTALL_DATADIR}/polkit-1/actions) + + add_executable (${PROJECT_NAME}-gui ${PROJECT_NAME}-gui.c ${ui_out}) + set_target_properties (${PROJECT_NAME}-gui PROPERTIES + COMPILE_FLAGS "${gtk3_CFLAGS_OTHER}") + target_link_libraries (${PROJECT_NAME}-gui ${gtk3_LIBRARIES}) + install (TARGETS ${PROJECT_NAME}-gui + DESTINATION ${CMAKE_INSTALL_BINDIR}) +endif (BUILD_GUI) + +set (CPACK_PACKAGE_DESCRIPTION_SUMMARY "SteelSeries Sensei Raw control utility") +set (CPACK_PACKAGE_VERSION ${project_VERSION}) +set (CPACK_PACKAGE_VENDOR "Premysl Janouch") +set (CPACK_PACKAGE_CONTACT "Přemysl Janouch ") +set (CPACK_RESOURCE_FILE_LICENSE "${PROJECT_SOURCE_DIR}/LICENSE") + +set (CPACK_GENERATOR "TGZ;ZIP") +set (CPACK_PACKAGE_FILE_NAME + "${PROJECT_NAME}-${project_VERSION}-${CMAKE_SYSTEM_NAME}-${CMAKE_SYSTEM_PROCESSOR}") + +set (CPACK_SOURCE_GENERATOR "TGZ;ZIP") +set (CPACK_SOURCE_IGNORE_FILES "/\\\\.git;/build;/CMakeLists.txt.user") +set (CPACK_SOURCE_PACKAGE_FILE_NAME "${PROJECT_NAME}-${project_VERSION}") + +set (CPACK_SET_DESTDIR TRUE) +include (CPack) diff --git a/config.h.in b/config.h.in index d00c838..36afa2c 100644 --- a/config.h.in +++ b/config.h.in @@ -4,6 +4,11 @@ #define PROJECT_NAME "${CMAKE_PROJECT_NAME}" #define PROJECT_VERSION "${project_VERSION}" -#endif /* ! CONFIG_H */ - +#cmakedefine DEVELOPER_MODE +#ifdef DEVELOPER_MODE + #define PROJECT_INSTALL_BINDIR "${PROJECT_BINARY_DIR}" +#else // ! DEVELOPER_MODE + #define PROJECT_INSTALL_BINDIR "${CMAKE_INSTALL_FULL_BINDIR}" +#endif // ! DEVELOPER MODE +#endif // ! CONFIG_H diff --git a/org.sensei-raw-ctl.policy.in b/org.sensei-raw-ctl.policy.in new file mode 100644 index 0000000..e37f0dd --- /dev/null +++ b/org.sensei-raw-ctl.policy.in @@ -0,0 +1,17 @@ + + + + ${PROJECT_NAME}-gui + + Device access + Authentication is required to access the USB device + + no + no + auth_admin_keep + + ${CMAKE_INSTALL_FULL_BINDIR}/${PROJECT_NAME} + + diff --git a/quote-file.cmake b/quote-file.cmake new file mode 100644 index 0000000..6f9159e --- /dev/null +++ b/quote-file.cmake @@ -0,0 +1,4 @@ +file (READ ${input} contents) +string (REPLACE "\n" "\\n\"\n\"" contents "${contents}") +file (WRITE ${output} + "const char ${var_name}[] = \n\"${contents}\";\n") diff --git a/sensei-raw-ctl-gui.c b/sensei-raw-ctl-gui.c new file mode 100644 index 0000000..46272de --- /dev/null +++ b/sensei-raw-ctl-gui.c @@ -0,0 +1,379 @@ +/* + * sensei-raw-ctl-gui.c: SteelSeries Sensei Raw control utility - GTK+ GUI + * + * Very tightly coupled with the sensei-raw-ctl utility. + * + * Copyright (c) 2013, Přemysl Janouch + * All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * SPECIAL, DIRECT, 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. + * + */ + +#include +#include +#include + +#include +#include + +#include "config.h" + +/** User interface string for GtkBuilder. */ +extern const char ui[]; + +/* To translate combo box entries into sensei-raw-ctl arguments. */ +static gchar *pulsation_list[] = { "steady", "slow", "medium", "fast", NULL }; +static gchar *intensity_list[] = { "off", "low", "medium", "high", NULL }; + +/* GtkNotebook pages within the UI. */ +enum +{ + PAGE_PROBING, + PAGE_NO_DEVICE, + PAGE_SETTINGS, + PAGE_COUNT +}; + +/* sensei-raw-ctl output values. */ +enum +{ + OUT_INTENSITY, + OUT_PULSATION, + OUT_CPI_LED_OFF, + OUT_CPI_LED_ON, + OUT_POLLING, + OUT_COUNT +}; + +// ----- User interface ------------------------------------------------------- + +static void +fatal (GtkWidget *parent, const gchar *message) +{ + GtkWidget *dialog = gtk_message_dialog_new (GTK_WINDOW (parent), + GTK_DIALOG_DESTROY_WITH_PARENT, + GTK_MESSAGE_ERROR, GTK_BUTTONS_CLOSE, _("Fatal error")); + gtk_message_dialog_format_secondary_text + (GTK_MESSAGE_DIALOG (dialog), "%s", message); + gtk_dialog_run (GTK_DIALOG (dialog)); + gtk_widget_destroy (dialog); + gtk_main_quit (); +} + +static void +set_page (GtkBuilder *builder, gint page) +{ + GtkNotebook *notebook = GTK_NOTEBOOK + (gtk_builder_get_object (builder, "notebook")); + gtk_notebook_set_current_page (notebook, page); +} + +static gboolean +spawn_ctl (gchar **argv, gchar **out, GtkBuilder *builder) +{ + GError *error = NULL; + gint status; + gchar *err; + + GtkWidget *win = GTK_WIDGET (gtk_builder_get_object (builder, "win")); + if (!g_spawn_sync (NULL, argv, NULL, G_SPAWN_SEARCH_PATH, NULL, NULL, + out, &err, &status, &error)) + { + fatal (win, error->message); + g_error_free (error); + return FALSE; + } + + if (WIFEXITED (status) && WEXITSTATUS (status) == 0) + return TRUE; + + if (strstr (err, "no suitable device")) + set_page (builder, PAGE_NO_DEVICE); + else + fatal (win, err); + + g_clear_pointer (out, g_free); + g_free (err); + return FALSE; +} + +static gboolean +set_combo (GtkComboBox *combo, gchar *list[], const gchar *word) +{ + gint i; + for (i = 0; list[i]; i++) + if (!strcmp (word, list[i])) + { + gtk_combo_box_set_active (combo, i); + return TRUE; + } + return FALSE; +} + +static gboolean +set_scale (GtkRange *scale, const gchar *word, const gchar *follows) +{ + gchar *end; + gint64 value = g_ascii_strtoll (word, &end, 10); + if (strcmp (end, follows)) + return FALSE; + + gtk_range_set_value (scale, value); + return TRUE; +} + +static void +load_configuration (GtkBuilder *builder) +{ + gchar *argv[] = { "pkexec", + PROJECT_INSTALL_BINDIR "/" PROJECT_NAME, "--show", NULL }; + + gchar *out; + if (!spawn_ctl (argv, &out, builder)) + return; + + GRegex *regex = g_regex_new ("(?<=: ).*$", G_REGEX_MULTILINE, 0, NULL); + GMatchInfo *info; + g_regex_match (regex, out, 0, &info); + + gint line = 0; + gchar *word = NULL; + + while (g_match_info_matches (info)) + { + g_free (word); + word = g_match_info_fetch (info, 0); + switch (line++) + { + case OUT_INTENSITY: + if (!set_combo (GTK_COMBO_BOX (gtk_builder_get_object + (builder, "intensity_combo")), intensity_list, word)) + goto out; + break; + case OUT_PULSATION: + if (!set_combo (GTK_COMBO_BOX (gtk_builder_get_object + (builder, "pulsation_combo")), pulsation_list, word)) + goto out; + break; + case OUT_CPI_LED_OFF: + if (!set_scale (GTK_RANGE (gtk_builder_get_object + (builder, "cpi_off_scale")), word, "")) + goto out; + break; + case OUT_CPI_LED_ON: + if (!set_scale (GTK_RANGE (gtk_builder_get_object + (builder, "cpi_on_scale")), word, "")) + goto out; + break; + case OUT_POLLING: + if (!set_scale (GTK_RANGE (gtk_builder_get_object + (builder, "polling_scale")), word, "Hz")) + goto out; + } + g_match_info_next (info, NULL); + } + + set_page (builder, PAGE_SETTINGS); + +out: + g_free (word); + g_match_info_free (info); + g_regex_unref (regex); + g_free (out); + + if (line != OUT_COUNT) + fatal (GTK_WIDGET (gtk_builder_get_object (builder, "win")), + _("Internal error")); +} + +static void +retry_load (GtkBuilder *builder) +{ + set_page (builder, PAGE_PROBING); + load_configuration (builder); +} + +static void +save_configuration (GtkBuilder *builder) +{ + gchar *polling = g_strdup_printf ("%.0f", gtk_range_get_value + (GTK_RANGE (gtk_builder_get_object (builder, "polling_scale")))); + gchar *cpi_on = g_strdup_printf ("%.0f", gtk_range_get_value + (GTK_RANGE (gtk_builder_get_object (builder, "cpi_on_scale")))); + gchar *cpi_off = g_strdup_printf ("%.0f", gtk_range_get_value + (GTK_RANGE (gtk_builder_get_object (builder, "cpi_off_scale")))); + + GtkComboBox *combo; + gint active; + + combo = GTK_COMBO_BOX (gtk_builder_get_object (builder, "pulsation_combo")); + active = gtk_combo_box_get_active (combo); + g_assert (active >= 0 && active < G_N_ELEMENTS (pulsation_list) - 1); + gchar *pulsation = pulsation_list[active]; + + combo = GTK_COMBO_BOX (gtk_builder_get_object (builder, "intensity_combo")); + active = gtk_combo_box_get_active (combo); + g_assert (active >= 0 && active < G_N_ELEMENTS (intensity_list) - 1); + gchar *intensity = intensity_list[active]; + + gchar *argv[] = { "pkexec", PROJECT_INSTALL_BINDIR "/" PROJECT_NAME, + "--polling", polling, "--cpi-on", cpi_on, "--cpi-off", cpi_off, + "--pulsation", pulsation, "--intensity", intensity, "--save", NULL }; + + gchar *out; + if (spawn_ctl (argv, &out, builder)) + g_free (out); + + g_free (polling); + g_free (cpi_on); + g_free (cpi_off); +} + +static void +on_set_mode_normal (GtkBuilder *builder) +{ + gchar *out, *argv[] = { "pkexec", + PROJECT_INSTALL_BINDIR "/" PROJECT_NAME, "--mode", "normal", NULL }; + if (spawn_ctl (argv, &out, builder)) + g_free (out); +} + +static void +on_set_mode_legacy (GtkBuilder *builder) +{ + gchar *out, *argv[] = { "pkexec", + PROJECT_INSTALL_BINDIR "/" PROJECT_NAME, "--mode", "compat", NULL }; + if (spawn_ctl (argv, &out, builder)) + g_free (out); +} + +// ----- User interface ------------------------------------------------------- + +static gboolean +on_change_value (GtkRange *range, GtkScrollType scroll, gdouble value, + gpointer user_data) +{ + GtkAdjustment *adjustment = gtk_range_get_adjustment (range); + static const gint steps[] = { 125, 250, 500, 1000 }; + + switch (scroll) + { + gint i; + case GTK_SCROLL_NONE: + case GTK_SCROLL_JUMP: + for (i = 0; i < G_N_ELEMENTS (steps); i++) + if (i == G_N_ELEMENTS (steps) - 1 || + value < (steps[i] + steps[i + 1]) / 2) + { + value = steps[i]; + break; + } + break; + case GTK_SCROLL_STEP_BACKWARD: + case GTK_SCROLL_PAGE_BACKWARD: + value = gtk_adjustment_get_value (adjustment); + for (i = 0; i < G_N_ELEMENTS (steps) - 1; i++) + if (steps[i + 1] >= value) + { + value = steps[i]; + break; + } + break; + case GTK_SCROLL_STEP_FORWARD: + case GTK_SCROLL_PAGE_FORWARD: + value = gtk_adjustment_get_value (adjustment); + for (i = 0; i < G_N_ELEMENTS (steps); i++) + if (steps[i] > value) + { + value = steps[i]; + break; + } + break; + case GTK_SCROLL_START: + value = steps[0]; + break; + case GTK_SCROLL_END: + value = steps[G_N_ELEMENTS (steps) - 1]; + break; + default: + g_assert_not_reached (); + } + + gtk_adjustment_set_value (adjustment, value); + return TRUE; +} + +static gboolean +on_change_value_steps (GtkRange *range, GtkScrollType scroll, gdouble value, + gpointer user_data) +{ + GtkAdjustment *adjustment = gtk_range_get_adjustment (range); + gdouble lower = gtk_adjustment_get_lower (adjustment); + gdouble step = gtk_adjustment_get_step_increment (adjustment); + value = lower + (int) ((value - lower) / step + 0.5) * step; + gtk_adjustment_set_value (adjustment, value); + return TRUE; +} + +static gchar * +on_format_value (GtkScale *scale, gdouble value) +{ + return g_strdup_printf (_("%gHz"), value); +} + +int +main (int argc, char *argv[]) +{ + gtk_init (&argc, &argv); + gtk_window_set_default_icon_name (PROJECT_NAME "-gui"); + + GError *error = NULL; + GtkBuilder *builder = gtk_builder_new (); + if (!gtk_builder_add_from_string (builder, ui, -1, &error)) + { + g_printerr ("%s: %s\n", _("Error"), error->message); + exit (EXIT_FAILURE); + } + + GtkWidget *win = GTK_WIDGET (gtk_builder_get_object (builder, "win")); + g_signal_connect (win, "destroy", G_CALLBACK (gtk_main_quit), NULL); + g_signal_connect_swapped (win, "map-event", + G_CALLBACK (load_configuration), builder); + gtk_widget_show_all (win); + + g_signal_connect (gtk_builder_get_object (builder, "polling_scale"), + "change-value", G_CALLBACK (on_change_value), NULL); + g_signal_connect (gtk_builder_get_object (builder, "polling_scale"), + "format-value", G_CALLBACK (on_format_value), NULL); + + g_signal_connect (gtk_builder_get_object (builder, "cpi_off_scale"), + "change-value", G_CALLBACK (on_change_value_steps), NULL); + g_signal_connect (gtk_builder_get_object (builder, "cpi_on_scale"), + "change-value", G_CALLBACK (on_change_value_steps), NULL); + + g_signal_connect_swapped (gtk_builder_get_object (builder, "retry_button"), + "clicked", G_CALLBACK (retry_load), builder); + + g_signal_connect_swapped (gtk_builder_get_object (builder, "normal_button"), + "clicked", G_CALLBACK (on_set_mode_normal), builder); + g_signal_connect_swapped (gtk_builder_get_object (builder, "legacy_button"), + "clicked", G_CALLBACK (on_set_mode_legacy), builder); + g_signal_connect_swapped (gtk_builder_get_object (builder, "apply_button"), + "clicked", G_CALLBACK (save_configuration), builder); + + gtk_main (); + g_object_unref (builder); + return 0; +} + diff --git a/sensei-raw-ctl-gui.desktop.in b/sensei-raw-ctl-gui.desktop.in new file mode 100644 index 0000000..202d429 --- /dev/null +++ b/sensei-raw-ctl-gui.desktop.in @@ -0,0 +1,8 @@ +[Desktop Entry] +Type=Application +Name=${CMAKE_PROJECT_NAME}-gui +GenericName=SteelSeries Sensei Raw control utility +Icon=${CMAKE_PROJECT_NAME}-gui +Exec=${CMAKE_PROJECT_NAME}-gui +StartupNotify=true +Categories=Settings;System;Utility;GTK; diff --git a/sensei-raw-ctl-gui.svg b/sensei-raw-ctl-gui.svg new file mode 100644 index 0000000..2bb1c26 --- /dev/null +++ b/sensei-raw-ctl-gui.svg @@ -0,0 +1,37 @@ + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/sensei-raw-ctl-gui.ui b/sensei-raw-ctl-gui.ui new file mode 100644 index 0000000..7b6ae27 --- /dev/null +++ b/sensei-raw-ctl-gui.ui @@ -0,0 +1,199 @@ + + + 125 + 1000 + + + 90 + 5670 + 90 + 90 + + + 90 + 5670 + 90 + 90 + + + GTK_SIZE_GROUP_HORIZONTAL + + + + + + + + + + GTK_WIN_POS_CENTER + SteelSeries Sensei Raw control utility + 10 + + FALSE + + GTK_ALIGN_CENTER + GTK_ALIGN_CENTER + 10 + + GTK_ALIGN_CENTER + GTK_ALIGN_CENTER + TRUE + + + Probing the device... + + + + 10 + GTK_ALIGN_CENTER + GTK_ALIGN_CENTER + + No suitable device found. + + + Retry + GTK_ALIGN_CENTER + + + + 10 + + 10 + + + Polling + + + + 200 + 0 + polling_adj + + + + + + + + + + + CPI + 0.5 + + 5 + + 10 + + + LED off + + FALSE + FALSE + + + + 200 + 0 + cpi_off_adj + + TRUE + TRUE + + + + + 10 + + + LED on + + FALSE + FALSE + + + + 200 + 0 + cpi_on_adj + + TRUE + TRUE + + + + + + + Backlight + 0.5 + + 5 + + 10 + + + Pulsation + + FALSE + FALSE + + + + + Steady + Slow + Medium + Fast + + + TRUE + TRUE + + + + + 10 + + + Intensity + + FALSE + FALSE + + + + + Off + Low + Medium + High + + + TRUE + TRUE + + + + + + + + Normal mode + + + Legacy mode + + + gtk-apply + TRUE + 15 + TRUE + + + + + + + diff --git a/sensei-raw-ctl.c b/sensei-raw-ctl.c index 8e0c18b..970c31b 100644 --- a/sensei-raw-ctl.c +++ b/sensei-raw-ctl.c @@ -86,8 +86,8 @@ out: #define USB_VENDOR_STEELSERIES 0x1038 #define USB_PRODUCT_STEELSERIES_SENSEI 0x1369 -#define GET_REPORT 0x01 -#define SET_REPORT 0x09 +#define USB_GET_REPORT 0x01 +#define USB_SET_REPORT 0x09 #define SENSEI_CTL_IFACE 0 @@ -108,7 +108,7 @@ enum sensei_pulsation /* Just guessing the names, could be anything */ enum sensei_mode { - MODE_COMPATIBILITY = 1, + MODE_LEGACY = 1, MODE_NORMAL }; @@ -148,7 +148,7 @@ sensei_send_command (libusb_device_handle *device, { int result = libusb_control_transfer (device, LIBUSB_ENDPOINT_OUT | LIBUSB_REQUEST_TYPE_CLASS | LIBUSB_RECIPIENT_INTERFACE, - SET_REPORT, 0x0200, 0x0000, data, length, 0); + USB_SET_REPORT, 0x0200, 0x0000, data, length, 0); return result < 0 ? result : 0; } @@ -215,7 +215,7 @@ sensei_load_config (libusb_device_handle *device, int result = libusb_control_transfer (device, LIBUSB_ENDPOINT_IN | LIBUSB_REQUEST_TYPE_CLASS | LIBUSB_RECIPIENT_INTERFACE, - GET_REPORT, 0x0300, 0x0000, data, sizeof data, 0); + USB_GET_REPORT, 0x0300, 0x0000, data, sizeof data, 0); if (result < 0) return result; @@ -287,7 +287,7 @@ show_usage (const char *program_name) printf (" --version Show program version and exit\n"); printf (" --show Show current mouse settings and exit\n"); printf (" --mode X Set the mode of the mouse" - " (can be either 'compat' or 'normal')\n"); + " (can be either 'legacy' or 'normal')\n"); printf (" --polling X Set polling to X Hz (1000, 500, 250, 125)\n"); printf (" --cpi-on X Set CPI with the LED on to X\n"); printf (" --cpi-off X Set CPI with the LED off to X\n"); @@ -369,8 +369,8 @@ parse_options (int argc, char *argv[], options->save_to_rom = true; break; case 'm': - if (!strcasecmp (optarg, "compat")) - new_config->mode = MODE_COMPATIBILITY; + if (!strcasecmp (optarg, "legacy")) + new_config->mode = MODE_LEGACY; else if (!strcasecmp (optarg, "normal")) new_config->mode = MODE_NORMAL; else diff --git a/sensei-raw.svg b/sensei-raw.svg new file mode 100644 index 0000000..238a08d --- /dev/null +++ b/sensei-raw.svg @@ -0,0 +1,37 @@ + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +