~ubuntu-branches/ubuntu/utopic/kde-workspace/utopic-proposed

« back to all changes in this revision

Viewing changes to kcontrol/input/logitechmouse.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Michał Zając
  • Date: 2011-07-09 08:31:15 UTC
  • Revision ID: james.westby@ubuntu.com-20110709083115-ohyxn6z93mily9fc
Tags: upstream-4.6.90
Import upstream version 4.6.90

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * logitechmouse.cpp
 
3
 *
 
4
 * Copyright (C) 2004 Brad Hards <bradh@frogmouth.net>
 
5
 *
 
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.
 
10
 *
 
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.
 
15
 *
 
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.
 
19
 */
 
20
 
 
21
 
 
22
#include <QPushButton>
 
23
#include <QWidget>
 
24
#include <QtGui/QProgressBar>
 
25
#include <QTimer>
 
26
 
 
27
#include <kdebug.h>
 
28
#include <kdialog.h>
 
29
#include <klocale.h>
 
30
#include <kmessagebox.h>
 
31
 
 
32
#include <config-workspace.h>
 
33
#include <config-kcontrol-input.h>
 
34
#ifdef HAVE_LIBUSB
 
35
#include <usb.h>
 
36
 
 
37
#include "logitechmouse.h"
 
38
 
 
39
LogitechMouse::LogitechMouse( struct usb_device *usbDev, int mouseCapabilityFlags, QWidget* parent, const char* name )
 
40
    : LogitechMouseBase( parent )
 
41
    , m_resolution( 0 )
 
42
{
 
43
    if ( !name )
 
44
        setObjectName( "LogitechMouse" );
 
45
 
 
46
    cordlessNameLabel->setText( i18n("Mouse type: %1", objectName() ) );
 
47
 
 
48
    m_mouseCapabilityFlags = mouseCapabilityFlags;
 
49
 
 
50
    m_usbDeviceHandle = usb_open( usbDev );
 
51
 
 
52
    if ( !m_usbDeviceHandle ) {
 
53
        kWarning() << "Error opening usbfs file: " << usb_strerror() ;
 
54
        return;
 
55
    }
 
56
 
 
57
    if ( mouseCapabilityFlags & USE_CH2 ) {
 
58
       m_useSecondChannel = 0x0100;
 
59
    } else {
 
60
        m_useSecondChannel = 0x0000;
 
61
    }
 
62
 
 
63
    permissionProblemText->hide();
 
64
 
 
65
    if ( mouseCapabilityFlags & HAS_RES ) {
 
66
        updateResolution();
 
67
        resolutionSelector->setEnabled( true );
 
68
 
 
69
        connect( button400cpi, SIGNAL( clicked() ), parent, SLOT( changed() ) );
 
70
        connect( button800cpi, SIGNAL( clicked() ), parent, SLOT( changed() ) );
 
71
 
 
72
        if ( 4 == resolution() ) {
 
73
            button800cpi->setChecked( true );
 
74
        } else if ( 3 == resolution() ) {
 
75
            button400cpi->setChecked( true );
 
76
        } else {
 
77
            // it must have failed, try to help out
 
78
            resolutionSelector->setEnabled(false);
 
79
            permissionProblemText->show();
 
80
        }
 
81
    }
 
82
 
 
83
    if ( mouseCapabilityFlags & HAS_CSR ) {
 
84
 
 
85
        initCordlessStatusReporting();
 
86
 
 
87
        // Do a name
 
88
        cordlessNameLabel->setText( i18n("Mouse type: %1", cordlessName() ) );
 
89
        cordlessNameLabel->setEnabled( true );
 
90
 
 
91
        // Display the battery power level - the level gets updated in updateGUI()
 
92
        batteryBox->setEnabled( true );
 
93
 
 
94
        // Channel
 
95
        channelSelector->setEnabled( true );
 
96
        // if the channel is changed, we need to turn off the timer, otherwise it
 
97
        // just resets the button to reflect the current status. The timer is
 
98
        // started again when we applyChanges()
 
99
        connect( channel1, SIGNAL( clicked() ), this, SLOT( stopTimerForNow() ) );
 
100
        connect( channel1, SIGNAL( clicked() ), parent, SLOT( changed() ) );
 
101
        if ( isDualChannelCapable() ) {
 
102
            channel2->setEnabled( true );
 
103
            connect( channel2, SIGNAL( clicked() ), this, SLOT( stopTimerForNow() ) );
 
104
            connect( channel2, SIGNAL( clicked() ), parent, SLOT( changed() ) );
 
105
        }
 
106
 
 
107
        updateGUI();
 
108
    }
 
109
 
 
110
}
 
