diff --git a/autotests/libinput/device_test.cpp b/autotests/libinput/device_test.cpp --- a/autotests/libinput/device_test.cpp +++ b/autotests/libinput/device_test.cpp @@ -54,6 +54,10 @@ void testDefaultPointerAccelerationProfileFlat(); void testDefaultPointerAccelerationProfileAdaptive_data(); void testDefaultPointerAccelerationProfileAdaptive(); + void testDefaultClickMethodAreas_data(); + void testDefaultClickMethodAreas(); + void testDefaultClickMethodClickfinger_data(); + void testDefaultClickMethodClickfinger(); void testLeftHandedEnabledByDefault_data(); void testLeftHandedEnabledByDefault(); void testTapEnabledByDefault_data(); @@ -138,6 +142,8 @@ void testLoadPointerAcceleration(); void testLoadPointerAccelerationProfile_data(); void testLoadPointerAccelerationProfile(); + void testLoadClickMethod_data(); + void testLoadClickMethod(); void testLoadTapToClick_data(); void testLoadTapToClick(); void testLoadTapAndDrag_data(); @@ -554,6 +560,46 @@ QCOMPARE(dbusProperty(d.sysName(), "defaultPointerAccelerationProfileAdaptive"), enabled); } +void TestLibinputDevice::testDefaultClickMethodAreas_data() +{ + QTest::addColumn("enabled"); + + QTest::addRow("enabled") << true; + QTest::addRow("disabled") << false; +} + +void TestLibinputDevice::testDefaultClickMethodAreas() +{ + QFETCH(bool, enabled); + libinput_device device; + device.defaultClickMethod = enabled ? LIBINPUT_CONFIG_CLICK_METHOD_BUTTON_AREAS : LIBINPUT_CONFIG_CLICK_METHOD_CLICKFINGER; + + Device d(&device); + QCOMPARE(d.defaultClickMethodAreas(), enabled); + QCOMPARE(d.property("defaultClickMethodAreas").toBool(), enabled); + QCOMPARE(dbusProperty(d.sysName(), "defaultClickMethodAreas"), enabled); +} + +void TestLibinputDevice::testDefaultClickMethodClickfinger_data() +{ + QTest::addColumn("enabled"); + + QTest::addRow("enabled") << true; + QTest::addRow("disabled") << false; +} + +void TestLibinputDevice::testDefaultClickMethodClickfinger() +{ + QFETCH(bool, enabled); + libinput_device device; + device.defaultClickMethod = enabled ? LIBINPUT_CONFIG_CLICK_METHOD_CLICKFINGER : LIBINPUT_CONFIG_CLICK_METHOD_BUTTON_AREAS; + + Device d(&device); + QCOMPARE(d.defaultClickMethodClickfinger(), enabled); + QCOMPARE(d.property("defaultClickMethodClickfinger").toBool(), enabled); + QCOMPARE(dbusProperty(d.sysName(), "defaultClickMethodClickfinger"), enabled); +} + void TestLibinputDevice::testScrollOnButtonDownEnabledByDefault_data() { QTest::addColumn("enabled"); @@ -1770,6 +1816,69 @@ } } +void TestLibinputDevice::testLoadClickMethod_data() +{ + QTest::addColumn("initValue"); + QTest::addColumn("initValuePropNameString"); + QTest::addColumn("configValue"); + QTest::addColumn("configValuePropNameString"); + + QTest::newRow("clickMethodAreas -> clickMethodClickfinger") + << static_cast(LIBINPUT_CONFIG_CLICK_METHOD_BUTTON_AREAS) << "clickMethodAreas" + << static_cast(LIBINPUT_CONFIG_CLICK_METHOD_CLICKFINGER) << "clickMethodClickfinger"; + QTest::newRow("clickMethodClickfinger -> clickMethodAreas") + << static_cast(LIBINPUT_CONFIG_CLICK_METHOD_CLICKFINGER) << "clickMethodClickfinger" + << static_cast(LIBINPUT_CONFIG_CLICK_METHOD_BUTTON_AREAS) << "clickMethodAreas"; + QTest::newRow("clickMethodAreas -> clickMethodAreas") + << static_cast(LIBINPUT_CONFIG_CLICK_METHOD_BUTTON_AREAS) << "clickMethodAreas" + << static_cast(LIBINPUT_CONFIG_CLICK_METHOD_BUTTON_AREAS) << "clickMethodAreas"; + QTest::newRow("clickMethodClickfinger -> clickMethodClickfinger") + << static_cast(LIBINPUT_CONFIG_CLICK_METHOD_CLICKFINGER) << "clickMethodClickfinger" + << static_cast(LIBINPUT_CONFIG_CLICK_METHOD_CLICKFINGER) << "clickMethodClickfinger"; +} + +void TestLibinputDevice::testLoadClickMethod() +{ + auto config = KSharedConfig::openConfig(QString(), KConfig::SimpleConfig); + KConfigGroup inputConfig(config, QStringLiteral("Test")); + QFETCH(quint32, initValue); + QFETCH(quint32, configValue); + QFETCH(QString, initValuePropNameString); + QFETCH(QString, configValuePropNameString); + + QByteArray initValuePropName = initValuePropNameString.toLatin1(); + QByteArray configValuePropName = configValuePropNameString.toLatin1(); + + inputConfig.writeEntry("ClickMethod", configValue); + + libinput_device device; + device.supportedClickMethods = LIBINPUT_CONFIG_CLICK_METHOD_BUTTON_AREAS | LIBINPUT_CONFIG_CLICK_METHOD_CLICKFINGER; + device.clickMethod = (libinput_config_click_method) initValue; + device.setClickMethodReturnValue = false; + + Device d(&device); + QCOMPARE(d.property(initValuePropName).toBool(), true); + QCOMPARE(d.property(configValuePropName).toBool(), initValue == configValue); + // no config group set, should not change + d.loadConfiguration(); + QCOMPARE(d.property(initValuePropName).toBool(), true); + QCOMPARE(d.property(configValuePropName).toBool(), initValue == configValue); + + // set the group + d.setConfig(inputConfig); + d.loadConfiguration(); + QCOMPARE(d.property(initValuePropName).toBool(), initValue == configValue); + QCOMPARE(d.property(configValuePropName).toBool(), true); + QCOMPARE(dbusProperty(d.sysName(), initValuePropName), initValue == configValue); + QCOMPARE(dbusProperty(d.sysName(), configValuePropName), true); + + // and try to store + if (configValue != initValue) { + d.setProperty(initValuePropName, true); + QCOMPARE(inputConfig.readEntry("ClickMethod", configValue), initValue); + } +} + void TestLibinputDevice::testLoadTapToClick_data() { QTest::addColumn("initValue"); diff --git a/autotests/libinput/mock_libinput.h b/autotests/libinput/mock_libinput.h --- a/autotests/libinput/mock_libinput.h +++ b/autotests/libinput/mock_libinput.h @@ -101,6 +101,10 @@ bool lidSwitch = false; bool tabletModeSwitch = false; + quint32 supportedClickMethods = 0; + enum libinput_config_click_method defaultClickMethod = LIBINPUT_CONFIG_CLICK_METHOD_NONE; + enum libinput_config_click_method clickMethod = LIBINPUT_CONFIG_CLICK_METHOD_NONE; + bool setClickMethodReturnValue = 0; }; struct libinput_event { diff --git a/autotests/libinput/mock_libinput.cpp b/autotests/libinput/mock_libinput.cpp --- a/autotests/libinput/mock_libinput.cpp +++ b/autotests/libinput/mock_libinput.cpp @@ -276,6 +276,33 @@ return device->pointerAccelerationProfile; } +uint32_t libinput_device_config_click_get_methods(struct libinput_device *device) +{ + return device->supportedClickMethods; +} + +enum libinput_config_click_method libinput_device_config_click_get_default_method(struct libinput_device *device) +{ + return device->defaultClickMethod; +} + +enum libinput_config_click_method libinput_device_config_click_get_method(struct libinput_device *device) +{ + return device->clickMethod; +} + +enum libinput_config_status libinput_device_config_click_set_method(struct libinput_device *device, enum libinput_config_click_method method) +{ + if (device->setClickMethodReturnValue == 0) { + if (!(device->supportedClickMethods & method) && method != LIBINPUT_CONFIG_CLICK_METHOD_NONE) { + return LIBINPUT_CONFIG_STATUS_INVALID; + } + device->clickMethod = method; + return LIBINPUT_CONFIG_STATUS_SUCCESS; + } + return LIBINPUT_CONFIG_STATUS_INVALID; +} + uint32_t libinput_device_config_send_events_get_mode(struct libinput_device *device) { if (device->enabled) { diff --git a/libinput/device.h b/libinput/device.h --- a/libinput/device.h +++ b/libinput/device.h @@ -129,6 +129,14 @@ Q_PROPERTY(bool lidSwitch READ isLidSwitch CONSTANT) Q_PROPERTY(bool tabletModeSwitch READ isTabletModeSwitch CONSTANT) + // Click Methods + Q_PROPERTY(bool supportsClickMethodAreas READ supportsClickMethodAreas CONSTANT) + Q_PROPERTY(bool defaultClickMethodAreas READ defaultClickMethodAreas CONSTANT) + Q_PROPERTY(bool clickMethodAreas READ isClickMethodAreas WRITE setClickMethodAreas NOTIFY clickMethodChanged) + + Q_PROPERTY(bool supportsClickMethodClickfinger READ supportsClickMethodClickfinger CONSTANT) + Q_PROPERTY(bool defaultClickMethodClickfinger READ defaultClickMethodClickfinger CONSTANT) + Q_PROPERTY(bool clickMethodClickfinger READ isClickMethodClickfinger WRITE setClickMethodClickfinger NOTIFY clickMethodChanged) public: explicit Device(libinput_device *device, QObject *parent = nullptr); @@ -381,6 +389,38 @@ quint32 defaultPointerAccelerationProfileToInt() const { return (quint32) m_defaultPointerAccelerationProfile; } + bool supportsClickMethodAreas() const { + return (m_supportedClickMethods & LIBINPUT_CONFIG_CLICK_METHOD_BUTTON_AREAS); + } + bool defaultClickMethodAreas() const { + return (m_defaultClickMethod == LIBINPUT_CONFIG_CLICK_METHOD_BUTTON_AREAS); + } + bool isClickMethodAreas() const { + return (m_clickMethod == LIBINPUT_CONFIG_CLICK_METHOD_BUTTON_AREAS); + } + bool supportsClickMethodClickfinger() const { + return (m_supportedClickMethods & LIBINPUT_CONFIG_CLICK_METHOD_CLICKFINGER); + } + bool defaultClickMethodClickfinger() const { + return (m_defaultClickMethod == LIBINPUT_CONFIG_CLICK_METHOD_CLICKFINGER); + } + bool isClickMethodClickfinger() const { + return (m_clickMethod == LIBINPUT_CONFIG_CLICK_METHOD_CLICKFINGER); + } + void setClickMethod(bool set, enum libinput_config_click_method method); + void setClickMethodAreas(bool set) { + setClickMethod(set, LIBINPUT_CONFIG_CLICK_METHOD_BUTTON_AREAS); + } + void setClickMethodClickfinger(bool set) { + setClickMethod(set, LIBINPUT_CONFIG_CLICK_METHOD_CLICKFINGER); + } + void setClickMethodFromInt(quint32 method) { + setClickMethod(true, (libinput_config_click_method) method); + } + quint32 defaultClickMethodToInt() const { + return (quint32) m_defaultClickMethod; + } + bool isEnabled() const { return m_enabled; } @@ -456,6 +496,7 @@ void naturalScrollChanged(); void scrollMethodChanged(); void scrollButtonChanged(); + void clickMethodChanged(); private: template @@ -518,6 +559,9 @@ enum libinput_config_accel_profile m_defaultPointerAccelerationProfile; enum libinput_config_accel_profile m_pointerAccelerationProfile; bool m_enabled; + quint32 m_supportedClickMethods; + enum libinput_config_click_method m_defaultClickMethod; + enum libinput_config_click_method m_clickMethod; KConfigGroup m_config; bool m_loading = false; diff --git a/libinput/device.cpp b/libinput/device.cpp --- a/libinput/device.cpp +++ b/libinput/device.cpp @@ -83,7 +83,8 @@ MiddleButtonEmulation, NaturalScroll, ScrollMethod, - ScrollButton + ScrollButton, + ClickMethod }; struct ConfigData { @@ -129,7 +130,8 @@ {ConfigKey::LmrTapButtonMap, ConfigData(QByteArrayLiteral("LmrTapButtonMap"), &Device::setLmrTapButtonMap, &Device::lmrTapButtonMapEnabledByDefault)}, {ConfigKey::NaturalScroll, ConfigData(QByteArrayLiteral("NaturalScroll"), &Device::setNaturalScroll, &Device::naturalScrollEnabledByDefault)}, {ConfigKey::ScrollMethod, ConfigData(QByteArrayLiteral("ScrollMethod"), &Device::activateScrollMethodFromInt, &Device::defaultScrollMethodToInt)}, - {ConfigKey::ScrollButton, ConfigData(QByteArrayLiteral("ScrollButton"), &Device::setScrollButton, &Device::defaultScrollButton)} + {ConfigKey::ScrollButton, ConfigData(QByteArrayLiteral("ScrollButton"), &Device::setScrollButton, &Device::defaultScrollButton)}, + {ConfigKey::ClickMethod, ConfigData(QByteArrayLiteral("ClickMethod"), &Device::setClickMethodFromInt, &Device::defaultClickMethodToInt)} }; namespace { @@ -209,6 +211,9 @@ , m_enabled(m_supportsDisableEvents ? libinput_device_config_send_events_get_mode(m_device) == LIBINPUT_CONFIG_SEND_EVENTS_ENABLED : true) , m_config() , m_defaultCalibrationMatrix(m_supportsCalibrationMatrix ? defaultCalibrationMatrix(m_device) : QMatrix4x4{}) + , m_supportedClickMethods(libinput_device_config_click_get_methods(m_device)) + , m_defaultClickMethod(libinput_device_config_click_get_default_method(m_device)) + , m_clickMethod(libinput_device_config_click_get_method(m_device)) { libinput_device_ref(m_device); @@ -356,6 +361,27 @@ } } +void Device::setClickMethod(bool set, enum libinput_config_click_method method) +{ + if (!(m_supportedClickMethods & method)) { + return; + } + if (!set) { + method = (method == LIBINPUT_CONFIG_CLICK_METHOD_BUTTON_AREAS) ? LIBINPUT_CONFIG_CLICK_METHOD_CLICKFINGER : LIBINPUT_CONFIG_CLICK_METHOD_BUTTON_AREAS; + if (!(m_supportedClickMethods & method)) { + return; + } + } + + if (libinput_device_config_click_set_method(m_device, method) == LIBINPUT_CONFIG_STATUS_SUCCESS) { + if (m_clickMethod != method) { + m_clickMethod = method; + emit clickMethodChanged(); + writeEntry(ConfigKey::ClickMethod, (quint32) method); + } + } +} + void Device::setScrollMethod(bool set, enum libinput_config_scroll_method method) { if (!(m_supportedScrollMethods & method)) {