diff options
-rw-r--r-- | src-qt5/core-utils/lumina-config/pages/getPage.h | 2 | ||||
-rw-r--r-- | src-qt5/core-utils/lumina-config/pages/page_mouse.cpp | 152 | ||||
-rw-r--r-- | src-qt5/core-utils/lumina-config/pages/page_mouse.h | 7 | ||||
-rw-r--r-- | src-qt5/core-utils/lumina-config/pages/page_mouse.ui | 43 | ||||
-rw-r--r-- | src-qt5/core/libLumina/LInputDevice.cpp | 181 | ||||
-rw-r--r-- | src-qt5/core/libLumina/LInputDevice.h | 28 | ||||
-rw-r--r-- | src-qt5/core/libLumina/LInputDevice.pri | 2 |
7 files changed, 338 insertions, 77 deletions
diff --git a/src-qt5/core-utils/lumina-config/pages/getPage.h b/src-qt5/core-utils/lumina-config/pages/getPage.h index ea0cfb00..a0785266 100644 --- a/src-qt5/core-utils/lumina-config/pages/getPage.h +++ b/src-qt5/core-utils/lumina-config/pages/getPage.h @@ -38,7 +38,7 @@ static QList<PAGEINFO> KnownPages(){ list << PageInfo("interface-menu", QObject::tr("Menu"), QObject::tr("Menu Plugins"), "preferences-plugin",QObject::tr("Change what options are shown on the desktop context menu"), "interface", QStringList(), QStringList() << "desktop" << "menu" << "plugins" << "shortcuts"); list << PageInfo("session-locale", QObject::tr("Localization"), QObject::tr("Locale Settings"), "preferences-desktop-locale",QObject::tr("Change the default locale settings for this user"), "user", QStringList(), QStringList() << "user"<<"locale"<<"language"<<"translations"); list << PageInfo("session-options", QObject::tr("General Options"), QObject::tr("User Settings"), "configure",QObject::tr("Change basic user settings such as time/date formats"), "user", QStringList(), QStringList() << "user"<<"settings"<<"time"<<"date"<<"icon"<<"reset"<<"numlock"<<"clock"); - //list << PageInfo("mouse", QObject::tr("Mouse Settings"), QObject::tr("Mouse Settings"), "input-mouse",QObject::tr("Adjust mouse settings"), "user", QStringList(), QStringList() << "user"<<"speed"<<"accel"<<"mouse"); + //list << PageInfo("mouse", QObject::tr("Input Device Settings"), QObject::tr("Input Device Settings"), "preferences-desktop-peripherals",QObject::tr("Adjust keyboard and mouse devices"), "user", QStringList(), QStringList() << "user"<<"speed"<<"accel"<<"mouse" << "keyboard"); //Now sort the items according to the translated name QStringList names; for(int i=0; i<list.length(); i++){ names << list[i].name; } diff --git a/src-qt5/core-utils/lumina-config/pages/page_mouse.cpp b/src-qt5/core-utils/lumina-config/pages/page_mouse.cpp index dbe075d7..1dd41295 100644 --- a/src-qt5/core-utils/lumina-config/pages/page_mouse.cpp +++ b/src-qt5/core-utils/lumina-config/pages/page_mouse.cpp @@ -8,15 +8,17 @@ #include "ui_page_mouse.h" #include "getPage.h" +#include <QSpinBox> +#include <QDoubleSpinBox> + //========== // PUBLIC //========== page_mouse::page_mouse(QWidget *parent) : PageWidget(parent), ui(new Ui::page_mouse()){ ui->setupUi(this); - connect(ui->slider_accel, SIGNAL(valueChanged(int)), this, SLOT(accelChanged(int)) ); - updateIcons(); - qDebug() << "List Devices:"; - QList<LInputDevice*> devices = LInput::listDevices(); + devices = LInput::listDevices(); + //DEBUG Code + /*qDebug() << "List Devices:"; for(int i=0; i<devices.length(); i++){ if(!devices[i]->isPointer()){ ::free( devices.takeAt(i)); @@ -24,9 +26,14 @@ page_mouse::page_mouse(QWidget *parent) : PageWidget(parent), ui(new Ui::page_mo }else{ qDebug() << "Found Pointer:" << devices[i]->devNumber(); qDebug() << " - isExtension:" << devices[i]->isExtension(); - qDebug() << " - Properties:" << devices[i]->listProperties(); + QList<int> props = devices[i]->listProperties(); + qDebug() << " - Properties:"; + for(int j=0; j<props.length(); j++){ + qDebug() << " --" <<devices[i]->propertyName(props[j])+" ("+QString::number(props[j])+")" <<" = " << devices[i]->getPropertyValue(props[j]); + } } - } + }*/ + generateUI(); } page_mouse::~page_mouse(){ @@ -43,35 +50,134 @@ void page_mouse::SaveSettings(){ void page_mouse::LoadSettings(int){ emit HasPendingChanges(false); - emit ChangePageTitle( tr("Desktop Settings") ); + emit ChangePageTitle( tr("Mouse Settings") ); } void page_mouse::updateIcons(){ - + for(int i=0; i<ui->tabWidget->count(); i++){ + ui->tabWidget->setTabIcon( i, LXDG::findIcon( "input-"+ui->tabWidget->tabWhatsThis(i).section(":",0,0), "" ) ); + } } //================= // PRIVATE //================= +void page_mouse::generateUI(){ + ui->tabWidget->clear(); //remove all tabs (just in case) + int mouse = 1; + int keyboard = 1; + qDebug() << "Devices Found:" << devices.length(); + for(int i=0; i<devices.length(); i++){ + QTreeWidget *tree = 0; + if(!devices[i]->isExtension()){ + //Make a new tab for this device + tree = new QTreeWidget(this); + tree->setHeaderHidden(true); + tree->setColumnCount(2); + if(devices[i]->isPointer()){ + int tab = ui->tabWidget->addTab(tree, LXDG::findIcon("input-mouse",""), QString(tr("Mouse #%1")).arg(QString::number(mouse)) ); + ui->tabWidget->setTabWhatsThis(tab, "mouse:"+QString::number(devices[i]->devNumber())); + mouse++; + }else{ + int tab = ui->tabWidget->addTab(tree, LXDG::findIcon("input-keyboard",""), QString(tr("Keyboard #%1")).arg(QString::number(keyboard)) ); + ui->tabWidget->setTabWhatsThis(tab, "keyboard:"+QString::number(devices[i]->devNumber()) ); + keyboard++; + } + }else{ + //Find the associated tab for this extension device + int tab = 0; + QString type = devices[i]->isPointer() ? "mouse" : "keyboard"; + int num = devices[i]->devNumber(); + for(int t=ui->tabWidget->count()-1; t>0; t--){ + if(ui->tabWidget->tabWhatsThis(t).startsWith(type) && ui->tabWidget->tabWhatsThis(t).section(":",-1).toInt() < num ){ tab = t; break; } + } + tree = static_cast<QTreeWidget*>( ui->tabWidget->widget(tab) ); + } + if(tree!=0){ populateDeviceTree(tree, devices[i]); } + } +} + +void page_mouse::populateDeviceTree(QTreeWidget *tree, LInputDevice *device){ + QTreeWidgetItem *top = new QTreeWidgetItem(tree); + if(device->isExtension()){ + top->setText( 0, QString(tr("Extension Device #%1")).arg(QString::number(tree->topLevelItemCount())) ); + }else{ top->setText(0, tr("Master Device")); } + top->setWhatsThis(0, QString(device->isPointer() ? "mouse" : "keyboard")+":"+QString::number(device->devNumber()) ); //save this for later + top->setFirstColumnSpanned(true); + top->setExpanded(true); + tree->addTopLevelItem(top); + //Now add all the child properties to this item + QList<int> props = device->listProperties(); + for(int i=0; i<props.length(); i++){ + QTreeWidgetItem *tmp = new QTreeWidgetItem(top); + tmp->setWhatsThis(0, QString::number(props[i]) ); + tmp->setText(0, device->propertyName(props[i])); + top->addChild(tmp); + populateDeviceItemValue(tree, tmp, device->getPropertyValue(props[i]), QString::number(device->devNumber())+":"+QString::number(props[i]) ); + } + //Clean up the tree widget as needed + top->sortChildren(0, Qt::AscendingOrder); + tree->resizeColumnToContents(0); +} + +void page_mouse::populateDeviceItemValue(QTreeWidget *tree, QTreeWidgetItem *it, QVariant value, QString id){ + if(value.type()==QVariant::Int){ + //Could be a boolian - check the name for known "enable" states + if(it->text(0).toLower().contains("enable") || it->text(0).toLower().contains("emulation") ){ + //Just use a checkable column within the item + bool enabled = (value.toInt()==1); + it->setText(1,""); + it->setCheckState(1, enabled ? Qt::Checked : Qt::Unchecked); + }else{ + //Use a QSpinBox + QSpinBox *box = new QSpinBox(); + box->setRange(0,100); + box->setValue( value.toInt() ); + tree->setItemWidget(it, 1, box); + connect(box, SIGNAL(valueChanged(int)), this, SLOT(valueChanged()) ); + } + }else if(value.canConvert<double>()){ + //Use a QDoubleSpinBox + QDoubleSpinBox *box = new QDoubleSpinBox(); + box->setRange(0,100); + box->setValue( value.toInt() ); + tree->setItemWidget(it, 1, box); + connect(box, SIGNAL(valueChanged(double)), this, SLOT(valueChanged()) ); + }else if(value.canConvert<QList<QVariant>>()){ + //Not Modifiable - just use the label in the item + QList<QVariant> list = value.toList(); + QStringList txtList; + for(int i=0; i<list.length(); i++){ txtList << list[i].toString(); } + it->setText(1, txtList.join(", ") ); + }else if( value.canConvert<QString>() ){ + //Not Modifiable - just use the label in the item + it->setText(1, value.toString()); + } +} //================= // PRIVATE SLOTS //================= -void page_mouse::accelChanged(int val){ - if(val<=4){ - val = 4-val; - ui->label_accel->setText( QString("1/%1").arg(QString::number(val)) ); - QProcess::startDetached("xset mouse 1/"+QString::number(val)); - }else{ - val = val-4; - if(val%2==0){ - val = val/2; - ui->label_accel->setText( QString::number(val) ); - QProcess::startDetached("xset mouse "+QString::number(val)); - }else{ - ui->label_accel->setText( QString::number(val)+"/2" ); - QProcess::startDetached("xset mouse "+QString::number(val)+"/2"); - } +void page_mouse::valueChanged(){ + //WILL NOT WORK - the widgets within the tree item *do not* activate the item when clicked + // - so the current item is NOT guaranteed to be the one which was modified + //Get the current Tab/TreeWidget + QTreeWidget *tree = static_cast<QTreeWidget*>(ui->tabWidget->widget( ui->tabWidget->currentIndex() ) ); + if(tree==0){ return; } + //Now get the current item in the tree + QTreeWidgetItem *it = tree->currentItem(); + if(it==0){ return; } + qDebug() << "Item Value Changed:" << it->text(0); + //Now read the value of the item and save that into the device + QVariant value; + if(tree->itemWidget(it, 1)!=0){ + //Got Item Widget + + }else if(it->text(1)==""){ + //Checkbox + value = QVariant( (it->checkState(1)==Qt::Checked) ? 1 : 0 ); } + + } diff --git a/src-qt5/core-utils/lumina-config/pages/page_mouse.h b/src-qt5/core-utils/lumina-config/pages/page_mouse.h index 849917c5..d16ec214 100644 --- a/src-qt5/core-utils/lumina-config/pages/page_mouse.h +++ b/src-qt5/core-utils/lumina-config/pages/page_mouse.h @@ -30,7 +30,12 @@ private: Ui::page_mouse *ui; QList<LInputDevice*> devices; + void generateUI(); + void populateDeviceTree(QTreeWidget *tree, LInputDevice *device); + void populateDeviceItemValue(QTreeWidget *tree, QTreeWidgetItem *it, QVariant value, QString id); + private slots: - void accelChanged(int val); + void valueChanged(); + }; #endif diff --git a/src-qt5/core-utils/lumina-config/pages/page_mouse.ui b/src-qt5/core-utils/lumina-config/pages/page_mouse.ui index 619e38dc..a6c2e53f 100644 --- a/src-qt5/core-utils/lumina-config/pages/page_mouse.ui +++ b/src-qt5/core-utils/lumina-config/pages/page_mouse.ui @@ -13,44 +13,17 @@ <property name="windowTitle"> <string>Form</string> </property> - <layout class="QFormLayout" name="formLayout"> - <item row="0" column="0"> - <widget class="QLabel" name="label"> - <property name="text"> - <string>Mouse Acceleration</string> + <layout class="QVBoxLayout" name="verticalLayout"> + <item> + <widget class="QTabWidget" name="tabWidget"> + <property name="iconSize"> + <size> + <width>32</width> + <height>32</height> + </size> </property> </widget> </item> - <item row="0" column="1"> - <layout class="QHBoxLayout" name="horizontalLayout"> - <item> - <widget class="QSlider" name="slider_accel"> - <property name="maximum"> - <number>20</number> - </property> - <property name="value"> - <number>4</number> - </property> - <property name="orientation"> - <enum>Qt::Horizontal</enum> - </property> - <property name="tickPosition"> - <enum>QSlider::TicksBelow</enum> - </property> - <property name="tickInterval"> - <number>2</number> - </property> - </widget> - </item> - <item> - <widget class="QLabel" name="label_accel"> - <property name="text"> - <string notr="true"/> - </property> - </widget> - </item> - </layout> - </item> </layout> </widget> <resources/> diff --git a/src-qt5/core/libLumina/LInputDevice.cpp b/src-qt5/core/libLumina/LInputDevice.cpp index d141e39a..a04dd607 100644 --- a/src-qt5/core/libLumina/LInputDevice.cpp +++ b/src-qt5/core/libLumina/LInputDevice.cpp @@ -17,6 +17,8 @@ #include <xcb/xinput.h> #include <xcb/xproto.h> +#include <LUtils.h> + //=================== // LInputDevice Class //=================== @@ -24,8 +26,10 @@ LInputDevice::LInputDevice(unsigned int id, unsigned int type){ devID = id; devType = type; + //ATOM_FLOAT = 0; //init this when needed later //devName = name; getProperties(); //need to populate the name/atom correlations for properties + readProperties(); //populate the hash with the current values of the properties } LInputDevice::~LInputDevice(){ @@ -53,17 +57,46 @@ bool LInputDevice::isExtension(){ } // Property Management -QStringList LInputDevice::listProperties(){ +QList<int> LInputDevice::listProperties(){ return devProps.keys(); } -QVariant LInputDevice::propertyValue(QString prop){ - if(!devProps.contains(prop)){ return QVariant(); } - //Now generate the property request - // xcb_input_get_device_property_cookie_t cookie = xcb_input_get_device_property_unchecked( QX11Info::connection(), devProps.value(prop), \ -// XCB_ATOM_ATOM, 0, 1000, devID, NULL); - QVariant result; - return result; +QString LInputDevice::propertyName(int prop){ + if(devProps.contains(prop)){ return devProps[prop].name; } + else{ return ""; } +} + +QVariant LInputDevice::getPropertyValue(int prop){ + if(devProps.contains(prop)){ return devProps[prop].value; } + else{ return QVariant(); } +} + +bool LInputDevice::setPropertyValue(int prop, QVariant value){ + if(!devProps.contains(prop)){ return false; } + //Need the float atom for some properties - make sure we have that first + /*if(ATOM_FLOAT==0){ + xcb_intern_atom_reply_t *ar = xcb_intern_atom_reply(QX11Info::connection(), \ + xcb_intern_atom(QX11Info::connection(), 0, 1, "FLOAT"), NULL); + if(ar!=0){ + ATOM_FLOAT = ar->atom; + free(ar); + } + }*/ + //Now setup the argument + bool ok = false; + QStringList args; + args << "--set-prop"; + args << QString::number(devID); + args << QString::number(prop); //prop ID + args << variantToString(value); + ok = (0 == LUtils::runCmd("xinput", args) ); + if(ok){ + //Need to update the value in the hash as well + propData dat = devProps[prop]; + dat.value = value; + devProps.insert(prop, dat); + } + return ok; } // === PRIVATE === @@ -78,12 +111,142 @@ void LInputDevice::getProperties(){ for(int i=0; i<reply->num_atoms; i++){ cookies << xcb_get_atom_name(QX11Info::connection(), atoms[i]); } for(int i=0; i<reply->num_atoms; i++){ xcb_get_atom_name_reply_t *nr = xcb_get_atom_name_reply(QX11Info::connection(), cookies[i], NULL); - devProps.insert(QString::fromUtf8( xcb_get_atom_name_name(nr), xcb_get_atom_name_name_length(nr) ),atoms[i] ); + propData DATA; + DATA.name = QString::fromUtf8( xcb_get_atom_name_name(nr), xcb_get_atom_name_name_length(nr) ); + DATA.atom = atoms[i]; + DATA.id = (int)(atoms[i]); + devProps.insert(DATA.id,DATA); ::free(nr); } //Done with data structure ::free(reply); } + +void LInputDevice::readProperties(){ + QList<int> props = devProps.keys(); + //XINPUT UTILITY USAGE (alternative to XCB which actually works right now) + QStringList info = LUtils::getCmdOutput("xinput list-props "+QString::number(devID)); + for(int i=0; i<props.length(); i++){ + propData PROP = devProps[props[i]]; + QStringList filter = info.filter(" ("+QString::number(PROP.id)+"):"); + if(filter.length()==1){ + QString val = filter.first().section("):",1,-1).simplified(); + //Now figure out what type of value this is and save it into the QVariant + QVariant variant; + if(val.split(", ").length()>1){ + //some kind of array + QList<QVariant> list; + QStringList valList = val.split(", "); + for(int j=0; j<valList.length(); j++){ list << valueToVariant(valList[j]); } + variant = QVariant(list); + }else{ + variant = valueToVariant(val); + } + PROP.value = variant; + } + devProps.insert(props[i], PROP); + } + +//XCB Code (non-functional - issue with library itself? 12/6/16 - Ken Moore) + /*QVariant result; + if(!devProps.contains(prop)){qDebug() << "Invalid Property"; return result; } + //Now generate the property request + xcb_input_get_device_property_cookie_t cookie = xcb_input_get_device_property_unchecked( QX11Info::connection(), devProps.value(prop).atom, \ + XCB_ATOM_ATOM, 0, 1000, devID, 0); + xcb_input_get_device_property_reply_t *reply = xcb_input_get_device_property_reply(QX11Info::connection(), cookie, NULL); + if(reply==0){ qDebug() << "Could not get reply!"; return result; } + //Now read off the value of the property + if(ATOM_FLOAT==0){ + xcb_intern_atom_reply_t *ar = xcb_intern_atom_reply(QX11Info::connection(), \ + xcb_intern_atom(QX11Info::connection(), 0, 1, "FLOAT"), NULL); + if(ar!=0){ + ATOM_FLOAT = ar->atom; + free(ar); + } + } + //Turn the reply into the proper items array (depends on format of the return data) + xcb_input_get_device_property_items_t items; + qDebug() <<QByteArray::fromRawData( (char*)(xcb_input_get_device_property_items(reply) ) , reply->num_items); + void *buffer = xcb_input_get_device_property_items(reply); + xcb_input_get_device_property_items_serialize( &buffer, reply->num_items, reply->format, &items); + + //if(reply->num_items > 0){ + //qDebug() << "Format:" << reply->format << "Length:" << length; + //qDebug() << "Response Type:" << reply->response_type << "Pads:" << reply->pad0 << reply->pad1; + switch(reply->type){ + case XCB_ATOM_INTEGER: + //qDebug() << "Got Integer"; + + break; + case XCB_ATOM_CARDINAL: + //qDebug() << "Got Cardinal"; + + break; + case XCB_ATOM_STRING: + qDebug() << "Got String:"; + if(reply->format==8){ + result.setValue( QByteArray::fromRawData( (char*) xcb_input_get_device_property_items_data_8(&items), sizeof(xcb_input_get_device_property_items_data_8(&items))/sizeof(char)) ); + } + break; + case XCB_ATOM_ATOM: + //qDebug() << "Got Atom"; + + break; + default: + qDebug() << "Other Type:" << reply->type; + } + //} + free(reply); //done with this structure + return result;*/ +} + +QVariant LInputDevice::valueToVariant(QString value){ + //Read through the string and see what type of value it is + if(value.count("\"")==2){ + //String value or atom + if(value.endsWith(")")){ + //ATOM (name string +(atomID)) + return QVariant(value); //don't strip off the atom number -- keep that within the parenthesis + }else{ + //String + value = value.section("\"",1,-2); //everything between the quotes + return QVariant(value); + } + }else if(value.contains(".")){ + //float/double number + return QVariant( value.toDouble() ); + }else{ + //integer or boolian (no way to tell right now - assume all int) + bool ok = false; + int intval = value.toInt(&ok); + if(ok){ return QVariant(intval); } + } + return QVariant(); +} + +QString LInputDevice::variantToString(QVariant value){ + if( value.canConvert< QList<QVariant> >() ){ + //List of variants + QStringList out; + QList<QVariant> list = value.toList(); + for(int i=0; i<list.length(); i++){ out << variantToString(list[i]); } + return out.join(", "); + }else{ + //Single value + if(value.canConvert<double>() ){ + return QString::number(value.toDouble()); + }else if(value.canConvert<int>() ){ + return QString::number(value.toInt()); + }else if( value.canConvert<QString>() ){ + //See if this is an atom first + QString val = value.toString(); + if(val.contains("(")){ val = val.section("(",1,-1).section(")",0,0); } + return val; + } + } + return ""; //nothing to return +} + //====================== // LInput Static Functions //====================== diff --git a/src-qt5/core/libLumina/LInputDevice.h b/src-qt5/core/libLumina/LInputDevice.h index f7a4713c..82dee4fd 100644 --- a/src-qt5/core/libLumina/LInputDevice.h +++ b/src-qt5/core/libLumina/LInputDevice.h @@ -18,6 +18,14 @@ #include <xcb/xproto.h> +//Internal data structure for storing the property information +struct propData{ + int id; + QString name; + QVariant value; + xcb_atom_t atom; +}; + class LInputDevice{ public: LInputDevice(unsigned int id, unsigned int type); //don't use this directly - use the "listDevices()" function instead @@ -31,16 +39,22 @@ public: bool isExtension(); //Property Management - QStringList listProperties(); - QVariant propertyValue(QString prop); + QList<int> listProperties(); + QString propertyName(int prop); + QVariant getPropertyValue(int prop); + bool setPropertyValue(int prop, QVariant value); private: - unsigned int devID; //device ID number - assigned at class creation - unsigned int devType; //device "use" identifier - assigned at class creation - QHash<QString, xcb_atom_t> devProps; //Known device properties <name, atom> + unsigned int devID; //device ID number - assigned at class creation + unsigned int devType; //device "use" identifier - assigned at class creation + QHash<int, propData> devProps; //Known device properties <id#, properties struct> + + void getProperties(); + void readProperties(); + QVariant valueToVariant(QString value); //xinput output to QVariant + QString variantToString(QVariant value); //QVariant to xinput input string - void getProperties(); - //QString devName; //device name - use this for cross-session management (id #'s can get changed every session) + //QString devName; //device name - use this for cross-session management (id #'s can get changed every session) }; //Static functions for overall management diff --git a/src-qt5/core/libLumina/LInputDevice.pri b/src-qt5/core/libLumina/LInputDevice.pri index e90728ce..a5f88a05 100644 --- a/src-qt5/core/libLumina/LInputDevice.pri +++ b/src-qt5/core/libLumina/LInputDevice.pri @@ -10,4 +10,4 @@ HEADERS *= $${PWD}/LInputDevice.h INCLUDEPATH *= ${PWD} #include LUtils and LuminaOS -#include(LUtils.pri) +include(LUtils.pri) |