111
 
 
112
LogitechMouse::~LogitechMouse()
 
113
{
 
114
    if ( m_usbDeviceHandle )
 
115
        usb_close( m_usbDeviceHandle );
 
116
}
 
117
 
 
118
void LogitechMouse::initCordlessStatusReporting()
 
119
{
 
120
    updateCordlessStatus();
 
121
    doUpdate = new QTimer( this ); // will be automatically deleted
 
122
    connect( doUpdate, SIGNAL( timeout() ), this, SLOT( updateGUI() ) );
 
123
    doUpdate->start( 20000 );
 
124
}
 
125
 
 
126
void LogitechMouse::updateCordlessStatus()
 
127
{
 
128
    QByteArray status(8, '\0');
 
129
 
 
130
    int result = -1;
 
131
 
 
132
    if ( m_usbDeviceHandle )
 
133
        result = usb_control_msg( m_usbDeviceHandle,
 
134
                                    USB_TYPE_VENDOR | USB_ENDPOINT_IN,0x09,
 
135
                                    (0x0003 | m_useSecondChannel),
 
136
                                    (0x0000 | m_useSecondChannel),
 
137
                                    status.data(),
 
138
                                    0x0008,
 
139
                                    1000);
 
140
 
 
141
    if (0 > result) {
 
142
        // We probably have a permission problem
 
143
        m_channel = 0;
 
144
        channelSelector->setEnabled( false );
 
145
        batteryBox->setEnabled( false );
 
146
        cordlessNameLabel->hide();
 
147
        permissionProblemText->show();
 
148
    } else {
 
149
        // kDebug() << "P6 (connect status): " << (status[0] & 0xFF);
 
150
        if ( status[0] & 0x20 ) { // mouse is talking
 
151
            m_connectStatus = ( status[0] & 0x80 );
 
152
            m_mousePowerup = ( status[0] & 0x40 );
 
153
            m_receiverUnlock = ( status[0] & 0x10 );
 
154
            m_waitLock = ( status[0] & 0x08 );
 
155
        }
 
156
 
 
157
        // kDebug() << "P0 (receiver type): " << (status[1] & 0xFF);
 
158
        /*
 
159
         0x38 = pid C501
 
160
         0x39 = pid C502
 
161
         0x3B = pid C504
 
162
         0x3C = pid C508
 
163
         0x3D = pid C506
 
164
         0x3E = pid C505
 
165
        */
 
166
 
 
167
        m_cordlessNameIndex = (status[2] & 0xFF);
 
168
 
 
169
        m_batteryLevel = (status[3] & 0x07 );
 
170
        if ( status[3] & 0x08 ) {
 
171
            m_channel = 2;
 
172
        } else {
 
173
            m_channel = 1;
 
174
        }
 
175
 
 
176
        m_cordlessSecurity = ( ( status[4] ) & ( status[5] << 8 ) );
 
177
 
 
178
        m_caseShape = ( status[6] & 0x7F );
 
179
 
 
180
        // kDebug() << "PB1 (device Capabilities): " << (status[7] & 0xFF);
 
181
        m_numberOfButtons = 2 + ( status[7] & 0x07 ); // 9 means something more than 8
 
182
        m_twoChannelCapable = ( status[7] & 0x40 );
 
183
        m_verticalRoller = ( status[7] & 0x08 );
 
184
        m_horizontalRoller = ( status[7] & 0x10 );
 
185
        m_has800cpi = ( status[7] & 0x20 );
 
186
    }
 
187
 
 
188
}
 
189
 
 
190
void LogitechMouse::updateGUI()
 
191
{
 
192
    updateCordlessStatus();
 
193
 
 
194
    batteryBar->setValue( batteryLevel() );
 
195
 
 
196
    if ( isDualChannelCapable() ) {
 
197
        if ( 2 == channel() ) {
 
198
            channel2->setChecked( true );
 
199
        } else if ( 1 == channel() ) {
 
200
            channel1->setChecked( true );
 
201
        } // else it might have failed - we don't do anything
 
202
    }
 
203
}
 
