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.
418 lines
12 KiB
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 <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, 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(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;
|
|
}
|
|
|
|
}
|
|
|
|
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
|
|
|