Make a branch to make krunner Good Enough For Aaron™.
[kdebase/uwolfer.git] / workspace / kcontrol / input / logitechmouse.cpp
blob575dee716fab94d7aeb08ff2084ff4792084f0aa
1 /*
2 * logitechmouse.cpp
4 * Copyright (C) 2004 Brad Hards <bradh@frogmouth.net>
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
22 #include <QPushButton>
23 #include <QWidget>
24 #include <QtGui/QProgressBar>
25 #include <QTimer>
27 #include <kdebug.h>
28 #include <kdialog.h>
29 #include <klocale.h>
30 #include <kmessagebox.h>
32 #include <config-workspace.h>
33 #include <config-kcontrol-input.h>
34 #ifdef HAVE_LIBUSB
35 #include <usb.h>
37 #include "logitechmouse.h"
39 LogitechMouse::LogitechMouse( struct usb_device *usbDev, int mouseCapabilityFlags, QWidget* parent, const char* name )
40 : LogitechMouseBase( parent )
42 if ( !name )
43 setObjectName( "LogitechMouse" );
45 cordlessNameLabel->setText( i18n("Mouse type: %1", objectName() ) );
47 m_mouseCapabilityFlags = mouseCapabilityFlags;
49 m_usbDeviceHandle = usb_open( usbDev );
51 if ( !m_usbDeviceHandle ) {
52 kWarning() << "Error opening usbfs file: " << usb_strerror() ;
53 return;
56 if ( mouseCapabilityFlags & USE_CH2 ) {
57 m_useSecondChannel = 0x0100;
58 } else {
59 m_useSecondChannel = 0x0000;
62 permissionProblemText->hide();
64 if ( mouseCapabilityFlags & HAS_RES ) {
65 updateResolution();
66 resolutionSelector->setEnabled( true );
68 connect( button400cpi, SIGNAL( clicked() ), parent, SLOT( changed() ) );
69 connect( button800cpi, SIGNAL( clicked() ), parent, SLOT( changed() ) );
71 if ( 4 == resolution() ) {
72 button800cpi->setChecked( true );
73 } else if ( 3 == resolution() ) {
74 button400cpi->setChecked( true );
75 } else {
76 // it must have failed, try to help out
77 resolutionSelector->setEnabled(false);
78 permissionProblemText->show();
82 if ( mouseCapabilityFlags & HAS_CSR ) {
84 initCordlessStatusReporting();
86 // Do a name
87 cordlessNameLabel->setText( i18n("Mouse type: %1", cordlessName() ) );
88 cordlessNameLabel->setEnabled( true );
90 // Display the battery power level - the level gets updated in updateGUI()
91 batteryBox->setEnabled( true );
93 // Channel
94 channelSelector->setEnabled( true );
95 // if the channel is changed, we need to turn off the timer, otherwise it
96 // just resets the button to reflect the current status. The timer is
97 // started again when we applyChanges()
98 connect( channel1, SIGNAL( clicked() ), this, SLOT( stopTimerForNow() ) );
99 connect( channel1, SIGNAL( clicked() ), parent, SLOT( changed() ) );
100 if ( isDualChannelCapable() ) {
101 channel2->setEnabled( true );
102 connect( channel2, SIGNAL( clicked() ), this, SLOT( stopTimerForNow() ) );
103 connect( channel2, SIGNAL( clicked() ), parent, SLOT( changed() ) );
106 updateGUI();
111 LogitechMouse::~LogitechMouse()
113 usb_close( m_usbDeviceHandle );
116 void LogitechMouse::initCordlessStatusReporting()
118 updateCordlessStatus();
119 doUpdate = new QTimer( this ); // will be automatically deleted
120 connect( doUpdate, SIGNAL( timeout() ), this, SLOT( updateGUI() ) );
121 doUpdate->start( 20000 );
124 void LogitechMouse::updateCordlessStatus()
126 QByteArray status(8, '\0');
128 int result = usb_control_msg( m_usbDeviceHandle,
129 USB_TYPE_VENDOR | USB_ENDPOINT_IN,0x09,
130 (0x0003 | m_useSecondChannel),
131 (0x0000 | m_useSecondChannel),
132 status.data(),
133 0x0008,
134 1000);
136 if (0 > result) {
137 // We probably have a permission problem
138 channelSelector->setEnabled( false );
139 batteryBox->setEnabled( false );
140 cordlessNameLabel->hide();
141 permissionProblemText->show();
142 } else {
143 // kDebug() << "P6 (connect status): " << (status[0] & 0xFF);
144 if ( status[0] & 0x20 ) { // mouse is talking
145 m_connectStatus = ( status[0] & 0x80 );
146 m_mousePowerup = ( status[0] & 0x40 );
147 m_receiverUnlock = ( status[0] & 0x10 );
148 m_waitLock = ( status[0] & 0x08 );
151 // kDebug() << "P0 (receiver type): " << (status[1] & 0xFF);
153 0x38 = pid C501
154 0x39 = pid C502
155 0x3B = pid C504
156 0x3C = pid C508
157 0x3D = pid C506
158 0x3E = pid C505
161 m_cordlessNameIndex = (status[2] & 0xFF);
163 m_batteryLevel = (status[3] & 0x07 );
164 if ( status[3] & 0x08 ) {
165 m_channel = 2;
166 } else {
167 m_channel = 1;
170 m_cordlessSecurity = ( ( status[4] ) & ( status[5] << 8 ) );
172 m_caseShape = ( status[6] & 0x7F );
174 // kDebug() << "PB1 (device Capabilities): " << (status[7] & 0xFF);
175 m_numberOfButtons = 2 + ( status[7] & 0x07 ); // 9 means something more than 8
176 m_twoChannelCapable = ( status[7] & 0x40 );
177 m_verticalRoller = ( status[7] & 0x08 );
178 m_horizontalRoller = ( status[7] & 0x10 );
179 m_has800cpi = ( status[7] & 0x20 );
184 void LogitechMouse::updateGUI()
186 updateCordlessStatus();
188 batteryBar->setValue( batteryLevel() );
190 if ( isDualChannelCapable() ) {
191 if ( 2 == channel() ) {
192 channel2->setChecked( true );
193 } else if ( 1 == channel() ) {
194 channel1->setChecked( true );
195 } // else it might have failed - we don't do anything
199 void LogitechMouse::stopTimerForNow()
201 doUpdate->stop();
204 void LogitechMouse::applyChanges()
206 if ( m_mouseCapabilityFlags & HAS_RES ) {
207 if ( ( resolution() == 4 ) && ( button400cpi->isChecked() ) ) {
208 // then we are in 800cpi mode, but want 400cpi
209 setLogitechTo400();
210 } else if ( ( resolution() == 3 ) && (button800cpi->isChecked() ) ) {
211 // then we are in 400 cpi mode, but want 800 cpi
212 setLogitechTo800();
216 if ( isDualChannelCapable() ) {
217 if ( ( channel() == 2 ) && ( channel1->isChecked() ) ) {
218 // we are on channel 2, but want channel 1
219 setChannel1();
220 KMessageBox::information(this, i18n("RF channel 1 has been set. Please press Connect button on mouse to re-establish link"), i18n("Press Connect Button") );
221 } else if ( ( channel() == 1 ) && ( channel2->isChecked() ) ) {
222 // we are on channel 1, but want channel 2
223 setChannel2();
224 KMessageBox::information(this, i18n("RF channel 2 has been set. Please press Connect button on mouse to re-establish link"), i18n("Press Connect Button") );
227 initCordlessStatusReporting();
231 void LogitechMouse::save(KConfig * /*config*/)
233 kDebug() << "Logitech mouse settings not saved - not implemented yet";
236 quint8 LogitechMouse::resolution()
238 // kDebug() << "resolution: " << m_resolution;
239 if ( 0 == m_resolution ) {
240 updateResolution();
242 return m_resolution;
245 void LogitechMouse::updateResolution()
247 char resolution;
249 int result = usb_control_msg( m_usbDeviceHandle,
250 USB_TYPE_VENDOR | USB_ENDPOINT_IN,
251 0x01,
252 0x000E,
253 0x0000,
254 &resolution,
255 0x0001,
256 100);
258 // kDebug() << "resolution is: " << resolution;
259 if (0 > result) {
260 kWarning() << "Error getting resolution from device : " << usb_strerror() ;
261 m_resolution = 0;
262 } else {
263 m_resolution = resolution;
267 void LogitechMouse::setLogitechTo800()
269 int result = usb_control_msg( m_usbDeviceHandle,
270 USB_TYPE_VENDOR,
271 0x02,
272 0x000E,
274 NULL,
275 0x0000,
276 100);
277 if (0 > result) {
278 kWarning() << "Error setting resolution on device: " << usb_strerror() ;
282 void LogitechMouse::setLogitechTo400()
284 int result = usb_control_msg( m_usbDeviceHandle,
285 USB_TYPE_VENDOR,
286 0x02,
287 0x000E,
289 NULL,
290 0x0000,
291 100);
292 if (0 > result) {
293 kWarning() << "Error setting resolution on device: " << usb_strerror() ;
297 quint8 LogitechMouse::batteryLevel()
299 return m_batteryLevel;
303 quint8 LogitechMouse::channel()
305 return m_channel;
308 bool LogitechMouse::isDualChannelCapable()
310 return m_twoChannelCapable;
313 void LogitechMouse::setChannel1()
315 int result = usb_control_msg( m_usbDeviceHandle,
316 USB_TYPE_VENDOR,
317 0x02,
318 (0x0008 | m_useSecondChannel),
319 (0x0000 | m_useSecondChannel),
320 NULL,
321 0x0000,
322 1000);
324 if (0 > result) {
325 kWarning() << "Error setting mouse to channel 1 : " << usb_strerror() ;
330 void LogitechMouse::setChannel2()
332 int result = usb_control_msg( m_usbDeviceHandle,
333 USB_TYPE_VENDOR,
334 0x02,
335 (0x0008 | m_useSecondChannel),
336 (0x0001 | m_useSecondChannel),
337 NULL,
338 0x0000,
339 1000);
341 if (0 > result) {
342 kWarning() << "Error setting mouse to channel 2 : " << usb_strerror() ;
347 QString LogitechMouse::cordlessName()
349 switch ( m_cordlessNameIndex ) {
350 case 0x00:
351 return i18n( "none" );
352 break;
353 case 0x04:
354 return i18n( "Cordless Mouse" );
355 break;
356 case 0x05:
357 return i18n( "Cordless Wheel Mouse" );
358 break;
359 case 0x06:
360 return i18n( "Cordless MouseMan Wheel" );
361 break;
362 case 0x07:
363 return i18n( "Cordless Wheel Mouse" );
364 break;
365 case 0x08:
366 return i18n( "Cordless Wheel Mouse" );
367 break;
368 case 0x09:
369 return i18n( "Cordless TrackMan Wheel" );
370 break;
371 case 0x0A:
372 return i18n( "TrackMan Live" );
373 break;
374 case 0x0C:
375 return i18n( "Cordless TrackMan FX" );
376 break;
377 case 0x0D:
378 return i18n( "Cordless MouseMan Optical" );
379 break;
380 case 0x0E:
381 return i18n( "Cordless Optical Mouse" );
382 break;
383 case 0x0F:
384 return i18n( "Cordless Mouse" );
385 break;
386 case 0x12:
387 return i18n( "Cordless MouseMan Optical (2ch)" );
388 break;
389 case 0x13:
390 return i18n( "Cordless Optical Mouse (2ch)" );
391 break;
392 case 0x14:
393 return i18n( "Cordless Mouse (2ch)" );
394 break;
395 case 0x82:
396 return i18n( "Cordless Optical TrackMan" );
397 break;
398 case 0x8A:
399 return i18n( "MX700 Cordless Optical Mouse" );
400 break;
401 case 0x8B:
402 return i18n( "MX700 Cordless Optical Mouse (2ch)" );
403 break;
404 default:
405 return i18n( "Unknown mouse");
409 #include "logitechmouse.moc"
411 #endif