4 * Copyright (c) 1997 Patrick Dowler dowler@morgul.fsh.uvic.ca
6 * Layout management, enhancements:
7 * Copyright (c) 1999 Dirk A. Mueller <dmuell@gmx.net>
9 * SC/DC/AutoSelect/ChangeCursor:
10 * Copyright (c) 2000 David Faure <faure@kde.org>
12 * Double click interval, drag time & dist
13 * Copyright (c) 2000 Bernd Gehrmann
15 * Large cursor support
16 * Visual activation TODO: speed
17 * Copyright (c) 2000 Rik Hemsley <rik@kde.org>
19 * White cursor support
20 * TODO: give user the option to choose a certain cursor font
23 * General/Advanced tabs
24 * Copyright (c) 2000 Brad Hughes <bhughes@trolltech.com>
26 * redesign for KDE 2.2
27 * Copyright (c) 2001 Ralf Nolden <nolden@kde.org>
29 * Logitech mouse support
30 * Copyright (C) 2004 Brad Hards <bradh@frogmouth.net>
32 * Requires the Qt widget libraries, available at no cost at
33 * http://www.troll.no/
35 * This program is free software; you can redistribute it and/or modify
36 * it under the terms of the GNU General Public License as published by
37 * the Free Software Foundation; either version 2 of the License, or
38 * (at your option) any later version.
40 * This program is distributed in the hope that it will be useful,
41 * but WITHOUT ANY WARRANTY; without even the implied warranty of
42 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
43 * GNU General Public License for more details.
45 * You should have received a copy of the GNU General Public License
46 * along with this program; if not, write to the Free Software
47 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
51 #include <QFormLayout>
58 #include <ktoolinvocation.h>
62 #include <kstandarddirs.h>
64 #include <kaboutdata.h>
65 #include <KPluginFactory>
66 #include <KPluginLoader>
68 #include <config-workspace.h>
74 #include <X11/Xutil.h>
75 #include <kglobalsettings.h>
81 K_PLUGIN_FACTORY(MouseConfigFactory
,
82 registerPlugin
<MouseConfig
>(); // mouse
84 K_EXPORT_PLUGIN(MouseConfigFactory("kcminput"))
86 MouseConfig::MouseConfig(QWidget
*parent
, const QVariantList
&args
)
87 : KCModule(MouseConfigFactory::componentData(), parent
, args
)
91 setQuickHelp( i18n("<h1>Mouse</h1> This module allows you to choose various"
92 " options for the way in which your pointing device works. Your"
93 " pointing device may be a mouse, trackball, or some other hardware"
94 " that performs a similar function."));
98 QBoxLayout
*top
= new QVBoxLayout(this);
100 top
->setSpacing(KDialog::spacingHint());
102 tabwidget
= new QTabWidget(this);
103 top
->addWidget(tabwidget
);
105 generalTab
= new KMouseDlg(this);
106 QButtonGroup
*group
= new QButtonGroup( generalTab
);
107 group
->setExclusive( true );
108 group
->addButton( generalTab
->singleClick
);
109 group
->addButton( generalTab
->doubleClick
);
111 tabwidget
->addTab(generalTab
, i18n("&General"));
113 group
= new QButtonGroup( generalTab
);
114 group
->setExclusive( true );
115 group
->addButton( generalTab
->rightHanded
,RIGHT_HANDED
);
116 group
->addButton( generalTab
->leftHanded
,LEFT_HANDED
);
118 connect(group
, SIGNAL(buttonClicked(int)), this, SLOT(changed()));
119 connect(group
, SIGNAL(buttonClicked(int)), this, SLOT(slotHandedChanged(int)));
121 wtstr
= i18n("If you are left-handed, you may prefer to swap the"
122 " functions of the left and right buttons on your pointing device"
123 " by choosing the 'left-handed' option. If your pointing device"
124 " has more than two buttons, only those that function as the"
125 " left and right buttons are affected. For example, if you have"
126 " a three-button mouse, the middle button is unaffected.");
127 generalTab
->handedBox
->setWhatsThis( wtstr
);
129 connect(generalTab
->doubleClick
, SIGNAL(clicked()), SLOT(changed()));
131 wtstr
= i18n("The default behavior in KDE is to select and activate"
132 " icons with a single click of the left button on your pointing"
133 " device. This behavior is consistent with what you would expect"
134 " when you click links in most web browsers. If you would prefer"
135 " to select with a single click, and activate with a double click,"
136 " check this option.");
137 generalTab
->doubleClick
->setWhatsThis( wtstr
);
139 wtstr
= i18n("Activates and opens a file or folder with a single click.");
140 generalTab
->singleClick
->setWhatsThis( wtstr
);
143 connect(generalTab
->cbAutoSelect
, SIGNAL(clicked()), this, SLOT(changed()));
145 wtstr
= i18n("If you check this option, pausing the mouse pointer"
146 " over an icon on the screen will automatically select that icon."
147 " This may be useful when single clicks activate icons, and you"
148 " want only to select the icon without activating it.");
149 generalTab
->cbAutoSelect
->setWhatsThis( wtstr
);
151 // slAutoSelect = new QSlider(0, 2000, 10, 0, QSlider::Horizontal, generalTab);
152 generalTab
->slAutoSelect
->setSingleStep( 125 );
153 generalTab
->slAutoSelect
->setPageStep( 125 );
154 generalTab
->slAutoSelect
->setTickPosition( QSlider::TicksBelow
);
155 generalTab
->slAutoSelect
->setTickInterval( 250 );
156 generalTab
->slAutoSelect
->setTracking( true );
158 wtstr
= i18n("If you have checked the option to automatically select"
159 " icons, this slider allows you to select how long the mouse pointer"
160 " must be paused over the icon before it is selected.");
161 generalTab
->slAutoSelect
->setWhatsThis( wtstr
);
163 connect(generalTab
->slAutoSelect
, SIGNAL(valueChanged(int)), this, SLOT(changed()));
165 connect(generalTab
->cb_pointershape
, SIGNAL(clicked()), this, SLOT(changed()));
167 connect(generalTab
->singleClick
, SIGNAL(clicked()), this, SLOT(changed()));
168 connect(generalTab
->singleClick
, SIGNAL(clicked()), this, SLOT(slotClick()));
169 connect(generalTab
->singleClick
, SIGNAL(clicked()), this, SLOT(slotSmartSliderEnabling()));
171 connect( generalTab
->doubleClick
, SIGNAL( clicked() ), this, SLOT( slotClick() ) );
172 connect( generalTab
->cbAutoSelect
, SIGNAL( clicked() ), this, SLOT( slotClick() ) );
173 connect(generalTab
->cbAutoSelect
, SIGNAL(clicked()), this, SLOT(slotSmartSliderEnabling()));
176 // Only allow setting reversing scroll polarity if we have scroll buttons
177 unsigned char map
[20];
178 if ( XGetPointerMapping(QX11Info::display(), map
, 20) >= 5 )
180 generalTab
->cbScrollPolarity
->setEnabled( true );
181 generalTab
->cbScrollPolarity
->show();
185 generalTab
->cbScrollPolarity
->setEnabled( false );
186 generalTab
->cbScrollPolarity
->hide();
188 connect(generalTab
->cbScrollPolarity
, SIGNAL(clicked()), this, SLOT(changed()));
189 connect(generalTab
->cbScrollPolarity
, SIGNAL(clicked()), this, SLOT(slotScrollPolarityChanged()));
192 themetab
= new ThemePage(this);
193 connect(themetab
, SIGNAL(changed(bool)), SLOT(changed()));
194 tabwidget
->addTab(themetab
, i18n("&Cursor Theme"));
197 advancedTab
= new QWidget(0);
198 advancedTab
->setObjectName("Advanced Tab");
199 tabwidget
->addTab(advancedTab
, i18n("Advanced"));
201 QFormLayout
*lay
= new QFormLayout(advancedTab
);
202 lay
->setMargin(KDialog::marginHint());
203 lay
->setSpacing(KDialog::spacingHint());
205 accel
= new KDoubleNumInput(0.1, 20, 2, advancedTab
, 0.1, 1);
206 accel
->setSuffix(i18n(" x"));
207 QLabel
* lbl
= new QLabel(i18n("Pointer acceleration:"), advancedTab
);
208 lbl
->setBuddy(accel
);
209 lay
->addRow(lbl
, accel
);
210 connect(accel
, SIGNAL(valueChanged(double)), this, SLOT(changed()));
212 wtstr
= i18n("<p>This option allows you to change the relationship"
213 " between the distance that the mouse pointer moves on the"
214 " screen and the relative movement of the physical device"
215 " itself (which may be a mouse, trackball, or some other"
216 " pointing device.)</p><p>"
217 " A high value for the acceleration will lead to large"
218 " movements of the mouse pointer on the screen even when"
219 " you only make a small movement with the physical device."
220 " Selecting very high values may result in the mouse pointer"
221 " flying across the screen, making it hard to control.</p>");
222 accel
->setWhatsThis( wtstr
);
224 thresh
= new KIntNumInput(20, advancedTab
);
225 thresh
->setRange(0,20,1);
226 thresh
->setSteps(1,1);
227 lbl
= new QLabel(i18n("Pointer threshold:"), advancedTab
);
228 lbl
->setBuddy(thresh
);
229 lay
->addRow(lbl
, thresh
);
230 connect(thresh
, SIGNAL(valueChanged(int)), this, SLOT(changed()));
231 connect(thresh
, SIGNAL(valueChanged(int)), this, SLOT(slotThreshChanged(int)));
232 slotThreshChanged(thresh
->value());
234 wtstr
= i18n("<p>The threshold is the smallest distance that the"
235 " mouse pointer must move on the screen before acceleration"
236 " has any effect. If the movement is smaller than the threshold,"
237 " the mouse pointer moves as if the acceleration was set to 1X;</p><p>"
238 " thus, when you make small movements with the physical device,"
239 " there is no acceleration at all, giving you a greater degree"
240 " of control over the mouse pointer. With larger movements of"
241 " the physical device, you can move the mouse pointer"
242 " rapidly to different areas on the screen.</p>");
243 thresh
->setWhatsThis( wtstr
);
245 // It would be nice if the user had a test field.
246 // Selecting such values in milliseconds is not intuitive
247 doubleClickInterval
= new KIntNumInput(2000, advancedTab
);
248 doubleClickInterval
->setRange(0, 2000, 100);
249 doubleClickInterval
->setSuffix(i18n(" msec"));
250 doubleClickInterval
->setSteps(100, 100);
251 lbl
= new QLabel(i18n("Double click interval:"), advancedTab
);
252 lbl
->setBuddy(doubleClickInterval
);
253 lay
->addRow(lbl
, doubleClickInterval
);
254 connect(doubleClickInterval
, SIGNAL(valueChanged(int)), this, SLOT(changed()));
256 wtstr
= i18n("The double click interval is the maximal time"
257 " (in milliseconds) between two mouse clicks which"
258 " turns them into a double click. If the second"
259 " click happens later than this time interval after"
260 " the first click, they are recognized as two"
261 " separate clicks.");
262 doubleClickInterval
->setWhatsThis( wtstr
);
264 dragStartTime
= new KIntNumInput(2000, advancedTab
);
265 dragStartTime
->setRange(0, 2000, 100);
266 dragStartTime
->setSuffix(i18n(" msec"));
267 dragStartTime
->setSteps(100, 100);
268 lbl
= new QLabel(i18n("Drag start time:"), advancedTab
);
269 lbl
->setBuddy(dragStartTime
);
270 lay
->addRow(lbl
, dragStartTime
);
271 connect(dragStartTime
, SIGNAL(valueChanged(int)), this, SLOT(changed()));
273 wtstr
= i18n("If you click with the mouse (e.g. in a multi-line"
274 " editor) and begin to move the mouse within the"
275 " drag start time, a drag operation will be initiated.");
276 dragStartTime
->setWhatsThis( wtstr
);
278 dragStartDist
= new KIntNumInput(20, advancedTab
);
279 dragStartDist
->setRange(1, 20, 1);
280 dragStartDist
->setSteps(1,1);
281 lbl
= new QLabel(i18n("Drag start distance:"), advancedTab
);
282 lbl
->setBuddy(dragStartDist
);
283 lay
->addRow(lbl
, dragStartDist
);
284 connect(dragStartDist
, SIGNAL(valueChanged(int)), this, SLOT(changed()));
285 connect(dragStartDist
, SIGNAL(valueChanged(int)), this, SLOT(slotDragStartDistChanged(int)));
286 slotDragStartDistChanged(dragStartDist
->value());
288 wtstr
= i18n("If you click with the mouse and begin to move the"
289 " mouse at least the drag start distance, a drag"
290 " operation will be initiated.");
291 dragStartDist
->setWhatsThis( wtstr
);
293 wheelScrollLines
= new KIntNumInput(3, advancedTab
);
294 wheelScrollLines
->setRange(1, 12, 1);
295 wheelScrollLines
->setSteps(1,1);
296 lbl
= new QLabel(i18n("Mouse wheel scrolls by:"), advancedTab
);
297 lbl
->setBuddy(wheelScrollLines
);
298 lay
->addRow(lbl
, wheelScrollLines
);
299 connect(wheelScrollLines
, SIGNAL(valueChanged(int)), this, SLOT(changed()));
300 connect(wheelScrollLines
, SIGNAL(valueChanged(int)), SLOT(slotWheelScrollLinesChanged(int)));
301 slotWheelScrollLinesChanged(wheelScrollLines
->value());
303 wtstr
= i18n("If you use the wheel of a mouse, this value determines the number of lines to scroll for each wheel movement. Note that if this number exceeds the number of visible lines, it will be ignored and the wheel movement will be handled as a page up/down movement.");
304 wheelScrollLines
->setWhatsThis(wtstr
);
307 QWidget
*mouse
= new QWidget(this);
308 mouse
->setObjectName("Mouse Navigation");
309 tabwidget
->addTab(mouse
, i18n("Mouse Navigation"));
311 QBoxLayout
*vbox
= new QVBoxLayout(mouse
);
312 vbox
->setMargin(KDialog::marginHint());
313 vbox
->setSpacing(KDialog::spacingHint());
315 QVBoxLayout
*vvbox
= new QVBoxLayout();
316 vbox
->addItem( vvbox
);
317 vvbox
->setSpacing(KDialog::spacingHint());
319 mouseKeys
= new QCheckBox(i18n("&Move pointer with keyboard (using the num pad)"), mouse
);
320 vvbox
->addWidget(mouseKeys
);
322 QFormLayout
*form
= new QFormLayout();
323 vvbox
->addItem( form
);
324 form
->setSpacing(KDialog::spacingHint());
326 mk_delay
= new KIntNumInput(mouse
);
327 mk_delay
->setSuffix(i18n(" msec"));
328 mk_delay
->setRange(1, 1000, 50);
329 lbl
= new QLabel(i18n("&Acceleration delay:"), mouse
);
330 lbl
->setBuddy(mk_delay
);
331 form
->addRow(lbl
, mk_delay
);
333 mk_interval
= new KIntNumInput(0, mouse
);
334 mk_interval
->setSuffix(i18n(" msec"));
335 mk_interval
->setRange(1, 1000, 10);
336 lbl
= new QLabel(i18n("R&epeat interval:"), mouse
);
337 lbl
->setBuddy(mk_interval
);
338 form
->addRow(lbl
, mk_interval
);
340 mk_time_to_max
= new KIntNumInput(0, mouse
);
341 mk_time_to_max
->setRange(100, 10000, 200);
342 mk_time_to_max
->setSuffix(i18n(" msec"));
343 lbl
= new QLabel(i18n("Acceleration &time:"), mouse
);
344 lbl
->setBuddy(mk_time_to_max
);
345 form
->addRow(lbl
, mk_time_to_max
);
347 mk_max_speed
= new KIntNumInput(0, mouse
);
348 mk_max_speed
->setRange(1, 2000, 20);
349 mk_max_speed
->setSuffix(i18n(" pixel/sec"));
350 lbl
= new QLabel(i18n("Ma&ximum speed:"), mouse
);
351 lbl
->setBuddy(mk_max_speed
);
352 form
->addRow(lbl
, mk_max_speed
);
354 mk_curve
= new KIntNumInput(0, mouse
);
355 mk_curve
->setRange(-1000, 1000, 100);
356 lbl
= new QLabel(i18n("Acceleration &profile:"), mouse
);
357 lbl
->setBuddy(mk_curve
);
358 form
->addRow(lbl
, mk_curve
);
360 connect(mouseKeys
, SIGNAL(clicked()), this, SLOT(checkAccess()));
361 connect(mouseKeys
, SIGNAL(clicked()), this, SLOT(changed()));
362 connect(mk_delay
, SIGNAL(valueChanged(int)), this, SLOT(changed()));
363 connect(mk_interval
, SIGNAL(valueChanged(int)), this, SLOT(changed()));
364 connect(mk_time_to_max
, SIGNAL(valueChanged(int)), this, SLOT(changed()));
365 connect(mk_max_speed
, SIGNAL(valueChanged(int)), this, SLOT(changed()));
366 connect(mk_curve
, SIGNAL(valueChanged(int)), this, SLOT(changed()));
371 settings
= new MouseSettings
;
373 // This part is for handling features on Logitech USB mice.
374 // It only works if libusb is available.
377 struct device_table
{
384 { VENDOR_LOGITECH
, 0xC00E, "M-BJ58", "Wheel Mouse Optical", HAS_RES
},
385 { VENDOR_LOGITECH
, 0xC00F, "M-BJ79", "MouseMan Traveler", HAS_RES
},
386 { VENDOR_LOGITECH
, 0xC012, "M-BL63B", "MouseMan Dual Optical", HAS_RES
},
387 { VENDOR_LOGITECH
, 0xC01B, "M-BP86", "MX310 Optical Mouse", HAS_RES
},
388 { VENDOR_LOGITECH
, 0xC01D, "M-BS81A", "MX510 Optical Mouse", HAS_RES
| HAS_SS
| HAS_SSR
},
389 { VENDOR_LOGITECH
, 0xC024, "M-BP82", "MX300 Optical Mouse", HAS_RES
},
390 { VENDOR_LOGITECH
, 0xC025, "M-BP81A", "MX500 Optical Mouse", HAS_RES
| HAS_SS
| HAS_SSR
},
391 { VENDOR_LOGITECH
, 0xC031, "M-UT58A", "iFeel Mouse (silver)", HAS_RES
},
392 { VENDOR_LOGITECH
, 0xC501, "C-BA4-MSE", "Mouse Receiver", HAS_CSR
},
393 { VENDOR_LOGITECH
, 0xC502, "C-UA3-DUAL", "Dual Receiver", HAS_CSR
| USE_CH2
},
394 { VENDOR_LOGITECH
, 0xC504, "C-BD9-DUAL", "Cordless Freedom Optical", HAS_CSR
| USE_CH2
},
395 { VENDOR_LOGITECH
, 0xC505, "C-BG17-DUAL", "Cordless Elite Duo", HAS_SS
| HAS_SSR
| HAS_CSR
| USE_CH2
},
396 { VENDOR_LOGITECH
, 0xC506, "C-BF16-MSE", "MX700 Optical Mouse", HAS_SS
| HAS_CSR
},
397 { VENDOR_LOGITECH
, 0xC508, "C-BA4-MSE", "Cordless Optical TrackMan", HAS_SS
| HAS_CSR
},
398 { VENDOR_LOGITECH
, 0xC50B, "967300-0403", "Cordless MX Duo Receiver", HAS_SS
|HAS_CSR
},
399 { VENDOR_LOGITECH
, 0xC50E, "M-RAG97", "MX1000 Laser Mouse", HAS_SS
| HAS_CSR
},
400 { VENDOR_LOGITECH
, 0xC702, "C-UF15", "Receiver for Cordless Presenter", HAS_CSR
},
401 { 0, 0, QString(), QString(), 0 }
409 struct usb_device
*dev
;
411 for (bus
= usb_busses
; bus
; bus
= bus
->next
) {
412 for (dev
= bus
->devices
; dev
; dev
= dev
->next
) {
413 for (int n
= 0; device_table
[n
].idVendor
; n
++)
414 if ( (device_table
[n
].idVendor
== dev
->descriptor
.idVendor
) &&
415 (device_table
[n
].idProduct
== dev
->descriptor
.idProduct
) ) {
416 // OK, we have a device that appears to be one of the ones we support
417 LogitechMouse
*mouse
= new LogitechMouse( dev
, device_table
[n
].flags
, this, device_table
[n
].Name
.toLatin1() );
418 settings
->logitechMouseList
.append(mouse
);
419 tabwidget
->addTab( (QWidget
*)mouse
, device_table
[n
].Name
);
426 KAboutData
* about
= new KAboutData("kcmmouse", 0, ki18n("Mouse"), 0, KLocalizedString(),
427 KAboutData::License_GPL
, ki18n("(c) 1997 - 2005 Mouse developers"));
428 about
->addAuthor(ki18n("Patrick Dowler"));
429 about
->addAuthor(ki18n("Dirk A. Mueller"));
430 about
->addAuthor(ki18n("David Faure"));
431 about
->addAuthor(ki18n("Bernd Gehrmann"));
432 about
->addAuthor(ki18n("Rik Hemsley"));
433 about
->addAuthor(ki18n("Brad Hughes"));
434 about
->addAuthor(ki18n("Ralf Nolden"));
435 about
->addAuthor(ki18n("Brad Hards"));
436 setAboutData( about
);
439 void MouseConfig::checkAccess()
441 mk_delay
->setEnabled(mouseKeys
->isChecked());
442 mk_interval
->setEnabled(mouseKeys
->isChecked());
443 mk_time_to_max
->setEnabled(mouseKeys
->isChecked());
444 mk_max_speed
->setEnabled(mouseKeys
->isChecked());
445 mk_curve
->setEnabled(mouseKeys
->isChecked());
449 MouseConfig::~MouseConfig()
454 double MouseConfig::getAccel()
456 return accel
->value();
459 void MouseConfig::setAccel(double val
)
461 accel
->setValue(val
);
464 int MouseConfig::getThreshold()
466 return thresh
->value();
469 void MouseConfig::setThreshold(int val
)
471 thresh
->setValue(val
);
475 int MouseConfig::getHandedness()
477 if (generalTab
->rightHanded
->isChecked())
483 void MouseConfig::setHandedness(int val
)
485 generalTab
->rightHanded
->setChecked(false);
486 generalTab
->leftHanded
->setChecked(false);
487 if (val
== RIGHT_HANDED
){
488 generalTab
->rightHanded
->setChecked(true);
489 generalTab
->mousePix
->setPixmap(KStandardDirs::locate("data", "kcminput/pics/mouse_rh.png"));
492 generalTab
->leftHanded
->setChecked(true);
493 generalTab
->mousePix
->setPixmap(KStandardDirs::locate("data", "kcminput/pics/mouse_lh.png"));
495 settings
->m_handedNeedsApply
= true;
498 void MouseConfig::load()
500 KConfig
config( "kcminputrc" );
501 settings
->load(&config
);
503 generalTab
->rightHanded
->setEnabled(settings
->handedEnabled
);
504 generalTab
->leftHanded
->setEnabled(settings
->handedEnabled
);
505 if ( generalTab
->cbScrollPolarity
->isEnabled() )
506 generalTab
->cbScrollPolarity
->setEnabled(settings
->handedEnabled
);
507 generalTab
->cbScrollPolarity
->setChecked( settings
->reverseScrollPolarity
);
509 setAccel(settings
->accelRate
);
510 setThreshold(settings
->thresholdMove
);
511 setHandedness(settings
->handed
);
513 doubleClickInterval
->setValue(settings
->doubleClickInterval
);
514 dragStartTime
->setValue(settings
->dragStartTime
);
515 dragStartDist
->setValue(settings
->dragStartDist
);
516 wheelScrollLines
->setValue(settings
->wheelScrollLines
);
518 generalTab
->singleClick
->setChecked( settings
->singleClick
);
519 generalTab
->doubleClick
->setChecked(!settings
->singleClick
);
520 generalTab
->cb_pointershape
->setChecked(settings
->changeCursor
);
521 generalTab
->cbAutoSelect
->setChecked( settings
->autoSelectDelay
>= 0 );
522 if ( settings
->autoSelectDelay
< 0 )
523 generalTab
->slAutoSelect
->setValue( 0 );
525 generalTab
->slAutoSelect
->setValue( settings
->autoSelectDelay
);
529 KConfig
ac("kaccessrc");
531 KConfigGroup group
= ac
.group("Mouse");
532 mouseKeys
->setChecked(group
.readEntry("MouseKeys", false));
533 mk_delay
->setValue(group
.readEntry("MKDelay", 160));
535 int interval
= group
.readEntry("MKInterval", 5);
536 mk_interval
->setValue(interval
);
538 // Default time to reach maximum speed: 5000 msec
539 int time_to_max
= group
.readEntry("MKTimeToMax", (5000+interval
/2)/interval
);
540 time_to_max
= group
.readEntry("MK-TimeToMax", time_to_max
*interval
);
541 mk_time_to_max
->setValue(time_to_max
);
543 // Default maximum speed: 1000 pixels/sec
544 // (The old default maximum speed from KDE <= 3.4
545 // (100000 pixels/sec) was way too fast)
546 long max_speed
= group
.readEntry("MKMaxSpeed", interval
);
547 max_speed
= max_speed
* 1000 / interval
;
548 if (max_speed
> 2000)
550 max_speed
= group
.readEntry("MK-MaxSpeed", int(max_speed
));
551 mk_max_speed
->setValue(max_speed
);
553 mk_curve
->setValue(group
.readEntry("MKCurve", 0));
562 void MouseConfig::save()
564 settings
->accelRate
= getAccel();
565 settings
->thresholdMove
= getThreshold();
566 settings
->handed
= getHandedness();
568 settings
->doubleClickInterval
= doubleClickInterval
->value();
569 settings
->dragStartTime
= dragStartTime
->value();
570 settings
->dragStartDist
= dragStartDist
->value();
571 settings
->wheelScrollLines
= wheelScrollLines
->value();
572 settings
->singleClick
= !generalTab
->doubleClick
->isChecked();
573 settings
->autoSelectDelay
= generalTab
->cbAutoSelect
->isChecked()? generalTab
->slAutoSelect
->value():-1;
574 // settings->changeCursor = generalTab->singleClick->isChecked();
575 settings
->changeCursor
= generalTab
->cb_pointershape
->isChecked();
576 settings
->reverseScrollPolarity
= generalTab
->cbScrollPolarity
->isChecked();
579 KConfig
config( "kcminputrc" );
580 settings
->save(&config
);
582 KConfig
ac("kaccessrc");
584 KConfigGroup group
= ac
.group("Mouse");
586 int interval
= mk_interval
->value();
587 group
.writeEntry("MouseKeys", mouseKeys
->isChecked());
588 group
.writeEntry("MKDelay", mk_delay
->value());
589 group
.writeEntry("MKInterval", interval
);
590 group
.writeEntry("MK-TimeToMax", mk_time_to_max
->value());
591 group
.writeEntry("MKTimeToMax",
592 (mk_time_to_max
->value() + interval
/2)/interval
);
593 group
.writeEntry("MK-MaxSpeed", mk_max_speed
->value());
594 group
.writeEntry("MKMaxSpeed",
595 (mk_max_speed
->value()*interval
+ 500)/1000);
596 group
.writeEntry("MKCurve", mk_curve
->value());
598 group
.writeEntry("MKCurve", mk_curve
->value());
603 KToolInvocation::startServiceByDesktopName("kaccess");
608 void MouseConfig::defaults()
612 setHandedness(RIGHT_HANDED
);
613 generalTab
->cbScrollPolarity
->setChecked( false );
614 doubleClickInterval
->setValue(400);
615 dragStartTime
->setValue(500);
616 dragStartDist
->setValue(4);
617 wheelScrollLines
->setValue(3);
618 generalTab
->doubleClick
->setChecked( !KDE_DEFAULT_SINGLECLICK
);
619 generalTab
->cbAutoSelect
->setChecked( KDE_DEFAULT_AUTOSELECTDELAY
!= -1 );
620 generalTab
->slAutoSelect
->setValue( KDE_DEFAULT_AUTOSELECTDELAY
== -1 ? 50 : KDE_DEFAULT_AUTOSELECTDELAY
);
621 generalTab
->singleClick
->setChecked( KDE_DEFAULT_SINGLECLICK
);
622 generalTab
->cb_pointershape
->setChecked(KDE_DEFAULT_CHANGECURSOR
);
625 mouseKeys
->setChecked(false);
626 mk_delay
->setValue(160);
627 mk_interval
->setValue(5);
628 mk_time_to_max
->setValue(5000);
629 mk_max_speed
->setValue(1000);
630 mk_curve
->setValue(0);
637 void MouseConfig::slotClick()
639 // Autoselect has a meaning only in single-click mode
640 generalTab
->cbAutoSelect
->setEnabled(!generalTab
->doubleClick
->isChecked() || generalTab
->singleClick
->isChecked());
641 // Delay has a meaning only for autoselect
642 bool bDelay
= generalTab
->cbAutoSelect
->isChecked() && ! generalTab
->doubleClick
->isChecked();
643 generalTab
->slAutoSelect
->setEnabled( bDelay
);
644 generalTab
->lDelay
->setEnabled( bDelay
);
645 generalTab
->lb_short
->setEnabled( bDelay
);
646 generalTab
->lb_long
->setEnabled( bDelay
);
650 /** No descriptions */
651 void MouseConfig::slotHandedChanged(int val
){
652 if(val
==RIGHT_HANDED
)
653 generalTab
->mousePix
->setPixmap(KStandardDirs::locate("data", "kcminput/pics/mouse_rh.png"));
655 generalTab
->mousePix
->setPixmap(KStandardDirs::locate("data", "kcminput/pics/mouse_lh.png"));
656 settings
->m_handedNeedsApply
= true;
659 void MouseSettings::load(KConfig
*config
)
661 int accel_num
, accel_den
, threshold
;
663 XGetPointerControl( QX11Info::display(),
664 &accel_num
, &accel_den
, &threshold
);
665 accel
= float(accel_num
) / float(accel_den
);
667 // get settings from X server
668 int h
= RIGHT_HANDED
;
669 unsigned char map
[20];
670 num_buttons
= XGetPointerMapping(QX11Info::display(), map
, 20);
672 handedEnabled
= true;
674 // ## keep this in sync with KGlobalSettings::mouseSettings
675 if( num_buttons
== 1 )
677 /* disable button remapping */
678 handedEnabled
= false;
680 else if( num_buttons
== 2 )
682 if ( (int)map
[0] == 1 && (int)map
[1] == 2 )
684 else if ( (int)map
[0] == 2 && (int)map
[1] == 1 )
687 /* custom button setup: disable button remapping */
688 handedEnabled
= false;
692 middle_button
= (int)map
[1];
693 if ( (int)map
[0] == 1 && (int)map
[2] == 3 )
695 else if ( (int)map
[0] == 3 && (int)map
[2] == 1 )
699 /* custom button setup: disable button remapping */
700 handedEnabled
= false;
704 KConfigGroup group
= config
->group("Mouse");
705 double a
= group
.readEntry("Acceleration",-1.0);
711 int t
= group
.readEntry("Threshold",-1);
713 thresholdMove
= threshold
;
717 QString key
= group
.readEntry("MouseButtonMapping");
718 if (key
== "RightHanded")
719 handed
= RIGHT_HANDED
;
720 else if (key
== "LeftHanded")
721 handed
= LEFT_HANDED
;
723 #warning was key == NULL how was this working? is key.isNull() what the coder meant?
725 else if (key
.isNull())
727 reverseScrollPolarity
= group
.readEntry( "ReverseScrollPolarity", false);
728 m_handedNeedsApply
= false;
730 // SC/DC/AutoSelect/ChangeCursor
731 group
= config
->group("KDE");
732 doubleClickInterval
= group
.readEntry("DoubleClickInterval", 400);
733 dragStartTime
= group
.readEntry("StartDragTime", 500);
734 dragStartDist
= group
.readEntry("StartDragDist", 4);
735 wheelScrollLines
= group
.readEntry("WheelScrollLines", 3);
737 singleClick
= group
.readEntry("SingleClick", KDE_DEFAULT_SINGLECLICK
);
738 autoSelectDelay
= group
.readEntry("AutoSelectDelay", KDE_DEFAULT_AUTOSELECTDELAY
);
739 changeCursor
= group
.readEntry("ChangeCursor", KDE_DEFAULT_CHANGECURSOR
);
742 void MouseConfig::slotThreshChanged(int value
)
744 thresh
->setSuffix(i18np(" pixel", " pixels", value
));
747 void MouseConfig::slotDragStartDistChanged(int value
)
749 dragStartDist
->setSuffix(i18np(" pixel", " pixels", value
));
752 void MouseConfig::slotWheelScrollLinesChanged(int value
)
754 wheelScrollLines
->setSuffix(i18np(" line", " lines", value
));
757 void MouseSettings::apply(bool force
)
759 XChangePointerControl( QX11Info::display(),
760 true, true, int(qRound(accelRate
*10)), 10, thresholdMove
);
762 // 256 might seems extreme, but X has already been known to return 32,
763 // and we don't want to truncate things. Xlib limits the table to 256 bytes,
764 // so it's a good uper bound..
765 unsigned char map
[256];
766 num_buttons
= XGetPointerMapping(QX11Info::display(), map
, 256);
768 int remap
=(num_buttons
>=1);
769 if (handedEnabled
&& (m_handedNeedsApply
|| force
)) {
770 if( num_buttons
== 1 )
772 map
[0] = (unsigned char) 1;
774 else if( num_buttons
== 2 )
776 if (handed
== RIGHT_HANDED
)
778 map
[0] = (unsigned char) 1;
779 map
[1] = (unsigned char) 3;
783 map
[0] = (unsigned char) 3;
784 map
[1] = (unsigned char) 1;
787 else // 3 buttons and more
789 if (handed
== RIGHT_HANDED
)
791 map
[0] = (unsigned char) 1;
792 map
[1] = (unsigned char) middle_button
;
793 map
[2] = (unsigned char) 3;
797 map
[0] = (unsigned char) 3;
798 map
[1] = (unsigned char) middle_button
;
799 map
[2] = (unsigned char) 1;
801 if( num_buttons
>= 5 )
803 // Apps seem to expect logical buttons 4,5 are the vertical wheel.
804 // With mice with more than 3 buttons (not including wheel) the physical
805 // buttons mapped to logical 4,5 may not be physical 4,5 , so keep
806 // this mapping, only possibly reversing them.
808 for( pos
= 0; pos
< num_buttons
; ++pos
)
809 if( map
[pos
] == 4 || map
[pos
] == 5 )
811 if( pos
< num_buttons
- 1 )
813 map
[pos
] = reverseScrollPolarity
? (unsigned char) 5 : (unsigned char) 4;
814 map
[pos
+1] = reverseScrollPolarity
? (unsigned char) 4 : (unsigned char) 5;
820 while ((retval
=XSetPointerMapping(QX11Info::display(), map
,
821 num_buttons
)) == MappingBusy
)
822 /* keep trying until the pointer is free */
824 m_handedNeedsApply
= false;
827 // This iterates through the various Logitech mice, if we have support.
829 LogitechMouse
*logitechMouse
;
830 Q_FOREACH( logitechMouse
, logitechMouseList
) {
831 logitechMouse
->applyChanges();
836 void MouseSettings::save(KConfig
*config
)
838 KConfigGroup group
= config
->group("Mouse");
839 group
.writeEntry("Acceleration",accelRate
);
840 group
.writeEntry("Threshold",thresholdMove
);
841 if (handed
== RIGHT_HANDED
)
842 group
.writeEntry("MouseButtonMapping",QString("RightHanded"));
844 group
.writeEntry("MouseButtonMapping",QString("LeftHanded"));
845 group
.writeEntry( "ReverseScrollPolarity", reverseScrollPolarity
);
847 group
= config
->group("KDE");
848 group
.writeEntry("DoubleClickInterval", doubleClickInterval
, KConfig::Persistent
|KConfig::Global
);
849 group
.writeEntry("StartDragTime", dragStartTime
, KConfig::Persistent
|KConfig::Global
);
850 group
.writeEntry("StartDragDist", dragStartDist
, KConfig::Persistent
|KConfig::Global
);
851 group
.writeEntry("WheelScrollLines", wheelScrollLines
, KConfig::Persistent
|KConfig::Global
);
852 group
.writeEntry("SingleClick", singleClick
, KConfig::Persistent
|KConfig::Global
);
853 group
.writeEntry("AutoSelectDelay", autoSelectDelay
, KConfig::Persistent
|KConfig::Global
);
854 group
.writeEntry("ChangeCursor", changeCursor
,KConfig::Persistent
|KConfig::Global
);
855 // This iterates through the various Logitech mice, if we have support.
857 LogitechMouse
*logitechMouse
;
858 Q_FOREACH( logitechMouse
, logitechMouseList
) {
859 logitechMouse
->save(config
);
863 KGlobalSettings::self()->emitChange(KGlobalSettings::SettingsChanged
, KGlobalSettings::SETTINGS_MOUSE
);
866 void MouseConfig::slotScrollPolarityChanged()
868 settings
->m_handedNeedsApply
= true;
871 void MouseConfig::slotSmartSliderEnabling()
873 bool enabled
= generalTab
->singleClick
->isChecked() ? generalTab
->cbAutoSelect
->isChecked() : false;
874 generalTab
->lDelay
->setEnabled(enabled
);
875 generalTab
->slAutoSelect
->setEnabled(enabled
);
876 generalTab
->lb_short
->setEnabled(enabled
);
877 generalTab
->lb_long
->setEnabled(enabled
);