2014-11-13 19:30:51 +02:00
/*
* 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
2016-10-10 16:46:15 +00:00
# include <libusb.h>
2014-11-13 19:30:51 +02:00
# include "logitechmouse.h"
2016-10-10 16:46:15 +00:00
LogitechMouse : : LogitechMouse ( libusb_device * usbDev , int mouseCapabilityFlags , QWidget * parent , const char * name )
2014-11-13 19:30:51 +02:00
: LogitechMouseBase ( parent )
, m_resolution ( 0 )
{
if ( ! name )
setObjectName ( " LogitechMouse " ) ;
cordlessNameLabel - > setText ( i18n ( " Mouse type: %1 " , objectName ( ) ) ) ;
m_mouseCapabilityFlags = mouseCapabilityFlags ;
2016-10-10 16:46:15 +00:00
int result = libusb_open ( usbDev , & m_usbDeviceHandle ) ;
2014-11-13 19:30:51 +02:00
2016-10-10 16:46:15 +00:00
if ( ! m_usbDeviceHandle | | result < 0 ) {
kWarning ( ) < < " Error opening usbfs file: " < < libusb_strerror ( static_cast < libusb_error > ( result ) ) ;
2014-11-13 19:30:51 +02:00
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 )
2016-10-10 16:46:15 +00:00
libusb_close ( m_usbDeviceHandle ) ;
2014-11-13 19:30:51 +02:00
}
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 )
2016-10-10 16:46:15 +00:00
result = libusb_control_transfer ( m_usbDeviceHandle ,
LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_ENDPOINT , 0x09 ,
2014-11-13 19:30:51 +02:00
( 0x0003 | m_useSecondChannel ) ,
( 0x0000 | m_useSecondChannel ) ,
2016-10-10 16:46:15 +00:00
reinterpret_cast < uchar * > ( status . data ( ) ) ,
2014-11-13 19:30:51 +02:00
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 ;
2016-10-10 16:46:15 +00:00
int result = - 1 ; // LIBUSB_ERROR_IO
2014-11-13 19:30:51 +02:00
if ( m_usbDeviceHandle )
2016-10-10 16:46:15 +00:00
result = libusb_control_transfer ( m_usbDeviceHandle ,
LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_ENDPOINT ,
2014-11-13 19:30:51 +02:00
0x01 ,
0x000E ,
0x0000 ,
2016-10-10 16:46:15 +00:00
reinterpret_cast < uchar * > ( & resolution ) ,
2014-11-13 19:30:51 +02:00
0x0001 ,
100 ) ;
// kDebug() << "resolution is: " << resolution;
if ( 0 > result ) {
2016-10-10 16:46:15 +00:00
kWarning ( ) < < " Error getting resolution from device : " < < libusb_strerror ( static_cast < libusb_error > ( result ) ) ;
2014-11-13 19:30:51 +02:00
m_resolution = 0 ;
} else {
m_resolution = resolution ;
}
}
void LogitechMouse : : setLogitechTo800 ( )
{
2016-10-10 16:46:15 +00:00
int result = libusb_control_transfer ( m_usbDeviceHandle ,
LIBUSB_REQUEST_TYPE_VENDOR ,
2014-11-13 19:30:51 +02:00
0x02 ,
0x000E ,
4 ,
NULL ,
0x0000 ,
100 ) ;
if ( 0 > result ) {
2016-10-10 16:46:15 +00:00
kWarning ( ) < < " Error setting resolution on device: " < < libusb_strerror ( static_cast < libusb_error > ( result ) ) ;
2014-11-13 19:30:51 +02:00
}
}
void LogitechMouse : : setLogitechTo400 ( )
{
2016-10-10 16:46:15 +00:00
int result = libusb_control_transfer ( m_usbDeviceHandle ,
LIBUSB_REQUEST_TYPE_VENDOR ,
2014-11-13 19:30:51 +02:00
0x02 ,
0x000E ,
3 ,
NULL ,
0x0000 ,
100 ) ;
if ( 0 > result ) {
2016-10-10 16:46:15 +00:00
kWarning ( ) < < " Error setting resolution on device: " < < libusb_strerror ( static_cast < libusb_error > ( result ) ) ;
2014-11-13 19:30:51 +02:00
}
}
quint8 LogitechMouse : : batteryLevel ( ) const
{
return m_batteryLevel ;
}
quint8 LogitechMouse : : channel ( ) const
{
return m_channel ;
}
bool LogitechMouse : : isDualChannelCapable ( ) const
{
return m_twoChannelCapable ;
}
void LogitechMouse : : setChannel1 ( )
{
2016-10-10 16:46:15 +00:00
int result = libusb_control_transfer ( m_usbDeviceHandle ,
LIBUSB_REQUEST_TYPE_VENDOR ,
2014-11-13 19:30:51 +02:00
0x02 ,
( 0x0008 | m_useSecondChannel ) ,
( 0x0000 | m_useSecondChannel ) ,
NULL ,
0x0000 ,
1000 ) ;
if ( 0 > result ) {
2016-10-10 16:46:15 +00:00
kWarning ( ) < < " Error setting mouse to channel 1 : " < < libusb_strerror ( static_cast < libusb_error > ( result ) ) ;
2014-11-13 19:30:51 +02:00
}
}
void LogitechMouse : : setChannel2 ( )
{
2016-10-10 16:46:15 +00:00
int result = libusb_control_transfer ( m_usbDeviceHandle ,
LIBUSB_REQUEST_TYPE_VENDOR ,
2014-11-13 19:30:51 +02:00
0x02 ,
( 0x0008 | m_useSecondChannel ) ,
( 0x0001 | m_useSecondChannel ) ,
NULL ,
0x0000 ,
1000 ) ;
if ( 0 > result ) {
2016-10-10 16:46:15 +00:00
kWarning ( ) < < " Error setting mouse to channel 2 : " < < libusb_strerror ( static_cast < libusb_error > ( result ) ) ;
2014-11-13 19:30:51 +02:00
}
}
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 " ) ;
}
}
2015-02-27 09:28:46 +00:00
# include "moc_logitechmouse.cpp"
2014-11-13 19:30:51 +02:00
# endif