summaryrefslogtreecommitdiffstats
path: root/kcontrol/input/logitechmouse.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'kcontrol/input/logitechmouse.cpp')
-rw-r--r--kcontrol/input/logitechmouse.cpp417
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
+