You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
tdebase/kcontrol/input/logitechmouse.cpp

418 lines
12 KiB

/*
* 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 <tqdialog.h>
#include <tqpushbutton.h>
#include <tqlabel.h>
#include <tqradiobutton.h>
#include <tqbuttongroup.h>
#include <tqwidget.h>
#include <tqlayout.h>
#include <tqprogressbar.h>
#include <tqtimer.h>
#include <kdebug.h>
#include <kdialog.h>
#include <tdelocale.h>
#include <tdemessagebox.h>
#include <config.h>
#ifdef HAVE_LIBUSB
#include <usb.h>
#include "logitechmouse.h"
LogitechMouse::LogitechMouse( struct usb_device *usbDev, int mouseCapabilityFlags, TQWidget* 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, TQT_SIGNAL( clicked() ), parent, TQT_SLOT( changed() ) );
connect( button800cpi, TQT_SIGNAL( clicked() ), parent, TQT_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, TQT_SIGNAL( clicked() ), this, TQT_SLOT( stopTimerForNow() ) );
connect( channel1, TQT_SIGNAL( clicked() ), parent, TQT_SLOT( changed() ) );
if ( isDualChannelCapable() ) {
channel2->setEnabled( TRUE );
connect( channel2, TQT_SIGNAL( clicked() ), this, TQT_SLOT( stopTimerForNow() ) );
connect( channel2, TQT_SIGNAL( clicked() ), parent, TQT_SLOT( changed() ) );
}
updateGUI();
}
}
LogitechMouse::~LogitechMouse()
{
usb_close( m_usbDeviceHandle );
}
void LogitechMouse::initCordlessStatusReporting()
{
updateCordlessStatus();
doUpdate = new TQTimer( this ); // will be automatically deleted
connect( doUpdate, TQT_SIGNAL( timeout() ), this, TQT_SLOT( updateGUI() ) );
doUpdate->start( 20000 );
}
void LogitechMouse::updateCordlessStatus()
{
TQByteArray 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(TDEConfig * /*config*/)
{
kdDebug() << "Logitech mouse settings not saved - not implemented yet" << endl;
}
TQ_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;
}
}
TQ_UINT8 LogitechMouse::batteryLevel()
{
return m_batteryLevel;
}
TQ_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;
}
}
TQString 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