File indexing completed on 2024-11-24 05:00:47
0001 #include <cmath> 0002 0003 #include "xlibtouchpad.h" 0004 #include <X11/Xlib-xcb.h> 0005 #include <X11/extensions/XInput.h> 0006 #include <X11/extensions/XInput2.h> 0007 #include <xserver-properties.h> 0008 0009 static QVariant negateVariant(const QVariant &value) 0010 { 0011 if (value.typeId() == QMetaType::Type::Double) { 0012 return QVariant(-value.toDouble()); 0013 } else if (value.typeId() == QMetaType::Type::Int) { 0014 return QVariant(-value.toInt()); 0015 } 0016 return value; 0017 } 0018 0019 XlibTouchpad::XlibTouchpad(Display *display, int deviceId) 0020 : m_display(display) 0021 , m_connection(XGetXCBConnection(display)) 0022 , m_deviceId(deviceId) 0023 { 0024 m_floatType.intern(m_connection, "FLOAT"); 0025 m_enabledAtom.intern(m_connection, XI_PROP_ENABLED); 0026 } 0027 0028 bool XlibTouchpad::applyConfig(const QVariantHash &p) 0029 { 0030 m_props.clear(); 0031 0032 bool error = false; 0033 for (const QString &name : std::as_const(m_supported)) { 0034 QVariantHash::ConstIterator i = p.find(name); 0035 if (i == p.end()) { 0036 continue; 0037 } 0038 const Parameter *par = findParameter(name); 0039 if (par) { 0040 QVariant value(i.value()); 0041 0042 double k = getPropertyScale(name); 0043 if (k != 1.0) { 0044 bool ok = false; 0045 value = QVariant(value.toDouble(&ok) * k); 0046 if (!ok) { 0047 error = true; 0048 continue; 0049 } 0050 } 0051 0052 if (m_negate.contains(name)) { 0053 QVariantHash::ConstIterator i = p.find(m_negate[name]); 0054 if (i != p.end() && i.value().toBool()) { 0055 value = negateVariant(value); 0056 } 0057 } 0058 0059 if (name == "CoastingSpeed") { 0060 QVariantHash::ConstIterator coastingEnabled = p.find("Coasting"); 0061 if (coastingEnabled != p.end() && !coastingEnabled.value().toBool()) { 0062 value = QVariant(0); 0063 } 0064 } 0065 0066 if (!setParameter(par, value)) { 0067 error = true; 0068 } 0069 } 0070 } 0071 0072 flush(); 0073 0074 return !error; 0075 } 0076 0077 bool XlibTouchpad::getConfig(QVariantHash &p) 0078 { 0079 if (m_supported.isEmpty()) { 0080 return false; 0081 } 0082 0083 m_props.clear(); 0084 0085 bool error = false; 0086 for (const QString &name : std::as_const(m_supported)) { 0087 const Parameter *par = findParameter(name); 0088 if (!par) { 0089 continue; 0090 } 0091 0092 QVariant value(getParameter(par)); 0093 if (!value.isValid()) { 0094 error = true; 0095 continue; 0096 } 0097 0098 double k = getPropertyScale(name); 0099 if (k != 1.0) { 0100 bool ok = false; 0101 value = QVariant(value.toDouble(&ok) / k); 0102 if (!ok) { 0103 error = true; 0104 continue; 0105 } 0106 } 0107 0108 if (m_negate.contains(name)) { 0109 bool negative = value.toDouble() < 0.0; 0110 p[m_negate[name]] = QVariant(negative); 0111 if (negative) { 0112 value = negateVariant(value); 0113 } 0114 } 0115 0116 if (name == "CoastingSpeed") { 0117 bool coasting = value.toDouble() != 0.0; 0118 p["Coasting"] = QVariant(coasting); 0119 if (!coasting) { 0120 continue; 0121 } 0122 } 0123 0124 p[name] = value; 0125 } 0126 0127 return !error; 0128 } 0129 0130 void XlibTouchpad::loadSupportedProperties(const Parameter *props) 0131 { 0132 m_paramList = props; 0133 for (const Parameter *param = props; param->name; param++) { 0134 QLatin1String name(param->prop_name); 0135 0136 if (!m_atoms.contains(name)) { 0137 m_atoms.insert(name, std::make_shared<XcbAtom>(m_connection, param->prop_name)); 0138 } 0139 } 0140 0141 for (const Parameter *p = props; p->name; p++) { 0142 if (getParameter(p).isValid()) { 0143 m_supported.append(p->name); 0144 } 0145 } 0146 } 0147 0148 QVariant XlibTouchpad::getParameter(const Parameter *par) 0149 { 0150 PropertyInfo *p = getDevProperty(QLatin1String(par->prop_name)); 0151 if (!p || par->prop_offset >= p->nitems) { 0152 return QVariant(); 0153 } 0154 0155 return p->value(par->prop_offset); 0156 } 0157 0158 void XlibTouchpad::flush() 0159 { 0160 for (const QLatin1String &name : std::as_const(m_changed)) { 0161 m_props[name].set(); 0162 } 0163 m_changed.clear(); 0164 0165 XFlush(m_display); 0166 } 0167 0168 double XlibTouchpad::getPropertyScale(const QString &name) const 0169 { 0170 Q_UNUSED(name); 0171 return 1.0; 0172 } 0173 0174 PropertyInfo *XlibTouchpad::getDevProperty(const QLatin1String &propName) 0175 { 0176 if (m_props.contains(propName)) { 0177 return &m_props[propName]; 0178 } 0179 0180 if (!m_atoms.contains(propName) || !m_atoms[propName]) { 0181 return nullptr; 0182 } 0183 0184 xcb_atom_t prop = m_atoms[propName]->atom(); 0185 if (!prop) { 0186 return nullptr; 0187 } 0188 0189 PropertyInfo p(m_display, m_deviceId, prop, m_floatType.atom()); 0190 if (!p.b && !p.f && !p.i) { 0191 return nullptr; 0192 } 0193 return &m_props.insert(propName, p).value(); 0194 } 0195 0196 bool XlibTouchpad::setParameter(const Parameter *par, const QVariant &value) 0197 { 0198 QLatin1String propName(par->prop_name); 0199 PropertyInfo *p = getDevProperty(propName); 0200 if (!p || par->prop_offset >= p->nitems) { 0201 return false; 0202 } 0203 0204 QVariant converted(value); 0205 QMetaType::Type convType = QMetaType::Type::Int; 0206 if (p->f) { 0207 convType = QMetaType::Type::Double; 0208 } else if (value.typeId() == QMetaType::Type::Double) { 0209 converted = QVariant(qRound(static_cast<qreal>(value.toDouble()))); 0210 } 0211 0212 if (!converted.convert(QMetaType(convType))) { 0213 return false; 0214 } 0215 0216 if (converted == p->value(par->prop_offset)) { 0217 return true; 0218 } 0219 0220 if (p->b) { 0221 p->b[par->prop_offset] = static_cast<char>(converted.toInt()); 0222 } else if (p->i) { 0223 p->i[par->prop_offset] = converted.toInt(); 0224 } else if (p->f) { 0225 p->f[par->prop_offset] = converted.toDouble(); 0226 } 0227 0228 m_changed.insert(propName); 0229 return true; 0230 } 0231 0232 void XlibTouchpad::setEnabled(bool enable) 0233 { 0234 PropertyInfo enabled(m_display, m_deviceId, m_enabledAtom.atom(), 0); 0235 if (enabled.b && *(enabled.b) != enable) { 0236 *(enabled.b) = enable; 0237 enabled.set(); 0238 } 0239 0240 flush(); 0241 } 0242 0243 bool XlibTouchpad::enabled() 0244 { 0245 PropertyInfo enabled(m_display, m_deviceId, m_enabledAtom.atom(), 0); 0246 return enabled.value(0).toBool(); 0247 } 0248 0249 const Parameter *XlibTouchpad::findParameter(const QString &name) 0250 { 0251 for (const Parameter *par = m_paramList; par->name; par++) { 0252 if (name == par->name) { 0253 return par; 0254 } 0255 } 0256 return nullptr; 0257 }