#include #include "xlibtouchpad.h" #include #include #include #include static QVariant negateVariant(const QVariant &value) { if (value.type() == QVariant::Double) { return QVariant(-value.toDouble()); } else if (value.type() == QVariant::Int) { return QVariant(-value.toInt()); } return value; } XlibTouchpad::XlibTouchpad(Display *display, int deviceId) : m_display(display) , m_connection(XGetXCBConnection(display)) , m_deviceId(deviceId) { m_floatType.intern(m_connection, "FLOAT"); m_enabledAtom.intern(m_connection, XI_PROP_ENABLED); } bool XlibTouchpad::applyConfig(const QVariantHash &p) { m_props.clear(); bool error = false; for (const QString &name : qAsConst(m_supported)) { QVariantHash::ConstIterator i = p.find(name); if (i == p.end()) { continue; } const Parameter *par = findParameter(name); if (par) { QVariant value(i.value()); double k = getPropertyScale(name); if (k != 1.0) { bool ok = false; value = QVariant(value.toDouble(&ok) * k); if (!ok) { error = true; continue; } } if (m_negate.contains(name)) { QVariantHash::ConstIterator i = p.find(m_negate[name]); if (i != p.end() && i.value().toBool()) { value = negateVariant(value); } } if (name == "CoastingSpeed") { QVariantHash::ConstIterator coastingEnabled = p.find("Coasting"); if (coastingEnabled != p.end() && !coastingEnabled.value().toBool()) { value = QVariant(0); } } if (!setParameter(par, value)) { error = true; } } } flush(); return !error; } bool XlibTouchpad::getConfig(QVariantHash &p) { if (m_supported.isEmpty()) { return false; } m_props.clear(); bool error = false; for (const QString &name : qAsConst(m_supported)) { const Parameter *par = findParameter(name); if (!par) { continue; } QVariant value(getParameter(par)); if (!value.isValid()) { error = true; continue; } double k = getPropertyScale(name); if (k != 1.0) { bool ok = false; value = QVariant(value.toDouble(&ok) / k); if (!ok) { error = true; continue; } } if (m_negate.contains(name)) { bool negative = value.toDouble() < 0.0; p[m_negate[name]] = QVariant(negative); if (negative) { value = negateVariant(value); } } if (name == "CoastingSpeed") { bool coasting = value.toDouble() != 0.0; p["Coasting"] = QVariant(coasting); if (!coasting) { continue; } } p[name] = value; } return !error; } void XlibTouchpad::loadSupportedProperties(const Parameter *props) { m_paramList = props; for (const Parameter *param = props; param->name; param++) { QLatin1String name(param->prop_name); if (!m_atoms.contains(name)) { m_atoms.insert(name, QSharedPointer(new XcbAtom(m_connection, param->prop_name))); } } for (const Parameter *p = props; p->name; p++) { if (getParameter(p).isValid()) { m_supported.append(p->name); } } } QVariant XlibTouchpad::getParameter(const Parameter *par) { PropertyInfo *p = getDevProperty(QLatin1String(par->prop_name)); if (!p || par->prop_offset >= p->nitems) { return QVariant(); } return p->value(par->prop_offset); } void XlibTouchpad::flush() { for (const QLatin1String &name : qAsConst(m_changed)) { m_props[name].set(); } m_changed.clear(); XFlush(m_display); } double XlibTouchpad::getPropertyScale(const QString &name) const { Q_UNUSED(name); return 1.0; } PropertyInfo *XlibTouchpad::getDevProperty(const QLatin1String &propName) { if (m_props.contains(propName)) { return &m_props[propName]; } if (!m_atoms.contains(propName) || !m_atoms[propName]) { return nullptr; } xcb_atom_t prop = m_atoms[propName]->atom(); if (!prop) { return nullptr; } PropertyInfo p(m_display, m_deviceId, prop, m_floatType.atom()); if (!p.b && !p.f && !p.i) { return nullptr; } return &m_props.insert(propName, p).value(); } bool XlibTouchpad::setParameter(const Parameter *par, const QVariant &value) { QLatin1String propName(par->prop_name); PropertyInfo *p = getDevProperty(propName); if (!p || par->prop_offset >= p->nitems) { return false; } QVariant converted(value); QVariant::Type convType = QVariant::Int; if (p->f) { convType = QVariant::Double; } else if (value.type() == QVariant::Double) { converted = QVariant(qRound(static_cast(value.toDouble()))); } if (!converted.convert(convType)) { return false; } if (converted == p->value(par->prop_offset)) { return true; } if (p->b) { p->b[par->prop_offset] = static_cast(converted.toInt()); } else if (p->i) { p->i[par->prop_offset] = converted.toInt(); } else if (p->f) { p->f[par->prop_offset] = converted.toDouble(); } m_changed.insert(propName); return true; } void XlibTouchpad::setEnabled(bool enable) { PropertyInfo enabled(m_display, m_deviceId, m_enabledAtom.atom(), 0); if (enabled.b && *(enabled.b) != enable) { *(enabled.b) = enable; enabled.set(); } flush(); } bool XlibTouchpad::enabled() { PropertyInfo enabled(m_display, m_deviceId, m_enabledAtom.atom(), 0); return enabled.value(0).toBool(); } const Parameter *XlibTouchpad::findParameter(const QString &name) { for (const Parameter *par = m_paramList; par->name; par++) { if (name == par->name) { return par; } } return nullptr; }