204
 
 
205
void LogitechMouse::stopTimerForNow()
 
206
{
 
207
    doUpdate->stop();
 
208
}
 
209
 
 
210
void LogitechMouse::applyChanges()
 
211
{
 
212
    if ( m_mouseCapabilityFlags & HAS_RES ) {
 
213
        if ( ( resolution() == 4 ) && ( button400cpi->isChecked() ) ) {
 
214
            // then we are in 800cpi mode, but want 400cpi
 
215
            setLogitechTo400();
 
216
        } else if ( ( resolution() == 3 ) && (button800cpi->isChecked() ) ) {
 
217
            // then we are in 400 cpi mode, but want 800 cpi
 
218
            setLogitechTo800();
 
219
        }
 
220
    }
 
221
 
 
222
    if ( isDualChannelCapable() ) {
 
223
        if ( ( channel() == 2 ) && ( channel1->isChecked() ) ) {
 
224
           // we are on channel 2, but want channel 1
 
225
           setChannel1();
 
226
           KMessageBox::information(this, i18n("RF channel 1 has been set. Please press Connect button on mouse to re-establish link"), i18n("Press Connect Button") );
 
227
        } else if ( ( channel() == 1 ) && ( channel2->isChecked() ) ) {
 
228
            // we are on channel 1, but want channel 2
 
229
            setChannel2();
 
230
            KMessageBox::information(this, i18n("RF channel 2 has been set. Please press Connect button on mouse to re-establish link"), i18n("Press Connect Button") );
 
231
        }
 
232
 
 
233
        initCordlessStatusReporting();
 
234
    }
 
235
}
 
236
 
 
237
void LogitechMouse::save(KConfig * /*config*/)
 
238
{
 
239
    kDebug() << "Logitech mouse settings not saved - not implemented yet";
 
240
}
 
241
 
 
242
quint8 LogitechMouse::resolution()
 
243
{
 
244
    // kDebug() << "resolution: " << m_resolution;
 
245
    if ( 0 == m_resolution ) {
 
246
        updateResolution();
 
247
    }
 
248
    return m_resolution;
 
249
}
 
250
 
 
251
void LogitechMouse::updateResolution()
 
252
{
 
253
    char resolution;
 
254
 
 
255
    int result = -1;
 
256
 
 
257
    if ( m_usbDeviceHandle )
 
258
        result = usb_control_msg( m_usbDeviceHandle,
 
259
                                   USB_TYPE_VENDOR | USB_ENDPOINT_IN,
 
260
                                   0x01,
 
261
                                   0x000E,
 
262
                                   0x0000,
 
263
                                   &resolution,
 
264
                                   0x0001,
 
265
                                   100);
 
266
 
 
267
    // kDebug() << "resolution is: " << resolution;
 
268
    if (0 > result) {
 
269
        kWarning() << "Error getting resolution from device : " << usb_strerror() ;
 
270
        m_resolution = 0;
 
271
    } else {
 
272
        m_resolution = resolution;
 
273
    }
 
274
}
 
275
 
 
276
void LogitechMouse::setLogitechTo800()
 
277
{
 
278
    int result = usb_control_msg( m_usbDeviceHandle,
 
279
                                  USB_TYPE_VENDOR,
 
280
                                  0x02,
 
281
                                  0x000E,
 
282
                                  4,
 
283
                                  NULL,
 
284
                                  0x0000,
 
285
                                  100);
 
286
    if (0 > result) {
 
287
        kWarning() << "Error setting resolution on device: " << usb_strerror() ;
 
288
    }
 
289
}
 
290
 
 
291
void LogitechMouse::setLogitechTo400()
 
292
{
 
293
    int result = usb_control_msg( m_usbDeviceHandle,
 
294
                                  USB_TYPE_VENDOR,
 
295
                                  0x02,
 
296
                                  0x000E,
 
297
                                  3,
 
298
                                  NULL,
 
299
                                  0x0000,
 
300
                                  100);
 
301
    if (0 > result) {
 
302
        kWarning() << "Error setting resolution on device: " << usb_strerror() ;
 
303
    }
 
304
}
 
