kde-workspace/kcontrol/input/logitechmouse.cpp
2015-02-27 09:28:46 +00:00

421 lines
12 KiB
C++

/*
* 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 <QPushButton>
#include <QWidget>
#include <QtGui/QProgressBar>
#include <QTimer>
#include <kdebug.h>
#include <kdialog.h>
#include <klocale.h>
#include <kmessagebox.h>
#include <config-workspace.h>
#include <config-kcontrol-input.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 )
, m_resolution( 0 )
{
if ( !name )
setObjectName( "LogitechMouse" );
cordlessNameLabel->setText( i18n("Mouse type: %1", objectName() ) );
m_mouseCapabilityFlags = mouseCapabilityFlags;
m_usbDeviceHandle = usb_open( usbDev );
if ( !m_usbDeviceHandle ) {
kWarning() << "Error opening usbfs file: " << usb_strerror() ;
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", 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()
{
if ( m_usbDeviceHandle )
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, '\0');
int result = -1;
if ( m_usbDeviceHandle )
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
m_channel = 0;
channelSelector->setEnabled( false );
batteryBox->setEnabled( false );
cordlessNameLabel->hide();
permissionProblemText->show();
} else {
// kDebug() << "P6 (connect status): " << (status[0] & 0xFF);
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 );
}
// kDebug() << "P0 (receiver type): " << (status[1] & 0xFF);
/*
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 );
// kDebug() << "PB1 (device Capabilities): " << (status[7] & 0xFF);
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->setValue( 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*/)
{
kDebug() << "Logitech mouse settings not saved - not implemented yet";
}
quint8 LogitechMouse::resolution()
{
// kDebug() << "resolution: " << m_resolution;
if ( 0 == m_resolution ) {
updateResolution();
}
return m_resolution;
}
void LogitechMouse::updateResolution()
{
char resolution;
int result = -1;
if ( m_usbDeviceHandle )
result = usb_control_msg( m_usbDeviceHandle,
USB_TYPE_VENDOR | USB_ENDPOINT_IN,
0x01,
0x000E,
0x0000,
&resolution,
0x0001,
100);
// kDebug() << "resolution is: " << resolution;
if (0 > result) {
kWarning() << "Error getting resolution from device : " << usb_strerror() ;
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) {
kWarning() << "Error setting resolution on device: " << usb_strerror() ;
}
}
void LogitechMouse::setLogitechTo400()
{
int result = usb_control_msg( m_usbDeviceHandle,
USB_TYPE_VENDOR,
0x02,
0x000E,
3,
NULL,
0x0000,
100);
if (0 > result) {
kWarning() << "Error setting resolution on device: " << usb_strerror() ;
}
}
quint8 LogitechMouse::batteryLevel() const
{
return m_batteryLevel;
}
quint8 LogitechMouse::channel() const
{
return m_channel;
}
bool LogitechMouse::isDualChannelCapable() const
{
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) {
kWarning() << "Error setting mouse to channel 1 : " << usb_strerror() ;
}
}
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) {
kWarning() << "Error setting mouse to channel 2 : " << usb_strerror() ;
}
}
QString LogitechMouse::cordlessName() const
{
switch ( m_cordlessNameIndex ) {
case 0x00:
return i18nc( "no cordless mouse", "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 "moc_logitechmouse.cpp"
#endif