Warning, file /plasma/wacomtablet/src/kded/xinputadaptor.cpp was not indexed or was modified since last indexation (in which case cross-reference links may be missing, inaccurate or erroneous).

0001 /*
0002  * This file is part of the KDE wacomtablet project. For copyright
0003  * information and license terms see the AUTHORS and COPYING files
0004  * in the top-level directory of this distribution.
0005  *
0006  * This program is free software; you can redistribute it and/or
0007  * modify it under the terms of the GNU General Public License as
0008  * published by the Free Software Foundation; either version 2 of
0009  * the License, or (at your option) any later version.
0010  *
0011  * This program is distributed in the hope that it will be useful,
0012  * but WITHOUT ANY WARRANTY; without even the implied warranty of
0013  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
0014  * GNU General Public License for more details.
0015  *
0016  * You should have received a copy of the GNU General Public License
0017  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
0018  */
0019 
0020 #include "xinputadaptor.h"
0021 
0022 #include "logging.h"
0023 #include "screensinfo.h"
0024 #include "screenspace.h"
0025 #include "stringutils.h"
0026 #include "x11input.h"
0027 #include "x11inputdevice.h"
0028 #include "x11wacom.h"
0029 #include "xinputproperty.h"
0030 
0031 #include <QApplication>
0032 
0033 using namespace Wacom;
0034 
0035 namespace Wacom
0036 {
0037 class XinputAdaptorPrivate
0038 {
0039 public:
0040     QString deviceName;
0041     X11InputDevice device;
0042 }; // CLASS
0043 } // NAMESPACE
0044 
0045 XinputAdaptor::XinputAdaptor(const QString &deviceName)
0046     : PropertyAdaptor(nullptr)
0047     , d_ptr(new XinputAdaptorPrivate)
0048 {
0049     Q_D(XinputAdaptor);
0050     d->deviceName = deviceName;
0051     X11Input::findDevice(deviceName, d->device);
0052 }
0053 
0054 XinputAdaptor::~XinputAdaptor()
0055 {
0056     delete this->d_ptr;
0057 }
0058 
0059 const QList<Property> XinputAdaptor::getProperties() const
0060 {
0061     return XinputProperty::ids();
0062 }
0063 
0064 const QString XinputAdaptor::getProperty(const Property &property) const
0065 {
0066     Q_D(const XinputAdaptor);
0067 
0068     const XinputProperty *xinputproperty = XinputProperty::map(property);
0069 
0070     if (!xinputproperty) {
0071         qCWarning(KDED) << QString::fromLatin1("Can not get unsupported property '%1' from device '%2' using xinput!").arg(property.key()).arg(d->deviceName);
0072         return QString();
0073     }
0074 
0075     if (!d->device.isOpen()) {
0076         qCWarning(KDED)
0077             << QString::fromLatin1("Can not get property '%1' from device '%2' because the device is not available!").arg(property.key()).arg(d->deviceName);
0078         return QString();
0079     }
0080 
0081     return getProperty(*xinputproperty);
0082 }
0083 
0084 bool XinputAdaptor::setProperty(const Property &property, const QString &value)
0085 {
0086     Q_D(const XinputAdaptor);
0087 
0088     qCDebug(KDED) << QString::fromLatin1("Setting property '%1' to '%2'.").arg(property.key()).arg(value);
0089 
0090     const XinputProperty *xinputproperty = XinputProperty::map(property);
0091 
0092     if (!xinputproperty) {
0093         qCWarning(KDED) << QString::fromLatin1("Can not set unsupported property '%1' to '%2' on device '%3' using xinput!")
0094                                .arg(property.key())
0095                                .arg(value)
0096                                .arg(d->deviceName);
0097         return false;
0098     }
0099 
0100     if (!d->device.isOpen()) {
0101         qCWarning(KDED) << QString::fromLatin1("Can not set property '%1' to '%2' on device '%3' because the device is not available!")
0102                                .arg(property.key())
0103                                .arg(value)
0104                                .arg(d->deviceName);
0105         return false;
0106     }
0107 
0108     return setProperty(*xinputproperty, value);
0109 }
0110 
0111 bool XinputAdaptor::supportsProperty(const Property &property) const
0112 {
0113     return (XinputProperty::map(property) != nullptr);
0114 }
0115 
0116 const QString XinputAdaptor::getProperty(const XinputProperty &property) const
0117 {
0118     Q_D(const XinputAdaptor);
0119 
0120     if (property == XinputProperty::CursorAccelProfile) {
0121         return getLongProperty(property);
0122 
0123     } else if (property == XinputProperty::CursorAccelAdaptiveDeceleration) {
0124         return getFloatProperty(property);
0125 
0126     } else if (property == XinputProperty::CursorAccelConstantDeceleration) {
0127         return getFloatProperty(property);
0128 
0129     } else if (property == XinputProperty::CursorAccelVelocityScaling) {
0130         return getFloatProperty(property);
0131 
0132     } else if (property == XinputProperty::InvertScroll) {
0133         return (X11Wacom::isScrollDirectionInverted(d->deviceName) ? QLatin1String("on") : QLatin1String("off"));
0134 
0135     } else {
0136         qCWarning(KDED) << QString::fromLatin1("Getting Xinput property '%1' is not yet implemented!").arg(property.key());
0137     }
0138 
0139     return QString();
0140 }
0141 
0142 const QString XinputAdaptor::getFloatProperty(const XinputProperty &property, long nelements) const
0143 {
0144     Q_D(const XinputAdaptor);
0145 
0146     QList<float> values;
0147 
0148     if (!d->device.getFloatProperty(property.key(), values, nelements)) {
0149         qCWarning(KDED) << QString::fromLatin1("Failed to get Xinput property '%1' from device '%2'!").arg(property.key()).arg(d->deviceName);
0150         return QString();
0151     }
0152 
0153     return numbersToString<float>(values);
0154 }
0155 
0156 const QString XinputAdaptor::getLongProperty(const XinputProperty &property, long nelements) const
0157 {
0158     Q_D(const XinputAdaptor);
0159 
0160     QList<long> values;
0161 
0162     if (!d->device.getLongProperty(property.key(), values, nelements)) {
0163         qCWarning(KDED) << QString::fromLatin1("Failed to get Xinput property '%1' from device '%2'!").arg(property.key()).arg(d->deviceName);
0164         return QString();
0165     }
0166 
0167     return numbersToString<long>(values);
0168 }
0169 
0170 bool XinputAdaptor::mapTabletToScreen(const QString &screenArea) const
0171 {
0172     Q_D(const XinputAdaptor);
0173 
0174     // what we need is the Coordinate Transformation Matrix
0175     // in the normal case where the whole screen is used we end up with a 3x3 identity matrix
0176     // in our case we want to change that
0177     // | w  0  offsetX |
0178     // | 0  h  offsetY |
0179     // | 0  0     1    |
0180 
0181     qCDebug(KDED) << "Mapping to area: " << screenArea;
0182 
0183     if (screenArea.isEmpty()) {
0184         return false; // nothing to do
0185     }
0186 
0187     // get the space the user wants to use to map the tablet
0188     QRect screenAreaGeometry;
0189     QRect fullScreenGeometry = ScreensInfo::getUnifiedDisplayGeometry();
0190     ScreenSpace screenSpace(screenArea);
0191 
0192     switch (screenSpace.getType()) {
0193     case Wacom::ScreenSpace::ScreenSpaceType::Desktop: {
0194         qCDebug(KDED) << "Full screen area selected: " << fullScreenGeometry;
0195         screenAreaGeometry = fullScreenGeometry;
0196 
0197         break;
0198     }
0199     case Wacom::ScreenSpace::ScreenSpaceType::Output: {
0200         auto output = screenSpace.toString();
0201         QMap<QString, QRect> screenList = ScreensInfo::getScreenGeometries();
0202 
0203         if (!screenList.contains(output)) {
0204             qCDebug(KDED) << "Selected monitor no longer connected - using full screen: " << fullScreenGeometry;
0205             screenAreaGeometry = fullScreenGeometry;
0206         } else {
0207             qCDebug(KDED) << "Use monitor geometry for screen " << output << ": " << screenList.value(output);
0208             screenAreaGeometry = screenList.value(output);
0209         }
0210 
0211         break;
0212     }
0213     case Wacom::ScreenSpace::ScreenSpaceType::Area: {
0214         screenAreaGeometry = screenSpace.getArea();
0215         qCDebug(KDED) << "Geometry selected: " << screenAreaGeometry;
0216         break;
0217     }
0218     case Wacom::ScreenSpace::ScreenSpaceType::ArbitraryTranslationMatrix: {
0219         qCDebug(KDED) << "Arbitrary transformation matrix is selected" << screenSpace.getSpeed();
0220 
0221         return X11Wacom::setCoordinateTransformationMatrix(d->deviceName, 0, 0, screenSpace.getSpeed().x(), screenSpace.getSpeed().y());
0222     }
0223     }
0224 
0225     // calculate the new transformation matrix
0226     int screenX = screenAreaGeometry.x();
0227     int screenY = screenAreaGeometry.y();
0228     int screenW = screenAreaGeometry.width();
0229     int screenH = screenAreaGeometry.height();
0230 
0231     qreal w = static_cast<qreal>(screenW) / fullScreenGeometry.width();
0232     qreal h = static_cast<qreal>(screenH) / fullScreenGeometry.height();
0233 
0234     qreal offsetX = static_cast<qreal>(screenX) / fullScreenGeometry.width();
0235     qreal offsetY = static_cast<qreal>(screenY) / fullScreenGeometry.height();
0236 
0237     qCDebug(KDED) << "Apply Coordinate Transformation Matrix";
0238     qCDebug(KDED) << w << "0" << offsetX;
0239     qCDebug(KDED) << "0" << h << offsetY;
0240     qCDebug(KDED) << "0"
0241                   << "0"
0242                   << "1";
0243 
0244     return X11Wacom::setCoordinateTransformationMatrix(d->deviceName, offsetX, offsetY, w, h);
0245 }
0246 
0247 template<typename T>
0248 const QString XinputAdaptor::numbersToString(const QList<T> &values) const
0249 {
0250     QString result;
0251 
0252     for (int i = 0; i < values.size(); ++i) {
0253         if (i > 0) {
0254             result += QLatin1String(" ");
0255         }
0256 
0257         result += QString::number(values.at(i));
0258     }
0259 
0260     return result;
0261 }
0262 
0263 bool XinputAdaptor::setProperty(const XinputProperty &property, const QString &value) const
0264 {
0265     Q_D(const XinputAdaptor);
0266 
0267     if (property == XinputProperty::CursorAccelProfile) {
0268         return d->device.setLongProperty(property.key(), value);
0269 
0270     } else if (property == XinputProperty::CursorAccelAdaptiveDeceleration) {
0271         return d->device.setFloatProperty(property.key(), value);
0272 
0273     } else if (property == XinputProperty::CursorAccelConstantDeceleration) {
0274         return d->device.setFloatProperty(property.key(), value);
0275 
0276     } else if (property == XinputProperty::CursorAccelVelocityScaling) {
0277         return d->device.setFloatProperty(property.key(), value);
0278 
0279     } else if (property == XinputProperty::InvertScroll) {
0280         return X11Wacom::setScrollDirection(d->deviceName, StringUtils::asBool(value));
0281 
0282     } else if (property == XinputProperty::ScreenSpace) {
0283         return mapTabletToScreen(value);
0284 
0285     } else {
0286         qCWarning(KDED) << QString::fromLatin1("Setting Xinput property '%1' is not yet implemented!").arg(property.key());
0287     }
0288 
0289     return false;
0290 }