File indexing completed on 2024-11-10 04:56:32

0001 /*
0002     KWin - the KDE window manager
0003     This file is part of the KDE project.
0004 
0005     SPDX-FileCopyrightText: 2016 Martin Gräßlin <mgraesslin@kde.org>
0006 
0007     SPDX-License-Identifier: GPL-2.0-or-later
0008 */
0009 #include "device.h"
0010 
0011 #include <config-kwin.h>
0012 
0013 #include "core/output.h"
0014 #include "core/outputbackend.h"
0015 #include "libinput_logging.h"
0016 #include "main.h"
0017 #include "mousebuttons.h"
0018 #include "pointer_input.h"
0019 
0020 #include <QDBusArgument>
0021 #include <QDBusConnection>
0022 #include <QDBusMetaType>
0023 
0024 #include <linux/input.h>
0025 
0026 QDBusArgument &operator<<(QDBusArgument &argument, const QMatrix4x4 &matrix)
0027 {
0028     argument.beginArray(qMetaTypeId<double>());
0029     for (quint8 row = 0; row < 4; ++row) {
0030         for (quint8 col = 0; col < 4; ++col) {
0031             argument << matrix(row, col);
0032         }
0033     }
0034     argument.endArray();
0035     return argument;
0036 }
0037 
0038 const QDBusArgument &operator>>(const QDBusArgument &argument, QMatrix4x4 &matrix)
0039 {
0040     argument.beginArray();
0041     for (quint8 row = 0; row < 4; ++row) {
0042         for (quint8 col = 0; col < 4; ++col) {
0043             double val;
0044             argument >> val;
0045             matrix(row, col) = val;
0046         }
0047     }
0048     argument.endArray();
0049     return argument;
0050 }
0051 
0052 namespace KWin
0053 {
0054 namespace LibInput
0055 {
0056 
0057 static bool checkAlphaNumericKeyboard(libinput_device *device)
0058 {
0059     for (uint i = KEY_1; i <= KEY_0; i++) {
0060         if (libinput_device_keyboard_has_key(device, i) == 0) {
0061             return false;
0062         }
0063     }
0064     for (uint i = KEY_Q; i <= KEY_P; i++) {
0065         if (libinput_device_keyboard_has_key(device, i) == 0) {
0066             return false;
0067         }
0068     }
0069     for (uint i = KEY_A; i <= KEY_L; i++) {
0070         if (libinput_device_keyboard_has_key(device, i) == 0) {
0071             return false;
0072         }
0073     }
0074     for (uint i = KEY_Z; i <= KEY_M; i++) {
0075         if (libinput_device_keyboard_has_key(device, i) == 0) {
0076             return false;
0077         }
0078     }
0079     return true;
0080 }
0081 
0082 enum class ConfigKey {
0083     Enabled,
0084     LeftHanded,
0085     DisableWhileTyping,
0086     PointerAcceleration,
0087     PointerAccelerationProfile,
0088     TapToClick,
0089     LmrTapButtonMap,
0090     TapAndDrag,
0091     TapDragLock,
0092     MiddleButtonEmulation,
0093     NaturalScroll,
0094     ScrollMethod,
0095     ScrollButton,
0096     ClickMethod,
0097     ScrollFactor,
0098     Orientation,
0099     Calibration,
0100     OutputName,
0101     OutputArea,
0102     MapToWorkspace
0103 };
0104 
0105 struct ConfigDataBase
0106 {
0107     ConfigDataBase(const QByteArray &_key)
0108         : key(_key)
0109     {
0110     }
0111     virtual ~ConfigDataBase() = default;
0112 
0113     QByteArray key;
0114     virtual void read(Device * /*device*/, const KConfigGroup & /*values*/) const = 0;
0115 };
0116 
0117 template<typename T>
0118 struct ConfigData : public ConfigDataBase
0119 {
0120     using SetterFunction = std::function<void(Device *, const T &)>;
0121     using DefaultValueFunction = std::function<T(Device *)>;
0122 
0123     explicit ConfigData(const QByteArray &_key, const SetterFunction &_setter, const DefaultValueFunction &_defaultValue)
0124         : ConfigDataBase(_key)
0125         , setterFunction(_setter)
0126         , defaultValueFunction(_defaultValue)
0127     {
0128     }
0129 
0130     void read(Device *device, const KConfigGroup &values) const override
0131     {
0132         if (!setterFunction || !defaultValueFunction) {
0133             return;
0134         }
0135 
0136         setterFunction(device, values.readEntry(key.constData(), defaultValueFunction(device)));
0137     }
0138 
0139     SetterFunction setterFunction;
0140     DefaultValueFunction defaultValueFunction;
0141 };
0142 
0143 // Template specializations for some specific config types that can't be handled
0144 // through plain readEntry.
0145 //
0146 // This uses tagged types to avoid specialising the general type since we
0147 // directly call the getters/setters.
0148 
0149 using DeviceOrientation = Qt::ScreenOrientation;
0150 
0151 template<>
0152 struct ConfigData<DeviceOrientation> : public ConfigDataBase
0153 {
0154     explicit ConfigData()
0155         : ConfigDataBase(QByteArrayLiteral("Orientation"))
0156     {
0157     }
0158 
0159     void read(Device *device, const KConfigGroup &values) const override
0160     {
0161         int defaultValue = device->defaultOrientation();
0162         device->setOrientation(static_cast<Qt::ScreenOrientation>(values.readEntry(key.constData(), defaultValue)));
0163     }
0164 };
0165 
0166 using CalibrationMatrix = QMatrix4x4;
0167 
0168 template<>
0169 struct ConfigData<CalibrationMatrix> : public ConfigDataBase
0170 {
0171     explicit ConfigData()
0172         : ConfigDataBase(QByteArrayLiteral("CalibrationMatrix"))
0173     {
0174     }
0175 
0176     void read(Device *device, const KConfigGroup &values) const override
0177     {
0178         if (values.hasKey(key.constData())) {
0179             auto list = values.readEntry(key.constData(), QList<float>());
0180             if (list.size() == 16) {
0181                 device->setCalibrationMatrix(QMatrix4x4{list.constData()});
0182                 return;
0183             }
0184         }
0185 
0186         device->setCalibrationMatrix(device->defaultCalibrationMatrix());
0187     }
0188 };
0189 
0190 static const QMap<ConfigKey, std::shared_ptr<ConfigDataBase>> s_configData{
0191     {ConfigKey::Enabled, std::make_shared<ConfigData<bool>>(QByteArrayLiteral("Enabled"), &Device::setEnabled, &Device::isEnabledByDefault)},
0192     {ConfigKey::LeftHanded, std::make_shared<ConfigData<bool>>(QByteArrayLiteral("LeftHanded"), &Device::setLeftHanded, &Device::leftHandedEnabledByDefault)},
0193     {ConfigKey::DisableWhileTyping, std::make_shared<ConfigData<bool>>(QByteArrayLiteral("DisableWhileTyping"), &Device::setDisableWhileTyping, &Device::disableWhileTypingEnabledByDefault)},
0194     {ConfigKey::PointerAcceleration, std::make_shared<ConfigData<QString>>(QByteArrayLiteral("PointerAcceleration"), &Device::setPointerAccelerationFromString, &Device::defaultPointerAccelerationToString)},
0195     {ConfigKey::PointerAccelerationProfile, std::make_shared<ConfigData<quint32>>(QByteArrayLiteral("PointerAccelerationProfile"), &Device::setPointerAccelerationProfileFromInt, &Device::defaultPointerAccelerationProfileToInt)},
0196     {ConfigKey::TapToClick, std::make_shared<ConfigData<bool>>(QByteArrayLiteral("TapToClick"), &Device::setTapToClick, &Device::tapToClickEnabledByDefault)},
0197     {ConfigKey::TapAndDrag, std::make_shared<ConfigData<bool>>(QByteArrayLiteral("TapAndDrag"), &Device::setTapAndDrag, &Device::tapAndDragEnabledByDefault)},
0198     {ConfigKey::TapDragLock, std::make_shared<ConfigData<bool>>(QByteArrayLiteral("TapDragLock"), &Device::setTapDragLock, &Device::tapDragLockEnabledByDefault)},
0199     {ConfigKey::MiddleButtonEmulation, std::make_shared<ConfigData<bool>>(QByteArrayLiteral("MiddleButtonEmulation"), &Device::setMiddleEmulation, &Device::middleEmulationEnabledByDefault)},
0200     {ConfigKey::LmrTapButtonMap, std::make_shared<ConfigData<bool>>(QByteArrayLiteral("LmrTapButtonMap"), &Device::setLmrTapButtonMap, &Device::lmrTapButtonMapEnabledByDefault)},
0201     {ConfigKey::NaturalScroll, std::make_shared<ConfigData<bool>>(QByteArrayLiteral("NaturalScroll"), &Device::setNaturalScroll, &Device::naturalScrollEnabledByDefault)},
0202     {ConfigKey::ScrollMethod, std::make_shared<ConfigData<quint32>>(QByteArrayLiteral("ScrollMethod"), &Device::activateScrollMethodFromInt, &Device::defaultScrollMethodToInt)},
0203     {ConfigKey::ScrollButton, std::make_shared<ConfigData<quint32>>(QByteArrayLiteral("ScrollButton"), &Device::setScrollButton, &Device::defaultScrollButton)},
0204     {ConfigKey::ClickMethod, std::make_shared<ConfigData<quint32>>(QByteArrayLiteral("ClickMethod"), &Device::setClickMethodFromInt, &Device::defaultClickMethodToInt)},
0205     {ConfigKey::ScrollFactor, std::make_shared<ConfigData<qreal>>(QByteArrayLiteral("ScrollFactor"), &Device::setScrollFactor, &Device::scrollFactorDefault)},
0206     {ConfigKey::Orientation, std::make_shared<ConfigData<DeviceOrientation>>()},
0207     {ConfigKey::Calibration, std::make_shared<ConfigData<CalibrationMatrix>>()},
0208     {ConfigKey::OutputName, std::make_shared<ConfigData<QString>>(QByteArrayLiteral("OutputName"), &Device::setOutputName, &Device::defaultOutputName)},
0209     {ConfigKey::OutputArea, std::make_shared<ConfigData<QRectF>>(QByteArrayLiteral("OutputArea"), &Device::setOutputArea, &Device::defaultOutputArea)},
0210     {ConfigKey::MapToWorkspace, std::make_shared<ConfigData<bool>>(QByteArrayLiteral("MapToWorkspace"), &Device::setMapToWorkspace, &Device::defaultMapToWorkspace)},
0211 };
0212 
0213 namespace
0214 {
0215 QMatrix4x4 getMatrix(libinput_device *device, std::function<int(libinput_device *, float[6])> getter)
0216 {
0217     float matrix[6];
0218     if (!getter(device, matrix)) {
0219         return {};
0220     }
0221     return QMatrix4x4{
0222         matrix[0], matrix[1], matrix[2], 0.0f,
0223         matrix[3], matrix[4], matrix[5], 0.0f,
0224         0.0f, 0.0f, 1.0f, 0.0f,
0225         0.0f, 0.0f, 0.0f, 1.0f};
0226 }
0227 
0228 bool setOrientedCalibrationMatrix(libinput_device *device, QMatrix4x4 matrix, Qt::ScreenOrientation orientation)
0229 {
0230     // 90 deg cw
0231     static const QMatrix4x4 portraitMatrix{
0232         0.0f, -1.0f, 1.0f, 0.0f,
0233         1.0f, 0.0f, 0.0f, 0.0f,
0234         0.0f, 0.0f, 1.0f, 0.0f,
0235         0.0f, 0.0f, 0.0f, 1.0f};
0236     // 180 deg cw
0237     static const QMatrix4x4 invertedLandscapeMatrix{
0238         -1.0f, 0.0f, 1.0f, 0.0f,
0239         0.0f, -1.0f, 1.0f, 0.0f,
0240         0.0f, 0.0f, 1.0f, 0.0f,
0241         0.0f, 0.0f, 0.0f, 1.0f};
0242     // 270 deg cw
0243     static const QMatrix4x4 invertedPortraitMatrix{
0244         0.0f, 1.0f, 0.0f, 0.0f,
0245         -1.0f, 0.0f, 1.0f, 0.0f,
0246         0.0f, 0.0f, 1.0f, 0.0f,
0247         0.0f, 0.0f, 0.0f, 1.0f};
0248 
0249     switch (orientation) {
0250     case Qt::PortraitOrientation:
0251         matrix *= portraitMatrix;
0252         break;
0253     case Qt::InvertedLandscapeOrientation:
0254         matrix *= invertedLandscapeMatrix;
0255         break;
0256     case Qt::InvertedPortraitOrientation:
0257         matrix *= invertedPortraitMatrix;
0258         break;
0259     case Qt::PrimaryOrientation:
0260     case Qt::LandscapeOrientation:
0261     default:
0262         break;
0263     }
0264 
0265     float data[6]{matrix(0, 0), matrix(0, 1), matrix(0, 2), matrix(1, 0), matrix(1, 1), matrix(1, 2)};
0266     return libinput_device_config_calibration_set_matrix(device, data) == LIBINPUT_CONFIG_STATUS_SUCCESS;
0267 }
0268 }
0269 
0270 Device::Device(libinput_device *device, QObject *parent)
0271     : InputDevice(parent)
0272     , m_device(device)
0273     , m_keyboard(libinput_device_has_capability(m_device, LIBINPUT_DEVICE_CAP_KEYBOARD))
0274     , m_pointer(libinput_device_has_capability(m_device, LIBINPUT_DEVICE_CAP_POINTER))
0275     , m_touch(libinput_device_has_capability(m_device, LIBINPUT_DEVICE_CAP_TOUCH))
0276     , m_tabletTool(libinput_device_has_capability(m_device, LIBINPUT_DEVICE_CAP_TABLET_TOOL))
0277     , m_tabletPad(libinput_device_has_capability(m_device, LIBINPUT_DEVICE_CAP_TABLET_PAD))
0278     , m_supportsGesture(libinput_device_has_capability(m_device, LIBINPUT_DEVICE_CAP_GESTURE))
0279     , m_switch(libinput_device_has_capability(m_device, LIBINPUT_DEVICE_CAP_SWITCH))
0280     , m_lidSwitch(m_switch ? libinput_device_switch_has_switch(m_device, LIBINPUT_SWITCH_LID) : false)
0281     , m_tabletSwitch(m_switch ? libinput_device_switch_has_switch(m_device, LIBINPUT_SWITCH_TABLET_MODE) : false)
0282     , m_name(QString::fromLocal8Bit(libinput_device_get_name(m_device)))
0283     , m_sysName(QString::fromLocal8Bit(libinput_device_get_sysname(m_device)))
0284     , m_outputName(QString::fromLocal8Bit(libinput_device_get_output_name(m_device)))
0285     , m_product(libinput_device_get_id_product(m_device))
0286     , m_vendor(libinput_device_get_id_vendor(m_device))
0287     , m_tapFingerCount(libinput_device_config_tap_get_finger_count(m_device))
0288     , m_defaultTapButtonMap(libinput_device_config_tap_get_default_button_map(m_device))
0289     , m_tapButtonMap(libinput_device_config_tap_get_button_map(m_device))
0290     , m_tapToClickEnabledByDefault(true)
0291     , m_tapToClick(libinput_device_config_tap_get_enabled(m_device))
0292     , m_tapAndDragEnabledByDefault(true)
0293     , m_tapAndDrag(libinput_device_config_tap_get_drag_enabled(m_device))
0294     , m_tapDragLockEnabledByDefault(libinput_device_config_tap_get_default_drag_lock_enabled(m_device))
0295     , m_tapDragLock(libinput_device_config_tap_get_drag_lock_enabled(m_device))
0296     , m_supportsDisableWhileTyping(libinput_device_config_dwt_is_available(m_device))
0297     , m_supportsPointerAcceleration(libinput_device_config_accel_is_available(m_device))
0298     , m_supportsLeftHanded(libinput_device_config_left_handed_is_available(m_device))
0299     , m_supportsCalibrationMatrix(libinput_device_config_calibration_has_matrix(m_device))
0300     , m_supportsDisableEvents(libinput_device_config_send_events_get_modes(m_device) & LIBINPUT_CONFIG_SEND_EVENTS_DISABLED)
0301     , m_supportsDisableEventsOnExternalMouse(libinput_device_config_send_events_get_modes(m_device) & LIBINPUT_CONFIG_SEND_EVENTS_DISABLED_ON_EXTERNAL_MOUSE)
0302     , m_supportsMiddleEmulation(libinput_device_config_middle_emulation_is_available(m_device))
0303     , m_supportsNaturalScroll(libinput_device_config_scroll_has_natural_scroll(m_device))
0304     , m_supportedScrollMethods(libinput_device_config_scroll_get_methods(m_device))
0305     , m_leftHandedEnabledByDefault(libinput_device_config_left_handed_get_default(m_device))
0306     , m_middleEmulationEnabledByDefault(libinput_device_config_middle_emulation_get_default_enabled(m_device) == LIBINPUT_CONFIG_MIDDLE_EMULATION_ENABLED)
0307     , m_naturalScrollEnabledByDefault(libinput_device_config_scroll_get_default_natural_scroll_enabled(m_device))
0308     , m_defaultScrollMethod(libinput_device_config_scroll_get_default_method(m_device))
0309     , m_defaultScrollButton(libinput_device_config_scroll_get_default_button(m_device))
0310     , m_disableWhileTypingEnabledByDefault(libinput_device_config_dwt_get_default_enabled(m_device))
0311     , m_disableWhileTyping(m_supportsDisableWhileTyping ? libinput_device_config_dwt_get_enabled(m_device) == LIBINPUT_CONFIG_DWT_ENABLED : false)
0312     , m_middleEmulation(libinput_device_config_middle_emulation_get_enabled(m_device) == LIBINPUT_CONFIG_MIDDLE_EMULATION_ENABLED)
0313     , m_leftHanded(m_supportsLeftHanded ? libinput_device_config_left_handed_get(m_device) : false)
0314     , m_naturalScroll(m_supportsNaturalScroll ? libinput_device_config_scroll_get_natural_scroll_enabled(m_device) : false)
0315     , m_scrollMethod(libinput_device_config_scroll_get_method(m_device))
0316     , m_scrollButton(libinput_device_config_scroll_get_button(m_device))
0317     , m_defaultPointerAcceleration(libinput_device_config_accel_get_default_speed(m_device))
0318     , m_pointerAcceleration(libinput_device_config_accel_get_speed(m_device))
0319     , m_scrollFactor(1.0)
0320     , m_supportedPointerAccelerationProfiles(libinput_device_config_accel_get_profiles(m_device))
0321     , m_defaultPointerAccelerationProfile(libinput_device_config_accel_get_default_profile(m_device))
0322     , m_pointerAccelerationProfile(libinput_device_config_accel_get_profile(m_device))
0323     , m_enabled(m_supportsDisableEvents ? libinput_device_config_send_events_get_mode(m_device) == LIBINPUT_CONFIG_SEND_EVENTS_ENABLED : true)
0324     , m_config()
0325     , m_defaultCalibrationMatrix(getMatrix(m_device, &libinput_device_config_calibration_get_default_matrix))
0326     , m_calibrationMatrix(getMatrix(m_device, &libinput_device_config_calibration_get_matrix))
0327     , m_supportedClickMethods(libinput_device_config_click_get_methods(m_device))
0328     , m_defaultClickMethod(libinput_device_config_click_get_default_method(m_device))
0329     , m_clickMethod(libinput_device_config_click_get_method(m_device))
0330 {
0331     libinput_device_ref(m_device);
0332     libinput_device_set_user_data(m_device, this);
0333 
0334     qreal width = 0;
0335     qreal height = 0;
0336     if (libinput_device_get_size(m_device, &width, &height) == 0) {
0337         m_size = QSizeF(width, height);
0338     }
0339     if (m_pointer) {
0340         // 0x120 is the first joystick Button
0341         for (int button = BTN_LEFT; button < 0x120; ++button) {
0342             if (libinput_device_pointer_has_button(m_device, button)) {
0343                 m_supportedButtons |= buttonToQtMouseButton(button);
0344             }
0345         }
0346     }
0347 
0348     if (m_keyboard) {
0349         m_alphaNumericKeyboard = checkAlphaNumericKeyboard(m_device);
0350     }
0351 
0352     if (m_supportsCalibrationMatrix && m_calibrationMatrix != m_defaultCalibrationMatrix) {
0353         float matrix[]{m_defaultCalibrationMatrix(0, 0),
0354                        m_defaultCalibrationMatrix(0, 1),
0355                        m_defaultCalibrationMatrix(0, 2),
0356                        m_defaultCalibrationMatrix(1, 0),
0357                        m_defaultCalibrationMatrix(1, 1),
0358                        m_defaultCalibrationMatrix(1, 2)};
0359         libinput_device_config_calibration_set_matrix(m_device, matrix);
0360         m_calibrationMatrix = m_defaultCalibrationMatrix;
0361     }
0362 
0363     qDBusRegisterMetaType<QMatrix4x4>();
0364 
0365     QDBusConnection::sessionBus().registerObject(QStringLiteral("/org/kde/KWin/InputDevice/") + m_sysName,
0366                                                  QStringLiteral("org.kde.KWin.InputDevice"),
0367                                                  this,
0368                                                  QDBusConnection::ExportAllProperties);
0369 }
0370 
0371 Device::~Device()
0372 {
0373     QDBusConnection::sessionBus().unregisterObject(QStringLiteral("/org/kde/KWin/InputDevice/") + m_sysName);
0374     libinput_device_set_user_data(m_device, nullptr);
0375     libinput_device_unref(m_device);
0376 }
0377 
0378 Device *Device::get(libinput_device *native)
0379 {
0380     return static_cast<Device *>(libinput_device_get_user_data(native));
0381 }
0382 
0383 template<typename T>
0384 void Device::writeEntry(const ConfigKey &key, const T &value)
0385 {
0386     if (!m_config.isValid()) {
0387         return;
0388     }
0389     if (m_loading) {
0390         return;
0391     }
0392     auto it = s_configData.find(key);
0393     Q_ASSERT(it != s_configData.end());
0394     m_config.writeEntry(it.value()->key.constData(), value);
0395     m_config.sync();
0396 }
0397 
0398 void Device::loadConfiguration()
0399 {
0400     if (!m_config.isValid() && !m_defaultConfig.isValid()) {
0401         return;
0402     }
0403 
0404     m_loading = true;
0405     for (auto it = s_configData.begin(), end = s_configData.end(); it != end; ++it) {
0406         (*it)->read(this, m_config);
0407     };
0408 
0409     m_loading = false;
0410 }
0411 
0412 void Device::setPointerAcceleration(qreal acceleration)
0413 {
0414     if (!m_supportsPointerAcceleration) {
0415         return;
0416     }
0417     acceleration = std::clamp(acceleration, -1.0, 1.0);
0418     if (libinput_device_config_accel_set_speed(m_device, acceleration) == LIBINPUT_CONFIG_STATUS_SUCCESS) {
0419         if (m_pointerAcceleration != acceleration) {
0420             m_pointerAcceleration = acceleration;
0421             Q_EMIT pointerAccelerationChanged();
0422             writeEntry(ConfigKey::PointerAcceleration, QString::number(acceleration, 'f', 3));
0423         }
0424     }
0425 }
0426 
0427 void Device::setScrollButton(quint32 button)
0428 {
0429     if (!(m_supportedScrollMethods & LIBINPUT_CONFIG_SCROLL_ON_BUTTON_DOWN)) {
0430         return;
0431     }
0432     if (libinput_device_config_scroll_set_button(m_device, button) == LIBINPUT_CONFIG_STATUS_SUCCESS) {
0433         if (m_scrollButton != button) {
0434             m_scrollButton = button;
0435             writeEntry(ConfigKey::ScrollButton, m_scrollButton);
0436             Q_EMIT scrollButtonChanged();
0437         }
0438     }
0439 }
0440 
0441 void Device::setPointerAccelerationProfile(bool set, enum libinput_config_accel_profile profile)
0442 {
0443     if (!(m_supportedPointerAccelerationProfiles & profile)) {
0444         return;
0445     }
0446     if (!set) {
0447         profile = (profile == LIBINPUT_CONFIG_ACCEL_PROFILE_FLAT) ? LIBINPUT_CONFIG_ACCEL_PROFILE_ADAPTIVE : LIBINPUT_CONFIG_ACCEL_PROFILE_FLAT;
0448         if (!(m_supportedPointerAccelerationProfiles & profile)) {
0449             return;
0450         }
0451     }
0452 
0453     if (libinput_device_config_accel_set_profile(m_device, profile) == LIBINPUT_CONFIG_STATUS_SUCCESS) {
0454         if (m_pointerAccelerationProfile != profile) {
0455             m_pointerAccelerationProfile = profile;
0456             Q_EMIT pointerAccelerationProfileChanged();
0457             writeEntry(ConfigKey::PointerAccelerationProfile, (quint32)profile);
0458         }
0459     }
0460 }
0461 
0462 void Device::setClickMethod(bool set, enum libinput_config_click_method method)
0463 {
0464     if (!(m_supportedClickMethods & method)) {
0465         return;
0466     }
0467     if (!set) {
0468         method = (method == LIBINPUT_CONFIG_CLICK_METHOD_BUTTON_AREAS) ? LIBINPUT_CONFIG_CLICK_METHOD_CLICKFINGER : LIBINPUT_CONFIG_CLICK_METHOD_BUTTON_AREAS;
0469         if (!(m_supportedClickMethods & method)) {
0470             return;
0471         }
0472     }
0473 
0474     if (libinput_device_config_click_set_method(m_device, method) == LIBINPUT_CONFIG_STATUS_SUCCESS) {
0475         if (m_clickMethod != method) {
0476             m_clickMethod = method;
0477             Q_EMIT clickMethodChanged();
0478             writeEntry(ConfigKey::ClickMethod, (quint32)method);
0479         }
0480     }
0481 }
0482 
0483 void Device::setScrollMethod(bool set, enum libinput_config_scroll_method method)
0484 {
0485     if (!(m_supportedScrollMethods & method)) {
0486         return;
0487     }
0488 
0489     bool isCurrent = m_scrollMethod == method;
0490     if (!set) {
0491         if (isCurrent) {
0492             method = LIBINPUT_CONFIG_SCROLL_NO_SCROLL;
0493             isCurrent = false;
0494         } else {
0495             return;
0496         }
0497     }
0498 
0499     if (libinput_device_config_scroll_set_method(m_device, method) == LIBINPUT_CONFIG_STATUS_SUCCESS) {
0500         if (!isCurrent) {
0501             m_scrollMethod = method;
0502             Q_EMIT scrollMethodChanged();
0503             writeEntry(ConfigKey::ScrollMethod, (quint32)method);
0504         }
0505     }
0506 }
0507 
0508 void Device::setLmrTapButtonMap(bool set)
0509 {
0510     enum libinput_config_tap_button_map map = set ? LIBINPUT_CONFIG_TAP_MAP_LMR : LIBINPUT_CONFIG_TAP_MAP_LRM;
0511 
0512     if (m_tapFingerCount < 2) {
0513         return;
0514     }
0515     if (!set) {
0516         map = LIBINPUT_CONFIG_TAP_MAP_LRM;
0517     }
0518 
0519     if (libinput_device_config_tap_set_button_map(m_device, map) == LIBINPUT_CONFIG_STATUS_SUCCESS) {
0520         if (m_tapButtonMap != map) {
0521             m_tapButtonMap = map;
0522             writeEntry(ConfigKey::LmrTapButtonMap, set);
0523             Q_EMIT tapButtonMapChanged();
0524         }
0525     }
0526 }
0527 
0528 int Device::stripsCount() const
0529 {
0530     return libinput_device_tablet_pad_get_num_strips(m_device);
0531 }
0532 
0533 int Device::ringsCount() const
0534 {
0535     return libinput_device_tablet_pad_get_num_rings(m_device);
0536 }
0537 
0538 void *Device::groupUserData() const
0539 {
0540     auto deviceGroup = libinput_device_get_device_group(m_device);
0541     return libinput_device_group_get_user_data(deviceGroup);
0542 }
0543 
0544 #define CONFIG(method, condition, function, variable, key)                                        \
0545     void Device::method(bool set)                                                                 \
0546     {                                                                                             \
0547         if (condition) {                                                                          \
0548             return;                                                                               \
0549         }                                                                                         \
0550         if (libinput_device_config_##function(m_device, set) == LIBINPUT_CONFIG_STATUS_SUCCESS) { \
0551             if (m_##variable != set) {                                                            \
0552                 m_##variable = set;                                                               \
0553                 writeEntry(ConfigKey::key, m_##variable);                                         \
0554                 Q_EMIT variable##Changed();                                                       \
0555             }                                                                                     \
0556         }                                                                                         \
0557     }
0558 
0559 CONFIG(setLeftHanded, !m_supportsLeftHanded, left_handed_set, leftHanded, LeftHanded)
0560 CONFIG(setNaturalScroll, !m_supportsNaturalScroll, scroll_set_natural_scroll_enabled, naturalScroll, NaturalScroll)
0561 
0562 #undef CONFIG
0563 
0564 #define CONFIG(method, condition, function, enum, variable, key)                                                                                                         \
0565     void Device::method(bool set)                                                                                                                                        \
0566     {                                                                                                                                                                    \
0567         if (condition) {                                                                                                                                                 \
0568             return;                                                                                                                                                      \
0569         }                                                                                                                                                                \
0570         if (libinput_device_config_##function(m_device, set ? LIBINPUT_CONFIG_##enum##_ENABLED : LIBINPUT_CONFIG_##enum##_DISABLED) == LIBINPUT_CONFIG_STATUS_SUCCESS) { \
0571             if (m_##variable != set) {                                                                                                                                   \
0572                 m_##variable = set;                                                                                                                                      \
0573                 writeEntry(ConfigKey::key, m_##variable);                                                                                                                \
0574                 Q_EMIT variable##Changed();                                                                                                                              \
0575             }                                                                                                                                                            \
0576         }                                                                                                                                                                \
0577     }
0578 
0579 CONFIG(setEnabled, !m_supportsDisableEvents, send_events_set_mode, SEND_EVENTS, enabled, Enabled)
0580 CONFIG(setDisableWhileTyping, !m_supportsDisableWhileTyping, dwt_set_enabled, DWT, disableWhileTyping, DisableWhileTyping)
0581 CONFIG(setTapToClick, m_tapFingerCount == 0, tap_set_enabled, TAP, tapToClick, TapToClick)
0582 CONFIG(setTapAndDrag, false, tap_set_drag_enabled, DRAG, tapAndDrag, TapAndDrag)
0583 CONFIG(setTapDragLock, false, tap_set_drag_lock_enabled, DRAG_LOCK, tapDragLock, TapDragLock)
0584 CONFIG(setMiddleEmulation, m_supportsMiddleEmulation == false, middle_emulation_set_enabled, MIDDLE_EMULATION, middleEmulation, MiddleButtonEmulation)
0585 
0586 #undef CONFIG
0587 
0588 void Device::setScrollFactor(qreal factor)
0589 {
0590     if (m_scrollFactor != factor) {
0591         m_scrollFactor = factor;
0592         writeEntry(ConfigKey::ScrollFactor, m_scrollFactor);
0593         Q_EMIT scrollFactorChanged();
0594     }
0595 }
0596 
0597 void Device::setCalibrationMatrix(const QMatrix4x4 &matrix)
0598 {
0599     if (!m_supportsCalibrationMatrix || m_calibrationMatrix == matrix) {
0600         return;
0601     }
0602 
0603     if (setOrientedCalibrationMatrix(m_device, matrix, m_orientation)) {
0604         QList<float> list;
0605         list.reserve(16);
0606         for (uchar row = 0; row < 4; ++row) {
0607             for (uchar col = 0; col < 4; ++col) {
0608                 list << matrix(row, col);
0609             }
0610         }
0611         writeEntry(ConfigKey::Calibration, list);
0612         m_calibrationMatrix = matrix;
0613         Q_EMIT calibrationMatrixChanged();
0614     }
0615 }
0616 
0617 void Device::setOrientation(Qt::ScreenOrientation orientation)
0618 {
0619     if (!m_supportsCalibrationMatrix || m_orientation == orientation) {
0620         return;
0621     }
0622 
0623     if (setOrientedCalibrationMatrix(m_device, m_calibrationMatrix, orientation)) {
0624         writeEntry(ConfigKey::Orientation, static_cast<int>(orientation));
0625         m_orientation = orientation;
0626         Q_EMIT orientationChanged();
0627     }
0628 }
0629 
0630 void Device::setOutputName(const QString &name)
0631 {
0632 #ifndef KWIN_BUILD_TESTING
0633     if (name == m_outputName) {
0634         return;
0635     }
0636 
0637     setOutput(nullptr);
0638     auto outputs = kwinApp()->outputBackend()->outputs();
0639     for (int i = 0; i < outputs.count(); ++i) {
0640         if (!outputs[i]->isEnabled()) {
0641             continue;
0642         }
0643         if (outputs[i]->name() == name) {
0644             setOutput(outputs[i]);
0645             break;
0646         }
0647     }
0648 
0649     m_outputName = name;
0650     writeEntry(ConfigKey::OutputName, name);
0651     Q_EMIT outputNameChanged();
0652 #endif
0653 }
0654 
0655 Output *Device::output() const
0656 {
0657     return m_output;
0658 }
0659 
0660 void Device::setOutput(Output *output)
0661 {
0662     m_output = output;
0663 }
0664 
0665 static libinput_led toLibinputLEDS(LEDs leds)
0666 {
0667     quint32 libinputLeds = 0;
0668     if (leds.testFlag(LED::NumLock)) {
0669         libinputLeds = libinputLeds | LIBINPUT_LED_NUM_LOCK;
0670     }
0671     if (leds.testFlag(LED::CapsLock)) {
0672         libinputLeds = libinputLeds | LIBINPUT_LED_CAPS_LOCK;
0673     }
0674     if (leds.testFlag(LED::ScrollLock)) {
0675         libinputLeds = libinputLeds | LIBINPUT_LED_SCROLL_LOCK;
0676     }
0677     return libinput_led(libinputLeds);
0678 }
0679 
0680 LEDs Device::leds() const
0681 {
0682     return m_leds;
0683 }
0684 
0685 void Device::setLeds(LEDs leds)
0686 {
0687     if (m_leds != leds) {
0688         m_leds = leds;
0689         libinput_device_led_update(m_device, toLibinputLEDS(m_leds));
0690     }
0691 }
0692 
0693 bool Device::supportsOutputArea() const
0694 {
0695     return m_tabletTool;
0696 }
0697 
0698 QRectF Device::defaultOutputArea() const
0699 {
0700     return QRectF(0, 0, 1, 1);
0701 }
0702 
0703 QRectF Device::outputArea() const
0704 {
0705     return m_outputArea;
0706 }
0707 
0708 void Device::setOutputArea(const QRectF &outputArea)
0709 {
0710     if (m_outputArea != outputArea) {
0711         m_outputArea = outputArea;
0712         writeEntry(ConfigKey::OutputArea, m_outputArea);
0713         Q_EMIT outputAreaChanged();
0714     }
0715 }
0716 
0717 void Device::setMapToWorkspace(bool mapToWorkspace)
0718 {
0719     if (m_mapToWorkspace != mapToWorkspace) {
0720         m_mapToWorkspace = mapToWorkspace;
0721         writeEntry(ConfigKey::MapToWorkspace, m_mapToWorkspace);
0722         Q_EMIT mapToWorkspaceChanged();
0723     }
0724 }
0725 }
0726 }
0727 
0728 #include "moc_device.cpp"