305
 
 
306
quint8 LogitechMouse::batteryLevel() const
 
307
{
 
308
    return m_batteryLevel;
 
309
}
 
310
 
 
311
 
 
312
quint8 LogitechMouse::channel() const
 
313
{
 
314
    return m_channel;
 
315
}
 
316
 
 
317
bool LogitechMouse::isDualChannelCapable() const
 
318
{
 
319
    return m_twoChannelCapable;
 
320
}
 
321
 
 
322
void LogitechMouse::setChannel1()
 
323
{
 
324
    int result =  usb_control_msg( m_usbDeviceHandle,
 
325
                                   USB_TYPE_VENDOR,
 
326
                                   0x02,
 
327
                                   (0x0008 | m_useSecondChannel),
 
328
                                   (0x0000 | m_useSecondChannel),
 
329
                                   NULL,
 
330
                                   0x0000,
 
331
                                   1000);
 
332
 
 
333
    if (0 > result) {
 
334
        kWarning() << "Error setting mouse to channel 1 : " << usb_strerror() ;
 
335
    }
 
336
 
 
337
}
 
338
 
 
339
void LogitechMouse::setChannel2()
 
340
{
 
341
    int result =  usb_control_msg( m_usbDeviceHandle,
 
342
                                   USB_TYPE_VENDOR,
 
343
                                   0x02,
 
344
                                   (0x0008 | m_useSecondChannel),
 
345
                                   (0x0001 | m_useSecondChannel),
 
346
                                   NULL,
 
347
                                   0x0000,
 
348
                                   1000);
 
349
 
 
350
    if (0 > result) {
 
351
        kWarning() << "Error setting mouse to channel 2 : " << usb_strerror() ;
 
352
    }
 
353
 
 
354
}
 
355
 
 
356
QString LogitechMouse::cordlessName() const
 
357
{
 
358
    switch ( m_cordlessNameIndex ) {
 
359
    case 0x00:
 
360
        return i18nc( "no cordless mouse", "none" );
 
361
        break;
 
362
    case 0x04:
 
363
        return i18n( "Cordless Mouse" );
 
364
        break;
 
365
    case 0x05:
 
366
        return i18n( "Cordless Wheel Mouse" );
 
367
        break;
 
368
    case 0x06:
 
369
        return i18n( "Cordless MouseMan Wheel" );
 
370
        break;
 
371
    case 0x07:
 
372
        return i18n( "Cordless Wheel Mouse" );
 
373
        break;
 
374
    case 0x08:
 
375
        return i18n( "Cordless Wheel Mouse" );
 
376
        break;
 
377
    case 0x09:
 
378
        return i18n( "Cordless TrackMan Wheel" );
 
379
        break;
 
380
    case 0x0A:
 
381
        return i18n( "TrackMan Live" );
 
382
        break;
 
383
    case 0x0C:
 
384
        return i18n( "Cordless TrackMan FX" );
 
385
        break;
 
386
    case 0x0D:
 
387
        return i18n( "Cordless MouseMan Optical" );
 
388
        break;
 
389
    case 0x0E:
 
390
        return i18n( "Cordless Optical Mouse" );
 
391
        break;
 
392
    case 0x0F:
 
393
        return i18n( "Cordless Mouse" );
 
394
        break;
 
395
    case 0x12:
 
396
        return i18n( "Cordless MouseMan Optical (2ch)" );
 
397
        break;
 
398
    case 0x13:
 
399
        return i18n( "Cordless Optical Mouse (2ch)" );
 
400
        break;
 
401
    case 0x14:
 
402
        return i18n( "Cordless Mouse (2ch)" );
 
403
        break;
 
404
    case 0x82:
 
405
        return i18n( "Cordless Optical TrackMan" );
 
406
        break;
 
407
    case 0x8A:
 
408
        return i18n( "MX700 Cordless Optical Mouse" );
 
409
        break;
 
410
    case 0x8B:
 
411
        return i18n( "MX700 Cordless Optical Mouse (2ch)" );
 
412
        break;
 
413
    default:
 
414
        return i18n( "Unknown mouse");
 
415
    }
 
416
}
 
417
 
 
418
#include "logitechmouse.moc"
 
419
 
 
420
#endif
 
421