You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
tdebase/kcontrol/input/touchpad_settings.cpp

410 lines
10 KiB

/*******************************************************************************
tdecm_touchpad
A touchpad module for the TDE Control Centre
Copyright © 2024 Mavridis Philippe <mavridisf@gmail.com>
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 <https://www.gnu.org/licenses/>.
*******************************************************************************/
// TDE
#include <tdeapplication.h>
#include <tdeconfig.h>
#include <kdebug.h>
// DCOP
#include <dcopref.h>
// X11
#include <X11/extensions/XInput.h>
#include <X11/extensions/XInput2.h>
// 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 tdesyndaemon
DCOPRef tdesyndaemon("tdesyndaemon", "tdesyndaemon");
tdesyndaemon.call("stop()");
if (offWhileTyping)
{
kapp->tdeinitExec("tdesyndaemon");
}
}
if (fail > 0)
kdWarning() << "some options could not be applied!" << endl;
}
TQValueList<bool> TouchpadSettings::getScrollMethodsAvailability()
{
TQValueList<bool> 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<bool> TouchpadSettings::getAccelProfilesAvailability()
{
TQValueList<bool> 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;
}