From 8bd4c502f65ad364261913150ce59a74c993ca1c Mon Sep 17 00:00:00 2001 From: Mavridis Philippe Date: Sat, 1 Jun 2024 22:46:37 +0300 Subject: KControl: add touchpad configuration module Supports the Libinput and Synaptics drivers, includes documentation and inpupt-touchpad icon. Signed-off-by: Mavridis Philippe --- kcontrol/input/CMakeLists.txt | 33 +- kcontrol/input/icons/CMakeLists.txt | 1 + .../input/icons/cr128-device-input-touchpad.png | Bin 0 -> 8267 bytes .../input/icons/cr16-device-input-touchpad.png | Bin 0 -> 719 bytes .../input/icons/cr32-device-input-touchpad.png | Bin 0 -> 1696 bytes .../input/icons/cr48-device-input-touchpad.png | Bin 0 -> 2824 bytes .../input/icons/cr64-device-input-touchpad.png | Bin 0 -> 4044 bytes .../input/icons/crsc-device-input-touchpad.svg | 485 +++++++++++++++++++ kcontrol/input/main.cpp | 19 + kcontrol/input/pics/CMakeLists.txt | 14 - kcontrol/input/pics/mouse0.png | Bin 0 -> 1857 bytes kcontrol/input/pics/mouse1.png | Bin 0 -> 1864 bytes kcontrol/input/pics/mouse2.png | Bin 0 -> 1868 bytes kcontrol/input/pics/mouse3.png | Bin 0 -> 1863 bytes kcontrol/input/syndaemon.cpp | 201 ++++++++ kcontrol/input/syndaemon.h | 78 +++ kcontrol/input/syndaemon_iface.h | 34 ++ kcontrol/input/touchpad.cpp | 528 +++++++++++++++++++++ kcontrol/input/touchpad.desktop | 16 + kcontrol/input/touchpad.h | 97 ++++ kcontrol/input/touchpad_settings.cpp | 409 ++++++++++++++++ kcontrol/input/touchpad_settings.h | 107 +++++ kcontrol/input/xiproperty.h | 123 +++++ 23 files changed, 2125 insertions(+), 20 deletions(-) create mode 100644 kcontrol/input/icons/CMakeLists.txt create mode 100644 kcontrol/input/icons/cr128-device-input-touchpad.png create mode 100644 kcontrol/input/icons/cr16-device-input-touchpad.png create mode 100644 kcontrol/input/icons/cr32-device-input-touchpad.png create mode 100644 kcontrol/input/icons/cr48-device-input-touchpad.png create mode 100644 kcontrol/input/icons/cr64-device-input-touchpad.png create mode 100644 kcontrol/input/icons/crsc-device-input-touchpad.svg delete mode 100644 kcontrol/input/pics/CMakeLists.txt create mode 100644 kcontrol/input/pics/mouse0.png create mode 100644 kcontrol/input/pics/mouse1.png create mode 100644 kcontrol/input/pics/mouse2.png create mode 100644 kcontrol/input/pics/mouse3.png create mode 100644 kcontrol/input/syndaemon.cpp create mode 100644 kcontrol/input/syndaemon.h create mode 100644 kcontrol/input/syndaemon_iface.h create mode 100644 kcontrol/input/touchpad.cpp create mode 100644 kcontrol/input/touchpad.desktop create mode 100644 kcontrol/input/touchpad.h create mode 100644 kcontrol/input/touchpad_settings.cpp create mode 100644 kcontrol/input/touchpad_settings.h create mode 100644 kcontrol/input/xiproperty.h (limited to 'kcontrol/input') diff --git a/kcontrol/input/CMakeLists.txt b/kcontrol/input/CMakeLists.txt index 2fc6f6ce8..81d4a2384 100644 --- a/kcontrol/input/CMakeLists.txt +++ b/kcontrol/input/CMakeLists.txt @@ -17,8 +17,6 @@ else( ) include_directories( core ) endif( ) -add_subdirectory( pics ) - include_directories( ${CMAKE_CURRENT_BINARY_DIR} ${CMAKE_BINARY_DIR} @@ -34,7 +32,7 @@ link_directories( ##### other data ################################ tde_create_translated_desktop( - SOURCE mouse.desktop + SOURCE mouse.desktop touchpad.desktop PO_DIR kcontrol-desktops ) @@ -47,18 +45,41 @@ install( FILES mouse_cursor_theme.upd DESTINATION ${KCONF_UPDATE_INSTALL_DIR} ) +install( + DIRECTORY pics/ + DESTINATION ${DATA_INSTALL_DIR}/kcminput/pics + FILES_MATCHING PATTERN *.png +) + +add_subdirectory(icons) + ##### kcm_input (module) ######################## tde_add_kpart( kcm_input AUTOMOC SOURCES - mouse.cpp kmousedlg.ui main.cpp logitechmouse.cpp - logitechmouse_base.ui - LINK themepage-static tdeio-shared ${XCURSOR_LIBRARIES} ${LIBUSB_LIBRARIES} + mouse.cpp kmousedlg.ui main.cpp + logitechmouse.cpp logitechmouse_base.ui + touchpad.cpp touchpad_settings.cpp + LINK + themepage-static tdeio-shared + ${XCURSOR_LIBRARIES} ${LIBUSB_LIBRARIES} + ${XINPUT_LIBRARIES} DESTINATION ${PLUGIN_INSTALL_DIR} ) +##### syndaemon (executable) #################### + +tde_add_executable( syndaemon AUTOMOC + SOURCES + syndaemon.cpp syndaemon_iface.skel + touchpad_settings.cpp + LINK tdecore-shared ${XINPUT_LIBRARIES} + DESTINATION ${BIN_INSTALL_DIR} +) + + ##### kapplymousetheme (executable) ############# tde_add_executable( kapplymousetheme diff --git a/kcontrol/input/icons/CMakeLists.txt b/kcontrol/input/icons/CMakeLists.txt new file mode 100644 index 000000000..546096f2e --- /dev/null +++ b/kcontrol/input/icons/CMakeLists.txt @@ -0,0 +1 @@ +tde_install_icons() \ No newline at end of file diff --git a/kcontrol/input/icons/cr128-device-input-touchpad.png b/kcontrol/input/icons/cr128-device-input-touchpad.png new file mode 100644 index 000000000..5b5b16553 Binary files /dev/null and b/kcontrol/input/icons/cr128-device-input-touchpad.png differ diff --git a/kcontrol/input/icons/cr16-device-input-touchpad.png b/kcontrol/input/icons/cr16-device-input-touchpad.png new file mode 100644 index 000000000..bde3c5e48 Binary files /dev/null and b/kcontrol/input/icons/cr16-device-input-touchpad.png differ diff --git a/kcontrol/input/icons/cr32-device-input-touchpad.png b/kcontrol/input/icons/cr32-device-input-touchpad.png new file mode 100644 index 000000000..6e00abaa4 Binary files /dev/null and b/kcontrol/input/icons/cr32-device-input-touchpad.png differ diff --git a/kcontrol/input/icons/cr48-device-input-touchpad.png b/kcontrol/input/icons/cr48-device-input-touchpad.png new file mode 100644 index 000000000..7c6a41c56 Binary files /dev/null and b/kcontrol/input/icons/cr48-device-input-touchpad.png differ diff --git a/kcontrol/input/icons/cr64-device-input-touchpad.png b/kcontrol/input/icons/cr64-device-input-touchpad.png new file mode 100644 index 000000000..b124147fa Binary files /dev/null and b/kcontrol/input/icons/cr64-device-input-touchpad.png differ diff --git a/kcontrol/input/icons/crsc-device-input-touchpad.svg b/kcontrol/input/icons/crsc-device-input-touchpad.svg new file mode 100644 index 000000000..2802b4716 --- /dev/null +++ b/kcontrol/input/icons/crsc-device-input-touchpad.svg @@ -0,0 +1,485 @@ + + +image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/kcontrol/input/main.cpp b/kcontrol/input/main.cpp index d72dd0aa6..71d9ec66f 100644 --- a/kcontrol/input/main.cpp +++ b/kcontrol/input/main.cpp @@ -38,6 +38,8 @@ #endif #include "mouse.h" +#include "touchpad_settings.h" +#include "touchpad.h" extern "C" { @@ -91,6 +93,23 @@ extern "C" delete config; } + + TDE_EXPORT TDECModule *create_touchpad(TQWidget *parent, const char *) + { + return new TouchpadConfig(parent, "kcminput"); + } + + TDE_EXPORT void init_touchpad() + { + TouchpadSettings settings; + settings.apply(); + } + + TDE_EXPORT bool test_touchpad() + { + TouchpadSettings settings; + return settings.foundTouchpad(); + } } diff --git a/kcontrol/input/pics/CMakeLists.txt b/kcontrol/input/pics/CMakeLists.txt deleted file mode 100644 index 0c9331efe..000000000 --- a/kcontrol/input/pics/CMakeLists.txt +++ /dev/null @@ -1,14 +0,0 @@ -################################################# -# -# (C) 2010-2011 Serghei Amelian -# serghei (DOT) amelian (AT) gmail.com -# -# Improvements and feedback are welcome -# -# This file is released under GPL >= 2 -# -################################################# - -install( FILES - mouse_rh.png mouse_lh.png doubleclick_1.png doubleclick_2.png - DESTINATION ${DATA_INSTALL_DIR}/kcminput/pics ) diff --git a/kcontrol/input/pics/mouse0.png b/kcontrol/input/pics/mouse0.png new file mode 100644 index 000000000..02e708b04 Binary files /dev/null and b/kcontrol/input/pics/mouse0.png differ diff --git a/kcontrol/input/pics/mouse1.png b/kcontrol/input/pics/mouse1.png new file mode 100644 index 000000000..f3aeea106 Binary files /dev/null and b/kcontrol/input/pics/mouse1.png differ diff --git a/kcontrol/input/pics/mouse2.png b/kcontrol/input/pics/mouse2.png new file mode 100644 index 000000000..40c34fe59 Binary files /dev/null and b/kcontrol/input/pics/mouse2.png differ diff --git a/kcontrol/input/pics/mouse3.png b/kcontrol/input/pics/mouse3.png new file mode 100644 index 000000000..74e5c1423 Binary files /dev/null and b/kcontrol/input/pics/mouse3.png differ diff --git a/kcontrol/input/syndaemon.cpp b/kcontrol/input/syndaemon.cpp new file mode 100644 index 000000000..53d8346ca --- /dev/null +++ b/kcontrol/input/syndaemon.cpp @@ -0,0 +1,201 @@ +/******************************************************************************* + syndaemon - daemon for the Synaptics touchpad driver which disables touchpad + on keyboard input + + Copyright © 2004 Nadeem Hasan + Stefan Kombrink + 2024 Mavridis Philippe + + 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 3 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 . + +*******************************************************************************/ + +// TQt +#include +#include + +// TDE +#include +#include +#include +#include +#include +#include + +// DCOP +#include + +// tdecm_touchpad +#include "touchpad_settings.h" + +// SynDaemon +#include "syndaemon.h" +#include "syndaemon.moc" + +const unsigned int SynDaemon::TIME_OUT = 150; +const unsigned int SynDaemon::POLL_INTERVAL = 100; +const unsigned int SynDaemon::KEYMAP_SIZE = 32; + +unsigned char* SynDaemon::m_keyboard_mask; + +SynDaemon::SynDaemon() : DCOPObject("syndaemon"), TQObject() +{ + m_typing = false; + m_time = new TQTime(); + d_settings = new TouchpadSettings; + + m_keyboard_mask = new unsigned char[ KEYMAP_SIZE ]; + + // open a connection to the X server + m_display = XOpenDisplay(NULL); + + if (!m_display) kdError() << "Can't open display!" << endl; + + // setup keymap + XModifierKeymap *modifiers; + + for (unsigned int i = 0; i < KEYMAP_SIZE; ++i) + m_keyboard_mask[i] = 0xFF; + + modifiers = XGetModifierMapping(m_display); + for (int i = 0; i < 8 * modifiers->max_keypermod; ++i) + { + KeyCode kc = modifiers->modifiermap[i]; + if (kc != 0) clearBit(m_keyboard_mask, kc); + } + + XFreeModifiermap(modifiers); + + m_poll = new TQTimer(this); + connect(m_poll, TQ_SIGNAL(timeout()), this, TQ_SLOT(poll())); + m_poll->start(POLL_INTERVAL); +} + +SynDaemon::~SynDaemon() +{ + setTouchpadOn(true); + m_poll->stop(); + delete m_keyboard_mask; +} + +void SynDaemon::stop() +{ + kapp->quit(); +} + +void SynDaemon::poll() +{ + // do nothing if the user has explicitly disabled the touchpad in the settings + if (!touchpadEnabled()) return; + + if (hasKeyboardActivity()) + { + m_time->start(); + + if (!m_typing) + { + setTouchpadOn(false); + } + } + + else + { + if (m_typing && (m_time->elapsed() > TIME_OUT)) + { + setTouchpadOn(true); + } + } +} + +bool SynDaemon::touchpadEnabled() +{ + // We can't read from our own TouchpadSettings + // as it contains the currently applied value + // so we revert to this + KSimpleConfig cfg("kcminputrc"); + cfg.setGroup("Touchpad"); + return cfg.readBoolEntry("Enabled", true); +} + +void SynDaemon::setTouchpadOn(bool on) +{ + m_typing = !on; + if (!d_settings->setTouchpadEnabled(on)) + { + kdWarning() << "unable to turn off touchpad!" << endl; + } +} + +void SynDaemon::clearBit(unsigned char *ptr, int bit) +{ + int byteNum = bit / 8; + int bitNum = bit % 8; + ptr[byteNum] &= ~(1 << bitNum); +} + +bool SynDaemon::hasKeyboardActivity() +{ + static unsigned char oldKeyState[KEYMAP_SIZE]; + unsigned char keyState[KEYMAP_SIZE]; + + bool result = false; + + XQueryKeymap(m_display, (char*)keyState); + + // find pressed keys + for (unsigned int i = 0; i < KEYMAP_SIZE; ++i) + { + if ((keyState[i] & ~oldKeyState[i]) & m_keyboard_mask[i]) + { + result = true; + break; + } + } + + // ignore any modifiers + for (unsigned int i = 0; i < KEYMAP_SIZE; ++i) + { + if (keyState[i] & ~m_keyboard_mask[i]) + { + result = false; + break; + } + } + + // back up key states... + for (unsigned int i = 0; i < KEYMAP_SIZE; ++i) + { + oldKeyState[i] = keyState[i]; + } + + return result; +} + +extern "C" TDE_EXPORT int main(int argc, char *argv[]) +{ + TDEAboutData aboutData( "syndaemon", I18N_NOOP("Synaptics helper daemon"), + "0.1", I18N_NOOP("Synaptics helper daemon"), TDEAboutData::License_GPL_V2, + "© 2024 Mavridis Philippe" ); + + aboutData.addAuthor("Nadeem Hasan", I18N_NOOP("Author"), "nhasan@kde.org"); + aboutData.addAuthor("Mavridis Philippe", I18N_NOOP("Author"), "mavridisf@gmail.com"); + + TDECmdLineArgs::init(argc, argv, &aboutData); + + TDEApplication app; + app.disableSessionManagement(); + app.dcopClient()->registerAs("syndaemon", false); + + SynDaemon syndaemon; + return app.exec(); +} \ No newline at end of file diff --git a/kcontrol/input/syndaemon.h b/kcontrol/input/syndaemon.h new file mode 100644 index 000000000..0556345eb --- /dev/null +++ b/kcontrol/input/syndaemon.h @@ -0,0 +1,78 @@ +/******************************************************************************* + syndaemon - daemon for the Synaptics touchpad driver which disables touchpad + on keyboard input + + Copyright © 2004 Nadeem Hasan + Stefan Kombrink + 2024 Mavridis Philippe + + 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 3 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 . + +*******************************************************************************/ + +#ifndef __SYNDAEMON_H__ +#define __SYNDAEMON_H__ + +// TQt +#include +#include + +// DCOP +#include + +// X11 +#include +#undef Bool /* fix problems in --enable-final mode */ +#undef None /* fix problems in --enable-final mode */ + +// Syndaemon +#include "syndaemon_iface.h" + + +class TQTimer; + +class SynDaemon : public TQObject, public virtual SynDaemonIface +{ + TQ_OBJECT + + public: + SynDaemon(); + ~SynDaemon(); + + bool touchpadEnabled(); + + public slots: + void poll(); + void setTouchpadOn(bool on); + virtual void stop(); + + protected: + void clearBit(unsigned char* ptr, int bit); + bool hasKeyboardActivity(); + + private: + TouchpadSettings *d_settings; + + TQTimer *m_poll; + TQTime *m_time; + Display *m_display; + bool m_typing; + + static const unsigned int POLL_INTERVAL; + static const unsigned int TIME_OUT; + static const unsigned int KEYMAP_SIZE; + static unsigned char *m_keyboard_mask; +}; + +#endif + diff --git a/kcontrol/input/syndaemon_iface.h b/kcontrol/input/syndaemon_iface.h new file mode 100644 index 000000000..0f3d33929 --- /dev/null +++ b/kcontrol/input/syndaemon_iface.h @@ -0,0 +1,34 @@ +/******************************************************************************* + syndaemon - daemon for the Synaptics touchpad driver which disables touchpad + on keyboard input + + Copyright © 2024 Mavridis Philippe + + 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 3 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 . + +*******************************************************************************/ + +#ifndef __SYNDAEMON_IFACE_H__ +#define __SYNDAEMON_IFACE_H__ + +// DCOP +#include + +class SynDaemonIface : virtual public DCOPObject +{ + K_DCOP + k_dcop: + virtual void stop() = 0; +}; + +#endif \ No newline at end of file diff --git a/kcontrol/input/touchpad.cpp b/kcontrol/input/touchpad.cpp new file mode 100644 index 000000000..d18e3b698 --- /dev/null +++ b/kcontrol/input/touchpad.cpp @@ -0,0 +1,528 @@ +/******************************************************************************* + tdecm_touchpad + A touchpad module for the TDE Control Centre + + Copyright © 2024 Mavridis Philippe + + 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 3 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 . + +*******************************************************************************/ + +// TQt +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// TDE +#include +#include +#include +#include +#include + +// TouchpadConfig +#include "touchpad_settings.h" +#include "touchpad.h" +#include "touchpad.moc" + + +/******************************* TouchpadConfig *******************************/ +TouchpadConfig::TouchpadConfig(TQWidget *parent, const char *name) +: TDECModule(parent, name), + m_error(nullptr) +{ + TDEGlobal::iconLoader()->addAppDir("kcminput"); + + d_settings = new TouchpadSettings; + d_settings->apply(); + + if (!d_settings->supportedTouchpad()) + { + TQString error_str; + + if (!d_settings->foundTouchpad()) + { + error_str = i18n( + "

Touchpad not found

" + "Please check your system installation.
" + ); + } + + else IF_DRIVER(None) + { + error_str = i18n( + "

Unsupported driver

" + "

This module only supports the following drivers:" + "

Libinput, Synaptics" + ); + } + + else error_str = i18n("

Unknown error

"); + + m_error = new TQLabel(error_str, this); + m_error->setAlignment(TQt::AlignCenter); + new TQVBoxLayout(this); + layout()->add(m_error); + return; + } + + initWidgets(); + load(); + + kdDebug() << "managed touchpad: " << d_settings->touchpad().name + << " (xid = " << d_settings->touchpad().id << ")" << endl; + + TDEAboutData* about = new TDEAboutData( + "tdecm_touchpad", + I18N_NOOP("Touchpad"), + 0, 0, + TDEAboutData::License_GPL, + I18N_NOOP("(c) 2024 Mavridis Philippe") + ); + about->addAuthor("Mavridis Philippe", 0, 0); + setAboutData(about); +} + +TouchpadConfig::~TouchpadConfig() +{ + DEL(m_error) + DEL(d_settings); +} + +void TouchpadConfig::initWidgets() +{ + // Create containers + m_container = new TQTabWidget(this); + + TQFrame *touchpadWidget = new TQFrame(this); + touchpadWidget->setMargin(0); + new TQVBoxLayout(touchpadWidget); + + // Enable option + TQFrame *enableCheckBox = new TQFrame(touchpadWidget); + enableCheckBox->setSizePolicy(TQSizePolicy::Maximum, TQSizePolicy::Fixed); + + m_enabled = new TQCheckBox(i18n("Enable touchpad"), enableCheckBox); + TQWhatsThis::add(m_enabled, i18n( + "This option determines whether the touchpad is enabled or disabled" + )); + + // Compute margin for idented checkboxes based on checkbox height + int lmargin = m_enabled->height() / 2; + + // Align the Enable checkbox with the other options below + new TQHBoxLayout(enableCheckBox); + enableCheckBox->layout()->addItem(new TQSpacerItem(lmargin, lmargin, TQSizePolicy::Fixed)); + enableCheckBox->layout()->add(m_enabled); + + // Settings frame + TQFrame *settingsFrame = new TQFrame(touchpadWidget); + TQGridLayout *grid = new TQGridLayout(settingsFrame, 3, 2, KDialog::spacingHint()); + + connect(m_enabled, TQ_SIGNAL(toggled(bool)), this, TQ_SLOT(changed())); + connect(m_enabled, TQ_SIGNAL(toggled(bool)), settingsFrame, TQ_SLOT(setEnabled(bool))); + + // Behaviour + m_behaviour = new TQGroupBox(2, TQt::Vertical, i18n("Behaviour"), settingsFrame); + + m_offWhileTyping = new TQCheckBox(i18n("Disable touchpad while typing"), m_behaviour); + TQWhatsThis::add(m_offWhileTyping, i18n( + "If this option is checked, the touchpad is disabled while you are typing, so as " + "to prevent accidental cursor movement and clicks." + )); + connect(m_offWhileTyping, TQ_SIGNAL(toggled(bool)), this, TQ_SLOT(changed())); + + m_mbEmulation = new TQCheckBox(i18n("Middle button emulation"), m_behaviour); + TQWhatsThis::add(m_mbEmulation, i18n( + "If this option is enabled, a simultaneous left and right button click is " + "automatically transformed into a middle button click." + )); + IF_DRIVER(LibInput) + { + connect(m_mbEmulation, TQ_SIGNAL(toggled(bool)), this, TQ_SLOT(changed())); + } + else + { + DISABLE_UNSUPPORTED_OPTION(m_mbEmulation); + } + + // Speed + m_speed = new TQGroupBox(4, TQt::Vertical, i18n("Speed"), settingsFrame); + + TQLabel *accelLabel = new TQLabel(i18n("Acceleration:"), m_speed); + + m_accel = new TQSlider(-100, 100, 5, 0, TQt::Horizontal, m_speed); + + TQWidget *accelSliderMarkBox = new TQWidget(m_speed); + new TQHBoxLayout(accelSliderMarkBox); + accelSliderMarkBox->layout()->setAutoAdd(true); + + TQLabel *l; + l = new TQLabel(i18n("Slower"), accelSliderMarkBox); + l->setAlignment(TQt::AlignLeft); + l = new TQLabel(i18n("Normal"), accelSliderMarkBox); + l->setAlignment(TQt::AlignHCenter); + l = new TQLabel(i18n("Faster"), accelSliderMarkBox); + l->setAlignment(TQt::AlignRight); + l = nullptr; + + m_accelAdaptive = new TQCheckBox(i18n("Use adaptive profile"), m_speed); + + IF_DRIVER(LibInput) + { + connect(m_accel, TQ_SIGNAL(valueChanged(int)), this, TQ_SLOT(changed())); + connect(m_accelAdaptive, TQ_SIGNAL(toggled(bool)), this, TQ_SLOT(changed())); + + // check available profiles + TQValueList accelProfilesAvail = d_settings->getAccelProfilesAvailability(); + if (!accelProfilesAvail.count() || accelProfilesAvail[0] == 0 || accelProfilesAvail[1] == 0) + { + m_accelAdaptive->setEnabled(false); + } + } + else + { + DISABLE_UNSUPPORTED_OPTION(m_speed) + } + + // Tapping + m_tapping = new TQGroupBox(5, TQt::Vertical, i18n("Tapping"), settingsFrame); + + m_tapClick = new TQCheckBox(i18n("Tap to click"), m_tapping); + TQWhatsThis::add(m_tapClick, i18n( + "If this option is checked, a tap on the touchpad is interpreted as a button click." + )); + connect(m_tapClick, TQ_SIGNAL(toggled(bool)), this, TQ_SLOT(changed())); + connect(m_tapClick, TQ_SIGNAL(toggled(bool)), this, TQ_SLOT(updateWidgetStates())); + + m_tapDrag = new TQCheckBox(i18n("Tap-and-drag"), m_tapping); + TQWhatsThis::add(m_tapDrag, i18n( + "Tap-and-drag is a tap which is immediately followed by a finger down and that finger " + "being held down emulates a button press. Moving the finger around can thus drag the " + "selected item on the screen." + )); + connect(m_tapDrag, TQ_SIGNAL(toggled(bool)), this, TQ_SLOT(changed())); + connect(m_tapDrag, TQ_SIGNAL(toggled(bool)), this, TQ_SLOT(updateWidgetStates())); + + m_tapDragLock = new TQCheckBox(i18n("Tap-and-drag lock"), m_tapping); + TQWhatsThis::add(m_tapDragLock, i18n( + "When enabled, lifting a finger while dragging will not immediately stop dragging." + )); + + IF_DRIVER(LibInput) + { + connect(m_tapDragLock, TQ_SIGNAL(toggled(bool)), this, TQ_SLOT(changed())); + } + else + { + DISABLE_UNSUPPORTED_OPTION(m_tapDragLock); + } + + TQLabel *tapMappingLabel = new TQLabel(i18n("Two-finger tap:"), m_tapping); + m_tapMapping = new TQComboBox(m_tapping); // "lrm" and "lmr" + m_tapMapping->setSizePolicy(TQSizePolicy::Maximum, TQSizePolicy::Fixed); + m_tapMapping->insertItem( + TDEGlobal::iconLoader()->loadIcon("mouse3", TDEIcon::Small), + i18n("Right click (three-finger tap for middle click)"), + 0); + m_tapMapping->insertItem( + TDEGlobal::iconLoader()->loadIcon("mouse2", TDEIcon::Small), + i18n("Middle click (three-finger tap for right click)"), + 1); + connect(m_tapMapping, TQ_SIGNAL(activated(const TQString&)), this, TQ_SLOT(changed())); + + // Scrolling options + m_scrolling = new TQGroupBox(4, TQt::Vertical, i18n("Scrolling options"), settingsFrame); + + m_verScroll = new TQCheckBox(i18n("Vertical scrolling"), m_scrolling); + TQWhatsThis::add(m_verScroll, i18n( + "This option enables/disables the vertical scrolling gesture on the touchpad. " + "(The actual gesture depends on the selected scroll method.) " + "Unless the used driver is Synaptics, disabling vertical scrolling also disables " + "horizontal scrolling." + )); + connect(m_verScroll, TQ_SIGNAL(toggled(bool)), this, TQ_SLOT(changed())); + connect(m_verScroll, TQ_SIGNAL(toggled(bool)), this, TQ_SLOT(updateWidgetStates())); + + m_horScroll = new TQCheckBox(i18n("Horizontal scrolling"), m_scrolling); + TQWhatsThis::add(m_horScroll, i18n( + "This option enables/disables the horizontal scrolling gesture on the touchpad. " + "(The actual gesture depends on the selected scroll method.)" + )); + connect(m_horScroll, TQ_SIGNAL(toggled(bool)), this, TQ_SLOT(changed())); + connect(m_horScroll, TQ_SIGNAL(toggled(bool)), this, TQ_SLOT(updateWidgetStates())); + + m_naturalScroll = new TQCheckBox(i18n("Reverse scroll direction"), m_scrolling); + TQWhatsThis::add(m_naturalScroll, i18n( + "If this option is checked, the scrolling direction is reversed to resemble natural " + "movement of content. This feature is also called natural scrolling." + )); + connect(m_naturalScroll, TQ_SIGNAL(toggled(bool)), this, TQ_SLOT(changed())); + + m_naturalScrollDirections = new TQFrame(m_scrolling); + TQWhatsThis::add(m_naturalScrollDirections, i18n( + "This option allows you to select the scrolling directions to which reversed scrolling will be applied. " + "It is only available if the Synaptics driver is used." + )); + TQGridLayout *nsdl = new TQGridLayout(m_naturalScrollDirections, 2, 2, KDialog::spacingHint()); + m_horNaturalScroll = new TQCheckBox(i18n("Apply to horizontal scrolling"), m_naturalScrollDirections); + m_verNaturalScroll = new TQCheckBox(i18n("Apply to vertical scrolling"), m_naturalScrollDirections); + nsdl->addItem(new TQSpacerItem(lmargin, lmargin, TQSizePolicy::Fixed), 0, 0); + nsdl->addItem(new TQSpacerItem(lmargin, lmargin, TQSizePolicy::Fixed), 1, 0); + nsdl->addWidget(m_horNaturalScroll, 0, 1); + nsdl->addWidget(m_verNaturalScroll, 1, 1); + + IF_DRIVER(Synaptics) + { + connect(m_horNaturalScroll, TQ_SIGNAL(toggled(bool)), TQ_SLOT(changed())); + connect(m_verNaturalScroll, TQ_SIGNAL(toggled(bool)), TQ_SLOT(changed())); + connect(m_naturalScroll, TQ_SIGNAL(toggled(bool)), TQ_SLOT(updateWidgetStates())); + } + else + { + // Not only disable, but also force checkboxes to be checked on + // so that the user knows that the natural scrolling option applies + // always to both directions + DISABLE_UNSUPPORTED_OPTION(m_naturalScrollDirections); + m_horNaturalScroll->setChecked(true); + m_verNaturalScroll->setChecked(true); + } + + // Scrolling methods + m_scrollMethods = new TQButtonGroup(3, TQt::Vertical, i18n("Scrolling method"), settingsFrame); + TQWhatsThis::add(m_scrollMethods, i18n( + "Here you can select your preferred scrolling method. The two most common options are " + "two-finger scrolling and edge scrolling. Two-finger scrolling entails a movement with " + "two fingers vertically or horizontally upon the surface of the touchpad. Edge scrolling " + "on the other hand tracks movements with one finger along the right or bottom edge of " + "the touchpad." + )); + connect(m_scrollMethods, TQ_SIGNAL(clicked(int)), this, TQ_SLOT(changed())); + + TQStringList scrollMethodLabels; + scrollMethodLabels << i18n("Two-finger") + << i18n("Edge"); + + IF_DRIVER(LibInput) + { + scrollMethodLabels << i18n("Button"); + } + + TQValueList scrollMethodAvail = d_settings->getScrollMethodsAvailability(); + Q_ASSERT(scrollMethodLabels.count() == scrollMethodAvail.count()); + + for (int i = 0; i < scrollMethodLabels.count(); ++i) + { + TQRadioButton *rad = new TQRadioButton(scrollMethodLabels[i], m_scrollMethods); + rad->setEnabled(scrollMethodAvail[i]); + } + + // Finalize layout + grid->addWidget(m_behaviour, 0, 0); + grid->addWidget(m_speed, 1, 0); + grid->addMultiCellWidget(m_scrolling, 0, 1, 1, 1); + grid->addWidget(m_scrollMethods, 2, 1); + grid->addWidget(m_tapping, 2, 0); + grid->addItem(new TQSpacerItem(10, 10)); + + // Synaptics deprecation warning + IF_DRIVER(Synaptics) + { + TQLabel *l = new TQLabel(i18n( + "Warning: The Synaptics driver has been deprecated." + ), settingsFrame); + TQWhatsThis::add(l, i18n( + "

The Synaptics driver is no longer in active development." + "

While Libinput is the preferred choice for handling input devices, " + "you might still have valid reasons to use the older Synaptics driver " + "in its place. Please bear in mind that you will probably not receive " + "updates and bug fixes from its upstream." + )); + grid->addMultiCellWidget(l, 3, 3, 0, 1); + } + + touchpadWidget->layout()->add(enableCheckBox); + touchpadWidget->layout()->add(settingsFrame); + m_container->addTab(touchpadWidget, SmallIconSet("input-touchpad"), d_settings->touchpad().name); + + new TQVBoxLayout(this, KDialog::marginHint()); + layout()->add(m_container); +} + +// We handle more complex UI cases here +void TouchpadConfig::updateWidgetStates() +{ + if (!d_settings->foundTouchpad()) return; + + // Scrolling related options + bool on; + + IF_DRIVER(LibInput) + { + // To disable vertical scrolling under LibInput one has to disable scrolling entirely + // so we mirror this in the UI + on = m_verScroll->isChecked(); + m_horScroll->setEnabled(on); + } + + else + { + // In case we can control both horizontal and vertical scrolling separately, any UI + // changes should be triggered when both are disabled + on = m_verScroll->isChecked() || m_horScroll->isChecked(); + + // Only enable natural scroll directions options when not under LibInput + m_naturalScrollDirections->setEnabled(on && m_naturalScroll->isChecked()); + } + + m_naturalScroll->setEnabled(on); + m_scrollMethods->setEnabled(on); + + // Tapping related options + m_tapDrag->setEnabled(m_tapClick->isChecked()); + + IF_DRIVER(LibInput) + { + m_tapDragLock->setEnabled(m_tapClick->isChecked() && m_tapDrag->isChecked()); + } +} + +void TouchpadConfig::defaults() +{ + load(true); +} + +void TouchpadConfig::load() +{ + load(false); +} + +void TouchpadConfig::load(bool useDefaults) +{ + if (!d_settings->foundTouchpad()) return; + + d_settings->load(); + + m_enabled->setChecked(d_settings->enabled); + + // Behaviour + m_offWhileTyping->setChecked(d_settings->offWhileTyping); + + IF_DRIVER(LibInput) + { + m_mbEmulation->setChecked(d_settings->midButtonEmulation); + } + + // Speed + IF_DRIVER(LibInput) + { + m_accel->setValue(d_settings->accelSpeed); + m_accelAdaptive->setChecked(d_settings->accelProfile == 0); + } + + // Tapping + m_tapClick->setChecked(d_settings->tapClick); + m_tapDrag->setChecked(d_settings->tapDrag); + + IF_DRIVER(LibInput) + { + m_tapDragLock->setChecked(d_settings->tapDragLock); + } + + m_tapMapping->setCurrentItem(d_settings->tapMapping); + + // Scrolling options + m_horScroll->setChecked(d_settings->scrollDirections & TQt::Horizontal); + m_verScroll->setChecked(d_settings->scrollDirections & TQt::Vertical); + m_naturalScroll->setChecked(d_settings->naturalScroll); + IF_DRIVER(Synaptics) + { + m_naturalScrollDirections->setEnabled(d_settings->naturalScroll); + m_horNaturalScroll->setChecked(d_settings->naturalScrollDirections & TQt::Horizontal); + m_verNaturalScroll->setChecked(d_settings->naturalScrollDirections & TQt::Vertical); + } + + IF_DRIVER(LibInput) + { + m_horScroll->setEnabled(m_verScroll->isOn()); + m_naturalScroll->setEnabled(m_verScroll->isOn()); + m_scrollMethods->setEnabled(m_verScroll->isOn()); + } + + // Scrolling method + m_scrollMethods->setButton(d_settings->scrollMethod); +} + +void TouchpadConfig::save() +{ + if (!d_settings->foundTouchpad()) return; + + d_settings->enabled = m_enabled->isChecked(); + + // Behaviour + d_settings->offWhileTyping = m_offWhileTyping->isChecked(); + + IF_DRIVER(LibInput) + { + d_settings->midButtonEmulation = m_mbEmulation->isChecked(); + } + + // Speed + IF_DRIVER(LibInput) + { + d_settings->accelSpeed = m_accel->value(); + d_settings->accelProfile = (m_accelAdaptive->isChecked() ? 0 : 1); + } + + // Tapping + d_settings->tapClick = m_tapClick->isChecked(); + d_settings->tapDrag = m_tapDrag->isChecked(); + + IF_DRIVER(LibInput) + { + d_settings->tapDragLock = m_tapDragLock->isChecked(); + } + + d_settings->tapMapping = m_tapMapping->currentItem(); + + // Scrolling options + int scrollDirections = 0; + if (m_horScroll->isChecked()) scrollDirections |= TQt::Horizontal; + if (m_verScroll->isChecked()) scrollDirections |= TQt::Vertical; + d_settings->scrollDirections = scrollDirections; + + d_settings->naturalScroll = m_naturalScroll->isChecked(); + + int naturalScrollDirections = 0; + if (m_horNaturalScroll->isChecked()) naturalScrollDirections |= TQt::Horizontal; + if (m_verNaturalScroll->isChecked()) naturalScrollDirections |= TQt::Vertical; + d_settings->naturalScrollDirections = naturalScrollDirections; + + // Scrolling method + d_settings->scrollMethod = m_scrollMethods->selectedId(); + + d_settings->save(); + d_settings->apply(); +} + +Touchpad TouchpadConfig::touchpad() +{ + return d_settings->touchpad(); +} diff --git a/kcontrol/input/touchpad.desktop b/kcontrol/input/touchpad.desktop new file mode 100644 index 000000000..d943749c1 --- /dev/null +++ b/kcontrol/input/touchpad.desktop @@ -0,0 +1,16 @@ +[Desktop Entry] +Exec=tdecmshell touchpad +Icon=input-touchpad +Type=Application +X-DocPath=kcontrol/touchpad/index.html + +X-TDE-Library=input +X-TDE-FactoryName=touchpad +X-TDE-Init=touchpad +X-TDE-ParentApp=kcontrol +X-TDE-Test-Module=true + +Name=Touchpad +Comment=Touchpad settings +Keywords=Touchpad;Tap to click;Mouse;Mouse buttons;Input Devices;Button Mapping;Tap;Click;mapping;right handed;left handed; +Categories=Qt;TDE;X-TDE-settings-hardware; \ No newline at end of file diff --git a/kcontrol/input/touchpad.h b/kcontrol/input/touchpad.h new file mode 100644 index 000000000..088f7164a --- /dev/null +++ b/kcontrol/input/touchpad.h @@ -0,0 +1,97 @@ +/******************************************************************************* + tdecm_touchpad + A touchpad module for the TDE Control Centre + + Copyright © 2024 Mavridis Philippe + + 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 3 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 . + +*******************************************************************************/ + +#ifndef __TOUCHPAD_H__ +#define __TOUCHPAD_H__ + +// TDE +#include +#include + +// Macros +#define OPTION_NOT_SUPPORTED I18N_NOOP("This option is not compatible with the currently used driver") +#define DISABLE_UNSUPPORTED_OPTION(optionWidget) \ + optionWidget->setEnabled(false); \ + TQToolTip::add(optionWidget, i18n(OPTION_NOT_SUPPORTED)); + +// Forward definitions +class TQTabWidget; +class TQButtonGroup; +class TQGroupBox; +class TQCheckBox; +class TQComboBox; +class TQSlider; +class TQLabel; +class TQFrame; +class TDEConfig; +class TouchpadSettings; +struct Touchpad; + + +/******************************* TouchpadConfig *******************************/ +class TouchpadConfig : public TDECModule +{ + TQ_OBJECT + + public: + TouchpadConfig(TQWidget *parent, const char *name); + ~TouchpadConfig(); + + void load(); + void load(bool useDefaults); + void save(); + void defaults(); + + Touchpad touchpad(); + + protected: + void initWidgets(); + + protected slots: + void updateWidgetStates(); + + private: + TouchpadSettings *d_settings; + + TQTabWidget *m_container; + TQLabel *m_error; + TQCheckBox *m_enabled; + + TQGroupBox *m_behaviour; + TQCheckBox *m_offWhileTyping, *m_leftHanded, *m_mbEmulation; + + TQGroupBox *m_speed; + TQSlider *m_accel; + TQCheckBox *m_accelAdaptive; + + TQGroupBox *m_tapping; + TQCheckBox *m_tapClick, *m_tapDrag, *m_tapDragLock; + TQComboBox *m_tapMapping; + + TQGroupBox *m_scrolling; + TQCheckBox *m_horScroll, *m_verScroll, *m_naturalScroll, + *m_horNaturalScroll, *m_verNaturalScroll; + + TQFrame *m_naturalScrollDirections; + + TQButtonGroup *m_scrollMethods; +}; + +#endif // __TOUCHPAD_H__ diff --git a/kcontrol/input/touchpad_settings.cpp b/kcontrol/input/touchpad_settings.cpp new file mode 100644 index 000000000..1230efcee --- /dev/null +++ b/kcontrol/input/touchpad_settings.cpp @@ -0,0 +1,409 @@ +/******************************************************************************* + tdecm_touchpad + A touchpad module for the TDE Control Centre + + Copyright © 2024 Mavridis Philippe + + 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 3 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 . + +*******************************************************************************/ + +// TDE +#include +#include +#include + +// DCOP +#include + +// X11 +#include +#include + +// tdecm_touchpad +#include "xiproperty.h" +#include "touchpad_settings.h" + + +/****************************** TouchpadSettings ******************************/ +TouchpadSettings::TouchpadSettings() +: m_foundTouchpad(false) +{ + findTouchpad(); +} + +bool TouchpadSettings::findTouchpad() +{ + Display *display = tqt_xdisplay(); + ATOM(isTouchpad, XI_TOUCHPAD) + ATOM(isLibinput, "libinput Send Events Mode Enabled") + ATOM(isSynaptics, "Synaptics Off") + + int devicesCount; + XDeviceInfo *deviceList = XListInputDevices(display, &devicesCount); + + for (int d = 0; d < devicesCount; ++d) + { + if (deviceList[d].type != isTouchpad) continue; + + m_foundTouchpad = true; + m_touchpad.init(deviceList[d].id, deviceList[d].name); + + int propertiesCount; + Atom *propertiesList = XIListProperties(display, deviceList[d].id, + &propertiesCount); + for (int p = 0; p < propertiesCount; ++p) + { + if (propertiesList[p] == isLibinput) + { + m_touchpad.driver = Touchpad::Driver::LibInput; + break; + } + + else if (propertiesList[p] == isSynaptics) + { + m_touchpad.driver = Touchpad::Driver::Synaptics; + } + } + + XFree(propertiesList); + + if (m_foundTouchpad) break; + } + + XFreeDeviceList(deviceList); + + return m_foundTouchpad; +} + +void TouchpadSettings::load(bool defaults) +{ + TDEConfig cfg("kcminputrc"); + cfg.setGroup("Touchpad"); + cfg.setReadDefaults(defaults); + + enabled = cfg.readBoolEntry("Enabled", true); + + // Behaviour + offWhileTyping = cfg.readBoolEntry("OffWhileTyping", false); + + IF_DRIVER(LibInput) + { + midButtonEmulation = cfg.readBoolEntry("MidButtonEmulation", false); + } + + // Speed + IF_DRIVER(LibInput) + { + accelSpeed = cfg.readNumEntry("AccelSpeed", 0); + accelProfile = cfg.readNumEntry("AccelProfile", 0); + } + + // Tapping + tapClick = cfg.readBoolEntry("TapToClick", true); + tapDrag = cfg.readBoolEntry("TapAndDrag", true); + + IF_DRIVER(LibInput) + { + tapDragLock = cfg.readBoolEntry("TapAndDragLock", false); + } + + tapMapping = cfg.readNumEntry("TapMapping", 0); + + // Scrolling options + int both = TQt::Horizontal | TQt::Vertical; + scrollDirections = cfg.readNumEntry("ScrollDirections", both); + naturalScroll = cfg.readBoolEntry("NaturalScroll", false); + naturalScrollDirections = cfg.readNumEntry("NaturalScrollDirections", both); + + // Scrolling method + scrollMethod = cfg.readNumEntry("ScrollMethod", 0); +} + +void TouchpadSettings::save() +{ + TDEConfig cfg("kcminputrc"); + cfg.setGroup("Touchpad"); + + cfg.writeEntry("Enabled", enabled); + + // Behaviour + cfg.writeEntry("OffWhileTyping", offWhileTyping); + + IF_DRIVER(LibInput) + { + cfg.writeEntry("MidButtonEmulation", midButtonEmulation); + } + + // Speed + cfg.writeEntry("AccelSpeed", accelSpeed); + cfg.writeEntry("AccelProfile", accelProfile); + + // Tapping + cfg.writeEntry("TapToClick", tapClick); + cfg.writeEntry("TapAndDrag", tapDrag); + + IF_DRIVER(LibInput) + { + cfg.writeEntry("TapAndDragLock", tapDragLock); + } + + cfg.writeEntry("TapMapping", tapMapping); + + // Scrolling options + cfg.writeEntry("ScrollDirections", scrollDirections); + cfg.writeEntry("NaturalScroll", naturalScroll); + cfg.writeEntry("NaturalScrollDirections", naturalScrollDirections); + + // Scrolling method + cfg.writeEntry("ScrollMethod", scrollMethod); + + cfg.sync(); +} + +bool TouchpadSettings::setTouchpadEnabled(bool on) +{ + enabled = on; + + XIProperty *prop = nullptr; + int fail = 0; + + IF_DRIVER(LibInput) + { + SET_PROP("Device Enabled", b) + { + prop->b[0] = enabled; + prop->set(); + } + } + + else + IF_DRIVER(Synaptics) + { + SET_PROP("Synaptics Off", b) + { + prop->b[0] = !enabled; + prop->set(); + } + } + + return !fail; +} + +void TouchpadSettings::apply(bool force) +{ + kdDebug() << "applying touchpad settings" << endl; + if (!foundTouchpad()) + { + kdWarning() << "no supported touchpads! settings not applied" << endl; + return; + } + + load(); + + Display *display = tqt_xdisplay(); + XIProperty *prop = nullptr; + int fail = 0; + + if (!setTouchpadEnabled(enabled)) + ++fail; + + IF_DRIVER(LibInput) + { + kdDebug() << "driver: libinput" << endl; + + SET_PROP("libinput Disable While Typing Enabled", b) + { + prop->b[0] = offWhileTyping; + prop->set(); + } + + SET_PROP("libinput Middle Emulation Enabled", b) + { + prop->b[0] = midButtonEmulation; + prop->set(); + } + + SET_PROP("libinput Accel Speed", f) + { + float val = accelSpeed; + val /= 100; + prop->f[0] = val; + prop->set(); + } + + SET_PROP("libinput Accel Profile Enabled", b) + { + prop->b[0] = (accelProfile == 0); + prop->b[1] = (accelProfile == 1); + prop->set(); + } + + SET_PROP("libinput Tapping Enabled", b) + { + prop->b[0] = tapClick; + prop->set(); + } + + SET_PROP("libinput Tapping Drag Enabled", b) + { + prop->b[0] = tapClick && tapDrag; + prop->set(); + } + + SET_PROP("libinput Tapping Drag Lock Enabled", b) + { + prop->b[0] = tapClick && tapDrag && tapDragLock; + prop->set(); + } + + SET_PROP("libinput Tapping Button Mapping Enabled", b) + { + prop->b[0] = (tapMapping == 0); + prop->b[1] = (tapMapping == 1); + prop->set(); + } + + SET_PROP("libinput Horizontal Scroll Enabled", b) + { + prop->b[0] = scrollDirections & TQt::Horizontal; + prop->set(); + } + + SET_PROP("libinput Natural Scrolling Enabled", b) + { + prop->b[0] = naturalScroll; + prop->set(); + } + + SET_PROP("libinput Scroll Method Enabled", b) + { + prop->b[0] = scrollDirections ? (scrollMethod == 0) : 0; // two-finger + prop->b[1] = scrollDirections ? (scrollMethod == 1) : 0; // edge + prop->b[2] = scrollDirections ? (scrollMethod == 2) : 0; // button + prop->set(); + } + } + + else IF_DRIVER(Synaptics) + { + kdDebug() << "driver: synaptics" << endl; + + SET_PROP("Synaptics Tap Action", b) + { + prop->b[0] = 0; + prop->b[1] = 0; + prop->b[2] = 0; + prop->b[3] = 0; + prop->b[4] = tapClick ? 1 : 0; // 1 finger + prop->b[5] = tapClick ? (tapMapping == 0 ? 3 : 2) : 0; // 2 fingers + prop->b[6] = tapClick ? (tapMapping == 0 ? 2 : 3) : 0; // 3 fingers + prop->set(); + } + + SET_PROP("Synaptics Gestures", b) + { + prop->b[0] = tapDrag; + prop->set(); + } + + SET_PROP("Synaptics Edge Scrolling", b) + { + prop->b[0] = scrollMethod == 1 ? (scrollDirections & TQt::Vertical ? 1 : 0) : 0; + prop->b[1] = scrollMethod == 1 ? (scrollDirections & TQt::Horizontal ? 1 : 0) : 0; + prop->b[2] = 0; // corner + prop->set(); + } + + SET_PROP("Synaptics Two-Finger Scrolling", b) + { + prop->b[0] = scrollMethod == 0 ? (scrollDirections & TQt::Vertical ? 1 : 0) : 0; + prop->b[1] = scrollMethod == 0 ? (scrollDirections & TQt::Horizontal ? 1 : 0) : 0; + prop->set(); + } + + SET_PROP("Synaptics Scrolling Distance", i) + { + prop->i[0] = naturalScroll && naturalScrollDirections & TQt::Vertical ? -80 : 80; + prop->i[1] = naturalScroll && naturalScrollDirections & TQt::Horizontal ? -80 : 80; + prop->set(); + } + + // start/stop syndaemon + DCOPRef syndaemon("syndaemon", "syndaemon"); + syndaemon.call("stop()"); + + if (offWhileTyping) + { + kapp->tdeinitExec("syndaemon"); + } + } + + if (fail > 0) + kdWarning() << "some options could not be applied!" << endl; +} + +TQValueList TouchpadSettings::getScrollMethodsAvailability() +{ + TQValueList avail; + + IF_DRIVER(LibInput) + { + PROP(propScrollMethodsAvail, "libinput Scroll Methods Available") + for (int i = 0; i < propScrollMethodsAvail.count(); ++i) + { + avail.append(propScrollMethodsAvail[i].toBool()); + } + } + + IF_DRIVER(Synaptics) + { + avail.append(1); // two-finger + avail.append(1); // edge + } + + return avail; +} + +TQValueList TouchpadSettings::getAccelProfilesAvailability() +{ + TQValueList avail; + + IF_DRIVER(LibInput) + { + PROP(propAccelProfilesAvail, "libinput Accel Profiles Available") + for (int i = 0; i < propAccelProfilesAvail.count(); ++i) + { + avail.append(propAccelProfilesAvail[i].toBool()); + } + } + + IF_DRIVER(Synaptics) { /* TODO no support yet */ } + + return avail; +} + +Touchpad TouchpadSettings::touchpad() +{ + return m_touchpad; +} + +bool TouchpadSettings::foundTouchpad() +{ + return m_foundTouchpad; +} + +bool TouchpadSettings::supportedTouchpad() +{ + return m_foundTouchpad && m_touchpad.driver != Touchpad::Driver::None; +} \ No newline at end of file diff --git a/kcontrol/input/touchpad_settings.h b/kcontrol/input/touchpad_settings.h new file mode 100644 index 000000000..8cdfea951 --- /dev/null +++ b/kcontrol/input/touchpad_settings.h @@ -0,0 +1,107 @@ +/******************************************************************************* + tdecm_touchpad + A touchpad module for the TDE Control Centre + + Copyright © 2024 Mavridis Philippe + + 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 3 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 . + +*******************************************************************************/ + +#ifndef __TOUCHPAD_SETTINGS_H__ +#define __TOUCHPAD_SETTINGS_H__ + +// TQt +#include + +// Macros +#define DEL(var) \ + if (var) { delete var; var = nullptr; } + +#define ATOM(var, atom) \ + Atom var = XInternAtom(display, atom, true); + +#define PROP(var, property) \ + XIProperty var = XIProperty(m_touchpad.id, property); + +#define SET_PROP(property, type) \ + DEL(prop) \ + prop = new XIProperty(m_touchpad.id, property); \ + if (prop->type == nullptr) \ + { \ + kdWarning() << "Failed to set property " << property << endl; \ + ++fail; \ + } \ + else + +#define IF_DRIVER(drv) \ + if (touchpad().driver == Touchpad::Driver::drv) + + +/****************************** struct Touchpad *******************************/ +#undef None + +struct Touchpad +{ + enum Driver { None, LibInput, Synaptics }; + + bool valid = false; + unsigned int id; + TQCString name; + Driver driver = Touchpad::Driver::None; + + void init(unsigned int _id, TQCString _name) + { + valid = true; + id = _id; + name = _name; + } +}; + + +/***************************** TouchpadSettings *******************************/ +class TouchpadSettings +{ + public: + TouchpadSettings(); + + void load(bool defaults = false); + void save(); + void apply(bool force = false); + + TQValueList getScrollMethodsAvailability(); + TQValueList getAccelProfilesAvailability(); + + bool enabled, tapClick, tapDrag, tapDragLock, tapMapping, offWhileTyping, + leftHandedMode, midButtonEmulation, naturalScroll, scrollMethod; + int scrollDirections, naturalScrollDirections; + + int accelSpeed, accelProfile; + + bool foundTouchpad(); + Touchpad touchpad(); + + // Enable/disable touchpad without applying all settings + bool setTouchpadEnabled(bool on); + + bool supportedTouchpad(); + + protected: + bool findTouchpad(); + + private: + Touchpad m_touchpad; + bool m_foundTouchpad; +}; + +#endif // __TOUCHPAD_SETTINGS_H__ \ No newline at end of file diff --git a/kcontrol/input/xiproperty.h b/kcontrol/input/xiproperty.h new file mode 100644 index 000000000..ddbdf4b16 --- /dev/null +++ b/kcontrol/input/xiproperty.h @@ -0,0 +1,123 @@ +/******************************************************************************* + XIGetProperty/XIChangeProperty wrapper + + Copyright © 2013 Alexandr Mezin + Copyright © 2024 Mavridis Philippe + + 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 . + +*******************************************************************************/ + +#ifndef __XI_PROPERTY_H__ +#define __XI_PROPERTY_H__ + +// TQt +#include // tqt_xdisplay() +#include + +// X11 +#include + + +class XIProperty +{ + public: + XIProperty() + : device(-1), + type(0), + format(0), + num_items(0), + data(0), + b(nullptr), + i(nullptr), + f(nullptr) + {} + + XIProperty(int device, TQCString propertyName) + : device(device), + type(0), + format(0), + num_items(0), + data(0), + b(nullptr), + i(nullptr), + f(nullptr) + { + Display *disp = tqt_xdisplay(); + + property = XInternAtom(disp, propertyName, true); + + unsigned char *ptr = nullptr; + unsigned long bytes_after; + + XIGetProperty(disp, device, property, 0, 1000, False, AnyPropertyType, + &type, &format, &num_items, &bytes_after, &ptr); + + data = ptr; + + if (format == CHAR_BIT && type == XA_INTEGER) + { + b = reinterpret_cast(data); + } + + if (format == sizeof(int) * CHAR_BIT + && (type == XA_INTEGER || type == XA_CARDINAL)) + { + i = reinterpret_cast(data); + } + + Atom floatType = XInternAtom(disp, "FLOAT", true); + + if (format == sizeof(float) * CHAR_BIT && floatType && type == floatType) + { + f = reinterpret_cast(data); + } + } + + ~XIProperty() + { + XFree(data); + } + + TQVariant operator[](int offset) + { + if (offset >= num_items) return TQVariant(); + + if (b) return TQVariant(static_cast(b[offset])); + if (i) return TQVariant(i[offset]); + if (f) return TQVariant(f[offset]); + + return TQVariant(); + } + + void set() + { + XIChangeProperty(tqt_xdisplay(), device, property, type, format, XIPropModeReplace, + data, num_items); + } + + int count() { return num_items; } + + public: + char *b; + int *i; + float *f; + + private: + Atom property, type; + int device, format; + unsigned long num_items; + unsigned char *data; +}; + +#endif // __XI_PROPERTY_H__ \ No newline at end of file -- cgit v1.2.1