diff options
Diffstat (limited to 'kcontrol/input/logitechmouse.cpp')
-rw-r--r-- | kcontrol/input/logitechmouse.cpp | 417 |
1 files changed, 417 insertions, 0 deletions
diff --git a/kcontrol/input/logitechmouse.cpp b/kcontrol/input/logitechmouse.cpp new file mode 100644 index 000000000..1b8132a7e --- /dev/null +++ b/kcontrol/input/logitechmouse.cpp @@ -0,0 +1,417 @@ +/* + * logitechmouse.cpp + * + * Copyright (C) 2004 Brad Hards <bradh@frogmouth.net> + * + * 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 2 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, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + + +#include <qdialog.h> +#include <qpushbutton.h> +#include <qlabel.h> +#include <qradiobutton.h> +#include <qbuttongroup.h> +#include <qwidget.h> +#include <qlayout.h> +#include <qprogressbar.h> +#include <qtimer.h> + +#include <kdebug.h> +#include <kdialog.h> +#include <klocale.h> +#include <kmessagebox.h> + +#include <config.h> + +#ifdef HAVE_LIBUSB +#include <usb.h> + +#include "logitechmouse.h" + +LogitechMouse::LogitechMouse( struct usb_device *usbDev, int mouseCapabilityFlags, QWidget* parent, const char* name ) + : LogitechMouseBase( parent, name, 0 ) +{ + if ( !name ) + setName( "LogitechMouse" ); + + cordlessNameLabel->setText( i18n("Mouse type: %1").arg( this->name() ) ); + + m_mouseCapabilityFlags = mouseCapabilityFlags; + + m_usbDeviceHandle = usb_open( usbDev ); + + if ( 0 == m_usbDeviceHandle ) { + kdWarning() << "Error opening usbfs file: " << usb_strerror() << endl; + return; + } + + if ( mouseCapabilityFlags & USE_CH2 ) { + m_useSecondChannel = 0x0100; + } else { + m_useSecondChannel = 0x0000; + } + + permissionProblemText->hide(); + + if ( mouseCapabilityFlags & HAS_RES ) { + updateResolution(); + resolutionSelector->setEnabled( TRUE ); + + connect( button400cpi, SIGNAL( clicked() ), parent, SLOT( changed() ) ); + connect( button800cpi, SIGNAL( clicked() ), parent, SLOT( changed() ) ); + + if ( 4 == resolution() ) { + button800cpi->setChecked( TRUE ); + } else if ( 3 == resolution() ) { + button400cpi->setChecked( TRUE ); + } else { + // it must have failed, try to help out + resolutionSelector->setEnabled(FALSE); + permissionProblemText->show(); + } + } + + if ( mouseCapabilityFlags & HAS_CSR ) { + + initCordlessStatusReporting(); + + // Do a name + cordlessNameLabel->setText( i18n("Mouse type: %1").arg( cordlessName() ) ); + cordlessNameLabel->setEnabled( TRUE ); + + // Display the battery power level - the level gets updated in updateGUI() + batteryBox->setEnabled( TRUE ); + + // Channel + channelSelector->setEnabled( TRUE ); + // if the channel is changed, we need to turn off the timer, otherwise it + // just resets the button to reflect the current status. The timer is + // started again when we applyChanges() + connect( channel1, SIGNAL( clicked() ), this, SLOT( stopTimerForNow() ) ); + connect( channel1, SIGNAL( clicked() ), parent, SLOT( changed() ) ); + if ( isDualChannelCapable() ) { + channel2->setEnabled( TRUE ); + connect( channel2, SIGNAL( clicked() ), this, SLOT( stopTimerForNow() ) ); + connect( channel2, SIGNAL( clicked() ), parent, SLOT( changed() ) ); + } + + updateGUI(); + } + +} + +LogitechMouse::~LogitechMouse() +{ + usb_close( m_usbDeviceHandle ); +} + +void LogitechMouse::initCordlessStatusReporting() +{ + updateCordlessStatus(); + doUpdate = new QTimer( this ); // will be automatically deleted + connect( doUpdate, SIGNAL( timeout() ), this, SLOT( updateGUI() ) ); + doUpdate->start( 20000 ); +} + +void LogitechMouse::updateCordlessStatus() +{ + QByteArray status(8); + + int result = usb_control_msg( m_usbDeviceHandle, + USB_TYPE_VENDOR | USB_ENDPOINT_IN,0x09, + (0x0003 | m_useSecondChannel), + (0x0000 | m_useSecondChannel), + status.data(), + 0x0008, + 1000); + + if (0 > result) { + // We probably have a permission problem + channelSelector->setEnabled( FALSE ); + batteryBox->setEnabled( FALSE ); + cordlessNameLabel->hide(); + permissionProblemText->show(); + } else { + // kdDebug() << "P6 (connect status): " << (status[0] & 0xFF) << endl; + if ( status[0] & 0x20 ) { // mouse is talking + m_connectStatus = ( status[0] & 0x80 ); + m_mousePowerup = ( status[0] & 0x40 ); + m_receiverUnlock = ( status[0] & 0x10 ); + m_waitLock = ( status[0] & 0x08 ); + } + + // kdDebug() << "P0 (receiver type): " << (status[1] & 0xFF) << endl; + /* + 0x38 = pid C501 + 0x39 = pid C502 + 0x3B = pid C504 + 0x3C = pid C508 + 0x3D = pid C506 + 0x3E = pid C505 + */ + + m_cordlessNameIndex = (status[2] & 0xFF); + + m_batteryLevel = (status[3] & 0x07 ); + if ( status[3] & 0x08 ) { + m_channel = 2; + } else { + m_channel = 1; + } + + m_cordlessSecurity = ( ( status[4] ) & ( status[5] << 8 ) ); + + m_caseShape = ( status[6] & 0x7F ); + + // kdDebug() << "PB1 (device Capabilities): " << (status[7] & 0xFF) << endl; + m_numberOfButtons = 2 + ( status[7] & 0x07 ); // 9 means something more than 8 + m_twoChannelCapable = ( status[7] & 0x40 ); + m_verticalRoller = ( status[7] & 0x08 ); + m_horizontalRoller = ( status[7] & 0x10 ); + m_has800cpi = ( status[7] & 0x20 ); + } + +} + +void LogitechMouse::updateGUI() +{ + updateCordlessStatus(); + + batteryBar->setProgress( batteryLevel() ); + + if ( isDualChannelCapable() ) { + if ( 2 == channel() ) { + channel2->setChecked( TRUE ); + } else if ( 1 == channel() ) { + channel1->setChecked( TRUE ); + } // else it might have failed - we don't do anything + } +} + +void LogitechMouse::stopTimerForNow() +{ + doUpdate->stop(); +} + +void LogitechMouse::applyChanges() +{ + if ( m_mouseCapabilityFlags & HAS_RES ) { + if ( ( resolution() == 4 ) && ( button400cpi->isChecked() ) ) { + // then we are in 800cpi mode, but want 400cpi + setLogitechTo400(); + } else if ( ( resolution() == 3 ) && (button800cpi->isChecked() ) ) { + // then we are in 400 cpi mode, but want 800 cpi + setLogitechTo800(); + } + } + + if ( isDualChannelCapable() ) { + if ( ( channel() == 2 ) && ( channel1->isChecked() ) ) { + // we are on channel 2, but want channel 1 + setChannel1(); + KMessageBox::information(this, i18n("RF channel 1 has been set. Please press Connect button on mouse to re-establish link"), i18n("Press Connect Button") ); + } else if ( ( channel() == 1 ) && ( channel2->isChecked() ) ) { + // we are on channel 1, but want channel 2 + setChannel2(); + KMessageBox::information(this, i18n("RF channel 2 has been set. Please press Connect button on mouse to re-establish link"), i18n("Press Connect Button") ); + } + + initCordlessStatusReporting(); + } +} + +void LogitechMouse::save(KConfig * /*config*/) +{ + kdDebug() << "Logitech mouse settings not saved - not implemented yet" << endl; +} + +Q_UINT8 LogitechMouse::resolution() +{ + // kdDebug() << "resolution: " << m_resolution << endl; + if ( 0 == m_resolution ) { + updateResolution(); + } + return m_resolution; +} + +void LogitechMouse::updateResolution() +{ + char resolution; + + int result = usb_control_msg( m_usbDeviceHandle, + USB_TYPE_VENDOR | USB_ENDPOINT_IN, + 0x01, + 0x000E, + 0x0000, + &resolution, + 0x0001, + 100); + + // kdDebug() << "resolution is: " << resolution << endl; + if (0 > result) { + kdWarning() << "Error getting resolution from device : " << usb_strerror() << endl; + m_resolution = 0; + } else { + m_resolution = resolution; + } +} + +void LogitechMouse::setLogitechTo800() +{ + int result = usb_control_msg( m_usbDeviceHandle, + USB_TYPE_VENDOR, + 0x02, + 0x000E, + 4, + NULL, + 0x0000, + 100); + if (0 > result) { + kdWarning() << "Error setting resolution on device: " << usb_strerror() << endl; + } +} + +void LogitechMouse::setLogitechTo400() +{ + int result = usb_control_msg( m_usbDeviceHandle, + USB_TYPE_VENDOR, + 0x02, + 0x000E, + 3, + NULL, + 0x0000, + 100); + if (0 > result) { + kdWarning() << "Error setting resolution on device: " << usb_strerror() << endl; + } +} + +Q_UINT8 LogitechMouse::batteryLevel() +{ + return m_batteryLevel; +} + + +Q_UINT8 LogitechMouse::channel() +{ + return m_channel; +} + +bool LogitechMouse::isDualChannelCapable() +{ + return m_twoChannelCapable; +} + +void LogitechMouse::setChannel1() +{ + int result = usb_control_msg( m_usbDeviceHandle, + USB_TYPE_VENDOR, + 0x02, + (0x0008 | m_useSecondChannel), + (0x0000 | m_useSecondChannel), + NULL, + 0x0000, + 1000); + + if (0 > result) { + kdWarning() << "Error setting mouse to channel 1 : " << usb_strerror() << endl; + } + +} + +void LogitechMouse::setChannel2() +{ + int result = usb_control_msg( m_usbDeviceHandle, + USB_TYPE_VENDOR, + 0x02, + (0x0008 | m_useSecondChannel), + (0x0001 | m_useSecondChannel), + NULL, + 0x0000, + 1000); + + if (0 > result) { + kdWarning() << "Error setting mouse to channel 2 : " << usb_strerror() << endl; + } + +} + +QString LogitechMouse::cordlessName() +{ + switch ( m_cordlessNameIndex ) { + case 0x00: + return i18n( "none" ); + break; + case 0x04: + return i18n( "Cordless Mouse" ); + break; + case 0x05: + return i18n( "Cordless Wheel Mouse" ); + break; + case 0x06: + return i18n( "Cordless MouseMan Wheel" ); + break; + case 0x07: + return i18n( "Cordless Wheel Mouse" ); + break; + case 0x08: + return i18n( "Cordless Wheel Mouse" ); + break; + case 0x09: + return i18n( "Cordless TrackMan Wheel" ); + break; + case 0x0A: + return i18n( "TrackMan Live" ); + break; + case 0x0C: + return i18n( "Cordless TrackMan FX" ); + break; + case 0x0D: + return i18n( "Cordless MouseMan Optical" ); + break; + case 0x0E: + return i18n( "Cordless Optical Mouse" ); + break; + case 0x0F: + return i18n( "Cordless Mouse" ); + break; + case 0x12: + return i18n( "Cordless MouseMan Optical (2ch)" ); + break; + case 0x13: + return i18n( "Cordless Optical Mouse (2ch)" ); + break; + case 0x14: + return i18n( "Cordless Mouse (2ch)" ); + break; + case 0x82: + return i18n( "Cordless Optical TrackMan" ); + break; + case 0x8A: + return i18n( "MX700 Cordless Optical Mouse" ); + break; + case 0x8B: + return i18n( "MX700 Cordless Optical Mouse (2ch)" ); + break; + default: + return i18n( "Unknown mouse"); + } +} + +#include "logitechmouse.moc" + +#endif + |