diff --git a/src/common/libwacomwrapper.cpp b/src/common/libwacomwrapper.cpp index 2e86fd7..f354856 100644 --- a/src/common/libwacomwrapper.cpp +++ b/src/common/libwacomwrapper.cpp @@ -1,201 +1,222 @@ /* * This file is part of the KDE wacomtablet project. For copyright * information and license terms see the AUTHORS and COPYING files * in the top-level directory of this distribution. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of * the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "libwacomwrapper.h" #include "logging.h" #include extern "C" { #include } namespace Wacom { static int skipWheelButtons(int button) { // skip buttons 4-7, which correspond to vertical/horizontal wheel up/down events if (button > 3) { return button + 4; } else { return button; } } #ifndef LIBWACOM_EVDEV_MISSING static int convertEvdevToXsetwacomButton(int evdevCode); #endif // LIBWACOM_EVDEV_MISSING libWacomWrapper::libWacomWrapper() { db = libwacom_database_new(); } libWacomWrapper &libWacomWrapper::instance() { static libWacomWrapper instance; return instance; } libWacomWrapper::~libWacomWrapper() { libwacom_database_destroy(db); } bool libWacomWrapper::lookupTabletInfo(int tabletId, int vendorId, TabletInformation &tabletInfo) { qCDebug(COMMON) << "LibWacom lookup for" << tabletId << vendorId; auto errorDeleter = [](WacomError *&e){libwacom_error_free(&e);}; std::unique_ptr error(libwacom_error_new(), errorDeleter); std::unique_ptr device(libwacom_new_from_usbid(db, vendorId, tabletId, error.get()), &libwacom_destroy); if (!device) { qCInfo(COMMON) << "LibWacom lookup failed:" << libwacom_error_get_message(error.get()); return false; } // TODO: libWacom returned button layouts don't make much sense (yet) // because they use letters instead of numbers const auto layoutFileName = libwacom_get_layout_filename(device.get()); if (layoutFileName) { tabletInfo.set(TabletInfo::ButtonLayout, QString::fromLatin1(layoutFileName)); } // Seems like there is no model or vendor names in libwacom // TODO: are these properties even used anywhere? tabletInfo.set(TabletInfo::CompanyName, QString()); tabletInfo.set(TabletInfo::TabletModel, QString()); // TODO: Seems like there's no info about the pad wheel in libwacom // Only a couple of tablets have the wheel anyway, so it probably can be hacked around tabletInfo.set(TabletInfo::HasWheel, false); // TODO: Returns more detailed information than we expect, // current LED code is broken anyway so this should be untangled later - tabletInfo.set(TabletInfo::StatusLEDs, 0); + int numStatusLeds = 0; + int numLedGroups; + const WacomStatusLEDs *ledGroups = libwacom_get_status_leds(device.get(), &numLedGroups); + for (int i = 0; i < numLedGroups; i++) { + int groupModes = 0; + switch (ledGroups[i]) { + case WACOM_STATUS_LED_RING: + groupModes = libwacom_get_ring_num_modes(device.get()); + break; + case WACOM_STATUS_LED_RING2: + groupModes = libwacom_get_ring2_num_modes(device.get()); + break; + case WACOM_STATUS_LED_TOUCHSTRIP: + groupModes = libwacom_get_strips_num_modes(device.get()); + break; + case WACOM_STATUS_LED_TOUCHSTRIP2: + groupModes = libwacom_get_strips_num_modes(device.get()); + break; + } + numStatusLeds += groupModes; + } + tabletInfo.set(TabletInfo::StatusLEDs, numStatusLeds); tabletInfo.set(TabletInfo::TabletName, QString::fromLatin1(libwacom_get_name(device.get()))); const int padButtonNumber = libwacom_get_num_buttons(device.get()); tabletInfo.set(TabletInfo::NumPadButtons, padButtonNumber); // Convert button evdev codes to buttonMap if (libwacom_get_num_buttons(device.get()) > 0) { QMap buttonMapping; for (char i = 1; i < padButtonNumber + 1; ++i) { #ifdef LIBWACOM_EVDEV_MISSING // TODO: warn the user in the KCM too qCWarning(COMMON) << "Your libwacom version is too old. We will try and guess button mapping, " << "but it's going to be broken for quirky tablets. Paired device detection is going to be broken as well." << "Use kde_wacomtablet_finder to configure your device instead."; const int buttonIndex = skipWheelButtons(i); buttonMapping[QString::number(i)] = QString::number(buttonIndex); #else const char buttonChar = 'A' + (i - 1); // libwacom marks buttons as 'A', 'B', 'C'... const int buttonEvdevCode = libwacom_get_button_evdev_code(device.get(), buttonChar); const int buttonIndex = convertEvdevToXsetwacomButton(buttonEvdevCode); buttonMapping[QString::number(i)] = QString::number(buttonIndex); if (buttonIndex < 1) { qCWarning(COMMON) << "Unrecognized evdev code. " << "Device:" << tabletId << "Vendor:" << vendorId << "Button:" << buttonChar << "EvdevCode:" << buttonEvdevCode; return false; } #endif } tabletInfo.setButtonMap(buttonMapping); } #ifndef LIBWACOM_EVDEV_MISSING const WacomMatch* paired_device_match = libwacom_get_paired_device(device.get()); if (paired_device_match) { const std::uint32_t pairedTabletId = libwacom_match_get_product_id(paired_device_match); const std::uint32_t pairedVendorId = libwacom_match_get_vendor_id(paired_device_match); const auto pairedDeviceID = QString::number(pairedTabletId, 16); tabletInfo.set(TabletInfo::TouchSensorId, pairedDeviceID); qCDebug(COMMON) << "Libwacom reported a paired device" << pairedTabletId << pairedVendorId << pairedDeviceID; } #endif const int numStrips = libwacom_get_num_strips(device.get()); const bool hasLeftStrip = numStrips > 0; const bool hasRightStrip = numStrips > 1; const bool hasRing = libwacom_has_ring(device.get()) != 0; tabletInfo.set(TabletInfo::HasLeftTouchStrip, hasLeftStrip); tabletInfo.set(TabletInfo::HasRightTouchStrip, hasRightStrip); tabletInfo.set(TabletInfo::HasTouchRing, hasRing); return true; } #ifndef LIBWACOM_EVDEV_MISSING static int convertMouseEvdevToXsetwacomButton(int evdevCode) { // some quirky consumer tablets, e.g. Bamboo/Graphire, use mouse button events // instead of just numbered express keys. Translate them back to numbers static const int BTN_LEFT = 0x110; static const int BTN_RIGHT = 0x111; static const int BTN_MIDDLE = 0x112; static const int BTN_FORWARD = 0x115; static const int BTN_BACK = 0x116; switch (evdevCode) { case BTN_LEFT: return 1; case BTN_RIGHT: return 3; case BTN_MIDDLE: return 2; case BTN_FORWARD: return 9; case BTN_BACK: return 8; default: return 0; } } static int convertEvdevToXsetwacomButton(int evdevCode) { // based on set_button_codes_from_heuristics from libwacom/libwacom-database.c static const int BTN_MISC = 0x100; static const int BTN_MOUSE = 0x110; static const int BTN_BASE = 0x126; static const int BTN_GAMEPAD = 0x130; int translatedCode = 0; if (evdevCode >= BTN_GAMEPAD) { translatedCode = evdevCode - BTN_GAMEPAD + 10; } else if (evdevCode >= BTN_BASE) { translatedCode = evdevCode - BTN_BASE + 16; } else if (evdevCode >= BTN_MOUSE) { return convertMouseEvdevToXsetwacomButton(evdevCode); } else if (evdevCode >= BTN_MISC) { translatedCode = evdevCode - BTN_MISC; } else { return 0; } return skipWheelButtons(translatedCode + 1); } #endif // LIBWACOM_EVDEV_MISSING } // namespace ends