4 * Copyright (c) 2000 Matthias H�zer-Klpfel
17 #include <QRadioButton>
18 #include <QtGui/QX11Info>
19 #include <QtDBus/QtDBus>
22 #include <QVBoxLayout>
23 #include <QHBoxLayout>
27 #include <kcombobox.h>
28 #include <kstandarddirs.h>
29 #include <kcolorbutton.h>
30 #include <kfiledialog.h>
31 #include <kapplication.h>
32 #include <kaboutdata.h>
33 #include <kshortcut.h>
34 #include <knotifyconfigwidget.h>
35 #include <kkeyserver.h>
38 #include <X11/XKBlib.h>
41 #include <X11/keysymdef.h>
42 #include <ktoolinvocation.h>
44 #include "kcmaccess.moc"
46 #include <kgenericfactory.h>
47 typedef KGenericFactory
<KAccessConfig
, QWidget
> KAccessConfigFactory
;
48 K_EXPORT_COMPONENT_FACTORY(kcm_access
, KAccessConfigFactory("kcmaccess"))
50 ExtendedIntNumInput::ExtendedIntNumInput
52 : KIntNumInput(parent
)
56 ExtendedIntNumInput::~ExtendedIntNumInput () {
59 void ExtendedIntNumInput::setRange(int min
, int max
, int step
, bool withSlider
) {
60 KIntNumInput::setRange (min
, max
, step
);
61 KIntNumInput::setSliderEnabled (withSlider
);
64 disconnect(slider(), SIGNAL(valueChanged(int)),
65 spinBox(), SLOT(setValue(int)));
66 disconnect(spinBox(), SIGNAL(valueChanged(int)),
67 this, SLOT(spinValueChanged(int)));
71 sliderMax
= (int)floor (0.5
72 + 2*(log((double)max
)-log((double)min
)) / (log((double)max
)-log((double)max
-1)));
73 slider()->setRange(0, sliderMax
);
74 slider()->setSingleStep(step
);
75 slider()->setPageStep(sliderMax
/10);
76 slider()->setTickInterval(sliderMax
/10);
78 double alpha
= sliderMax
/ (log((double)max
) - log((double)min
));
79 double logVal
= alpha
* (log((double)value())-log((double)min
));
80 slider()->setValue ((int)floor (0.5 + logVal
));
82 connect(slider(), SIGNAL(valueChanged(int)),
83 this, SLOT(slotSliderValueChanged(int)));
84 connect(spinBox(), SIGNAL(valueChanged(int)),
85 this, SLOT(slotSpinValueChanged(int)));
89 // Basically the slider values are logarithmic whereas
90 // spinbox values are linear.
92 void ExtendedIntNumInput::slotSpinValueChanged(int val
)
96 double alpha
= sliderMax
/ (log((double)max
) - log((double)min
));
97 double logVal
= alpha
* (log((double)val
)-log((double)min
));
98 slider()->setValue ((int)floor (0.5 + logVal
));
101 emit
valueChanged(val
);
104 void ExtendedIntNumInput::slotSliderValueChanged(int val
)
106 double alpha
= sliderMax
/ (log((double)max
) - log((double)min
));
107 double linearVal
= exp (val
/alpha
+ log((double)min
));
108 spinBox()->setValue ((int)floor(0.5 + linearVal
));
111 static bool needToRunKAccessDaemon( KConfig
*config
)
113 // We always start the KAccess Daemon, if it is not needed,
114 // it will terminate itself after configuring the AccessX
119 QString
mouseKeysShortcut (Display
*display
) {
120 // Calculate the keycode
121 KeySym sym
= XK_MouseKeys_Enable
;
122 KeyCode code
= XKeysymToKeycode(display
, sym
);
124 sym
= XK_Pointer_EnableKeys
;
125 code
= XKeysymToKeycode(display
, sym
);
127 return ""; // No shortcut available?
130 // Calculate the modifiers by searching the keysym in the X keyboard mapping
131 XkbDescPtr xkbdesc
= XkbGetMap(display
, XkbKeyTypesMask
| XkbKeySymsMask
, XkbUseCoreKbd
);
133 return ""; // Failed to obtain the mapping from server
136 unsigned char modifiers
= 0;
137 int groups
= XkbKeyNumGroups(xkbdesc
, code
);
138 for (int grp
= 0; grp
< groups
&& !found
; grp
++)
140 int levels
= XkbKeyGroupWidth(xkbdesc
, code
, grp
);
141 for (int level
= 0; level
< levels
&& !found
; level
++)
143 if (sym
== XkbKeySymEntry(xkbdesc
, code
, level
, grp
))
145 // keysym found => determine modifiers
146 int typeIdx
= xkbdesc
->map
->key_sym_map
[code
].kt_index
[grp
];
147 XkbKeyTypePtr type
= &(xkbdesc
->map
->types
[typeIdx
]);
148 for (int i
= 0; i
< type
->map_count
&& !found
; i
++)
150 if (type
->map
[i
].active
&& (type
->map
[i
].level
== level
))
152 modifiers
= type
->map
[i
].mods
.mask
;
159 XkbFreeClientMap (xkbdesc
, 0, true);
162 return ""; // Somehow the keycode -> keysym mapping is flawed
165 ev
.xkey
.display
= display
;
166 ev
.xkey
.keycode
= code
;
169 KKeyServer::xEventToQt(&ev
, &key
);
170 QString keyname
= QKeySequence(key
).toString();
172 unsigned int AltMask
= KKeyServer::modXAlt();
173 unsigned int WinMask
= KKeyServer::modXMeta();
174 unsigned int NumMask
= KKeyServer::modXNumLock();
175 unsigned int ScrollMask
= KKeyServer::modXScrollLock();
177 unsigned int MetaMask
= XkbKeysymToModifiers (display
, XK_Meta_L
);
178 unsigned int SuperMask
= XkbKeysymToModifiers (display
, XK_Super_L
);
179 unsigned int HyperMask
= XkbKeysymToModifiers (display
, XK_Hyper_L
);
180 unsigned int AltGrMask
= XkbKeysymToModifiers (display
, XK_Mode_switch
)
181 | XkbKeysymToModifiers (display
, XK_ISO_Level3_Shift
)
182 | XkbKeysymToModifiers (display
, XK_ISO_Level3_Latch
)
183 | XkbKeysymToModifiers (display
, XK_ISO_Level3_Lock
);
185 unsigned int mods
= ShiftMask
| ControlMask
| AltMask
| WinMask
186 | LockMask
| NumMask
| ScrollMask
;
189 MetaMask
&= ~(mods
| AltGrMask
);
190 SuperMask
&= ~(mods
| AltGrMask
| MetaMask
);
191 HyperMask
&= ~(mods
| AltGrMask
| MetaMask
| SuperMask
);
193 if ((modifiers
& AltGrMask
) != 0)
194 keyname
= i18n("AltGraph") + '+' + keyname
;
195 if ((modifiers
& HyperMask
) != 0)
196 keyname
= i18n("Hyper") + '+' + keyname
;
197 if ((modifiers
& SuperMask
) != 0)
198 keyname
= i18n("Super") + '+' + keyname
;
199 if ((modifiers
& WinMask
) != 0)
200 keyname
= QKeySequence(Qt::META
).toString() + '+' + keyname
;
201 if ((modifiers
& AltMask
) != 0)
202 keyname
= QKeySequence(Qt::ALT
).toString() + '+' + keyname
;
203 if ((modifiers
& ControlMask
) != 0)
204 keyname
= QKeySequence(Qt::CTRL
).toString() + '+' + keyname
;
205 if ((modifiers
& ShiftMask
) != 0)
206 keyname
= QKeySequence(Qt::SHIFT
).toString() + '+' + keyname
;
209 if ((modifiers
& ScrollMask
) != 0)
210 if ((modifiers
& LockMask
) != 0)
211 if ((modifiers
& NumMask
) != 0)
212 result
= i18n("Press %1 while NumLock, CapsLock and ScrollLock are active", keyname
);
214 result
= i18n("Press %1 while CapsLock and ScrollLock are active", keyname
);
215 else if ((modifiers
& NumMask
) != 0)
216 result
= i18n("Press %1 while NumLock and ScrollLock are active", keyname
);
218 result
= i18n("Press %1 while ScrollLock is active", keyname
);
219 else if ((modifiers
& LockMask
) != 0)
220 if ((modifiers
& NumMask
) != 0)
221 result
= i18n("Press %1 while NumLock and CapsLock are active", keyname
);
223 result
= i18n("Press %1 while CapsLock is active", keyname
);
224 else if ((modifiers
& NumMask
) != 0)
225 result
= i18n("Press %1 while NumLock is active", keyname
);
227 result
= i18n("Press %1", keyname
);
232 KAccessConfig::KAccessConfig(QWidget
*parent
, const QStringList
& args
)
233 : KCModule(KAccessConfigFactory::componentData(), parent
, args
)
237 new KAboutData(I18N_NOOP("kaccess"), 0, ki18n("KDE Accessibility Tool"),
238 0, KLocalizedString(), KAboutData::License_GPL
,
239 ki18n("(c) 2000, Matthias Hoelzer-Kluepfel"));
241 about
->addAuthor(ki18n("Matthias Hoelzer-Kluepfel"), ki18n("Author") , "hoelzer@kde.org");
243 setAboutData( about
);
245 QVBoxLayout
*main
= new QVBoxLayout(this);
247 main
->setSpacing(KDialog::spacingHint());
248 QTabWidget
*tab
= new QTabWidget(this);
249 main
->addWidget(tab
);
251 // bell settings ---------------------------------------
252 QWidget
*bell
= new QWidget(this);
254 QVBoxLayout
*vbox
= new QVBoxLayout(bell
);
255 vbox
->setMargin(KDialog::marginHint());
256 vbox
->setSpacing(KDialog::spacingHint());
258 QGroupBox
*grp
= new QGroupBox(i18n("Audible Bell"), bell
);
259 QHBoxLayout
*layout
= new QHBoxLayout
;
260 grp
->setLayout(layout
);
261 vbox
->addWidget(grp
);
263 QVBoxLayout
*vvbox
= new QVBoxLayout();
264 layout
->addLayout( vvbox
);
265 vvbox
->setSpacing( KDialog::spacingHint() );
267 systemBell
= new QCheckBox(i18n("Use &system bell"), grp
);
268 vvbox
->addWidget(systemBell
);
269 customBell
= new QCheckBox(i18n("Us&e customized bell"), grp
);
270 vvbox
->addWidget(customBell
);
271 systemBell
->setWhatsThis( i18n("If this option is checked, the default system bell will be used. See the"
272 " \"System Bell\" control module for how to customize the system bell."
273 " Normally, this is just a \"beep\".") );
274 customBell
->setWhatsThis( i18n("<p>Check this option if you want to use a customized bell, playing"
275 " a sound file. If you do this, you will probably want to turn off the system bell.</p><p> Please note"
276 " that on slow machines this may cause a \"lag\" between the event causing the bell and the sound being played.</p>") );
278 QHBoxLayout
*hbox
= new QHBoxLayout();
279 vvbox
->addItem( hbox
);
280 hbox
->setSpacing(KDialog::spacingHint());
281 hbox
->addSpacing(24);
282 soundEdit
= new QLineEdit(grp
);
283 soundLabel
= new QLabel(i18n("Sound &to play:"), grp
);
284 soundLabel
->setBuddy(soundEdit
);
285 hbox
->addWidget(soundLabel
);
286 hbox
->addWidget(soundEdit
);
287 soundButton
= new QPushButton(i18n("Browse..."), grp
);
288 hbox
->addWidget(soundButton
);
289 QString wtstr
= i18n("If the option \"Use customized bell\" is enabled, you can choose a sound file here."
290 " Click \"Browse...\" to choose a sound file using the file dialog.");
291 soundEdit
->setWhatsThis( wtstr
);
292 soundLabel
->setWhatsThis( wtstr
);
293 soundButton
->setWhatsThis( wtstr
);
295 connect(soundButton
, SIGNAL(clicked()), this, SLOT(selectSound()));
297 connect(customBell
, SIGNAL(clicked()), this, SLOT(checkAccess()));
299 connect(systemBell
, SIGNAL(clicked()), this, SLOT(configChanged()));
300 connect(customBell
, SIGNAL(clicked()), this, SLOT(configChanged()));
301 connect(soundEdit
, SIGNAL(textChanged(const QString
&)), this, SLOT(configChanged()));
303 // -----------------------------------------------------
305 // visible bell ----------------------------------------
306 grp
= new QGroupBox(i18n("Visible Bell"), bell
);
307 layout
= new QHBoxLayout
;
308 grp
->setLayout(layout
);
309 vbox
->addWidget(grp
);
311 vvbox
= new QVBoxLayout();
312 layout
->addLayout( vvbox
);
313 vvbox
->setSpacing(KDialog::spacingHint());
315 visibleBell
= new QCheckBox(i18n("&Use visible bell"), grp
);
316 vvbox
->addWidget(visibleBell
);
317 visibleBell
->setWhatsThis( i18n("This option will turn on the \"visible bell\", i.e. a visible"
318 " notification shown every time that normally just a bell would occur. This is especially useful"
319 " for deaf people.") );
321 hbox
= new QHBoxLayout();
322 vvbox
->addItem(hbox
);
323 hbox
->setSpacing(KDialog::spacingHint());
324 hbox
->addSpacing(24);
325 invertScreen
= new QRadioButton(i18n("I&nvert screen"), grp
);
326 hbox
->addWidget(invertScreen
);
327 hbox
= new QHBoxLayout();
328 vvbox
->addItem(hbox
);
329 hbox
->setSpacing(KDialog::spacingHint());
330 invertScreen
->setWhatsThis( i18n("All screen colors will be inverted for the amount of time specified below.") );
331 hbox
->addSpacing(24);
332 flashScreen
= new QRadioButton(i18n("F&lash screen"), grp
);
333 hbox
->addWidget(flashScreen
);
334 flashScreen
->setWhatsThis( i18n("The screen will turn to a custom color for the amount of time specified below.") );
335 hbox
->addSpacing(12);
336 colorButton
= new KColorButton(grp
);
337 colorButton
->setFixedWidth(colorButton
->sizeHint().height()*2);
338 hbox
->addWidget(colorButton
);
340 colorButton
->setWhatsThis( i18n("Click here to choose the color used for the \"flash screen\" visible bell.") );
342 hbox
= new QHBoxLayout();
343 vvbox
->addItem(hbox
);
344 hbox
->setSpacing(KDialog::spacingHint());
345 hbox
->addSpacing(24);
347 durationSlider
= new ExtendedIntNumInput(grp
);
348 durationSlider
->setRange(100, 2000, 100);
349 durationSlider
->setLabel(i18n("Duration:"));
350 durationSlider
->setSuffix(i18n(" msec"));
351 hbox
->addWidget(durationSlider
);
352 durationSlider
->setWhatsThis( i18n("Here you can customize the duration of the \"visible bell\" effect being shown.") );
354 connect(invertScreen
, SIGNAL(clicked()), this, SLOT(configChanged()));
355 connect(flashScreen
, SIGNAL(clicked()), this, SLOT(configChanged()));
356 connect(visibleBell
, SIGNAL(clicked()), this, SLOT(configChanged()));
357 connect(visibleBell
, SIGNAL(clicked()), this, SLOT(checkAccess()));
358 connect(colorButton
, SIGNAL(clicked()), this, SLOT(changeFlashScreenColor()));
360 connect(invertScreen
, SIGNAL(clicked()), this, SLOT(invertClicked()));
361 connect(flashScreen
, SIGNAL(clicked()), this, SLOT(flashClicked()));
363 connect(durationSlider
, SIGNAL(valueChanged(int)), this, SLOT(configChanged()));
367 // -----------------------------------------------------
369 tab
->addTab(bell
, i18n("&Bell"));
372 // modifier key settings -------------------------------
373 QWidget
*modifiers
= new QWidget(this);
375 vbox
= new QVBoxLayout(modifiers
);
376 vbox
->setMargin(KDialog::marginHint());
377 vbox
->setSpacing(KDialog::spacingHint());
379 grp
= new QGroupBox(i18n("S&ticky Keys"), modifiers
);
380 layout
= new QHBoxLayout
;
381 grp
->setLayout(layout
);
382 vbox
->addWidget(grp
);
384 vvbox
= new QVBoxLayout();
385 layout
->addLayout(vvbox
);
386 vvbox
->setSpacing(KDialog::spacingHint());
388 stickyKeys
= new QCheckBox(i18n("Use &sticky keys"), grp
);
389 vvbox
->addWidget(stickyKeys
);
391 hbox
= new QHBoxLayout();
392 vvbox
->addItem(hbox
);
393 hbox
->setSpacing(KDialog::spacingHint());
394 hbox
->addSpacing(24);
395 stickyKeysLock
= new QCheckBox(i18n("&Lock sticky keys"), grp
);
396 hbox
->addWidget(stickyKeysLock
);
398 hbox
= new QHBoxLayout();
399 vvbox
->addItem(hbox
);
400 hbox
->setSpacing(KDialog::spacingHint());
401 hbox
->addSpacing(24);
402 stickyKeysAutoOff
= new QCheckBox(i18n("Turn sticky keys off when two keys are pressed simultaneously"), grp
);
403 hbox
->addWidget(stickyKeysAutoOff
);
405 hbox
= new QHBoxLayout();
406 vvbox
->addItem(hbox
);
407 hbox
->setSpacing(KDialog::spacingHint());
408 hbox
->addSpacing(24);
409 stickyKeysBeep
= new QCheckBox(i18n("Use system bell whenever a modifier gets latched, locked or unlocked"), grp
);
410 hbox
->addWidget(stickyKeysBeep
);
412 grp
= new QGroupBox(i18n("Locking Keys"), modifiers
);
413 layout
= new QHBoxLayout
;
414 grp
->setLayout(layout
);
415 vbox
->addWidget(grp
);
417 vvbox
= new QVBoxLayout();
418 layout
->addLayout(vvbox
);
419 vvbox
->setSpacing(KDialog::spacingHint());
421 toggleKeysBeep
= new QCheckBox(i18n("Use system bell whenever a locking key gets activated or deactivated"), grp
);
422 vvbox
->addWidget(toggleKeysBeep
);
424 kNotifyModifiers
= new QCheckBox(i18n("Use KDE's system notification mechanism whenever a modifier or locking key changes its state"), grp
);
425 vvbox
->addWidget(kNotifyModifiers
);
427 hbox
= new QHBoxLayout();
428 vvbox
->addItem(hbox
);
429 hbox
->setSpacing(KDialog::spacingHint());
431 kNotifyModifiersButton
= new QPushButton(i18n("Configure &Notifications..."), grp
);
432 kNotifyModifiersButton
->setSizePolicy(QSizePolicy::Fixed
, QSizePolicy::Fixed
);
433 hbox
->addWidget(kNotifyModifiersButton
);
435 connect(stickyKeys
, SIGNAL(clicked()), this, SLOT(configChanged()));
436 connect(stickyKeysLock
, SIGNAL(clicked()), this, SLOT(configChanged()));
437 connect(stickyKeysAutoOff
, SIGNAL(clicked()), this, SLOT(configChanged()));
438 connect(stickyKeys
, SIGNAL(clicked()), this, SLOT(checkAccess()));
440 connect(stickyKeysBeep
, SIGNAL(clicked()), this, SLOT(configChanged()));
441 connect(toggleKeysBeep
, SIGNAL(clicked()), this, SLOT(configChanged()));
442 connect(kNotifyModifiers
, SIGNAL(clicked()), this, SLOT(configChanged()));
443 connect(kNotifyModifiers
, SIGNAL(clicked()), this, SLOT(checkAccess()));
444 connect(kNotifyModifiersButton
, SIGNAL(clicked()), this, SLOT(configureKNotify()));
448 tab
->addTab(modifiers
, i18n("&Modifier Keys"));
450 // key filter settings ---------------------------------
451 QWidget
*filters
= new QWidget(this);
453 vbox
= new QVBoxLayout(filters
);
454 vbox
->setMargin(KDialog::marginHint());
455 vbox
->setSpacing(KDialog::spacingHint());
456 grp
= new QGroupBox(i18n("Slo&w Keys"), filters
);
457 layout
= new QHBoxLayout
;
458 grp
->setLayout(layout
);
459 vbox
->addWidget(grp
);
461 vvbox
= new QVBoxLayout();
462 layout
->addLayout(vvbox
);
463 vvbox
->setSpacing(KDialog::spacingHint());
465 slowKeys
= new QCheckBox(i18n("&Use slow keys"), grp
);
466 vvbox
->addWidget(slowKeys
);
468 hbox
= new QHBoxLayout();
469 vvbox
->addItem(hbox
);
470 hbox
->setSpacing(KDialog::spacingHint());
471 hbox
->addSpacing(24);
472 slowKeysDelay
= new ExtendedIntNumInput(grp
);
473 slowKeysDelay
->setSuffix(i18n(" msec"));
474 slowKeysDelay
->setRange(50, 10000, 100);
475 slowKeysDelay
->setLabel(i18n("Acceptance dela&y:"), Qt::AlignVCenter
|Qt::AlignLeft
);
476 hbox
->addWidget(slowKeysDelay
);
478 hbox
= new QHBoxLayout();
479 vvbox
->addItem(hbox
);
480 hbox
->setSpacing(KDialog::spacingHint());
481 hbox
->addSpacing(24);
482 slowKeysPressBeep
= new QCheckBox(i18n("&Use system bell whenever a key is pressed"), grp
);
483 hbox
->addWidget(slowKeysPressBeep
);
485 hbox
= new QHBoxLayout();
486 vvbox
->addItem(hbox
);
487 hbox
->setSpacing(KDialog::spacingHint());
488 hbox
->addSpacing(24);
489 slowKeysAcceptBeep
= new QCheckBox(i18n("&Use system bell whenever a key is accepted"), grp
);
490 hbox
->addWidget(slowKeysAcceptBeep
);
492 hbox
= new QHBoxLayout();
493 vvbox
->addItem(hbox
);
494 hbox
->setSpacing(KDialog::spacingHint());
495 hbox
->addSpacing(24);
496 slowKeysRejectBeep
= new QCheckBox(i18n("&Use system bell whenever a key is rejected"), grp
);
497 hbox
->addWidget(slowKeysRejectBeep
);
499 grp
= new QGroupBox(i18n("Bounce Keys"), filters
);
500 layout
= new QHBoxLayout
;
501 grp
->setLayout(layout
);
502 vbox
->addWidget(grp
);
504 vvbox
= new QVBoxLayout();
505 layout
->addLayout( vvbox
);
506 vvbox
->setSpacing(KDialog::spacingHint());
508 bounceKeys
= new QCheckBox(i18n("Use bou&nce keys"), grp
);
509 vvbox
->addWidget(bounceKeys
);
511 hbox
= new QHBoxLayout();
512 vvbox
->addItem(hbox
);
513 hbox
->setSpacing(KDialog::spacingHint());
514 hbox
->addSpacing(24);
515 bounceKeysDelay
= new ExtendedIntNumInput(grp
);
516 bounceKeysDelay
->setSuffix(i18n(" msec"));
517 bounceKeysDelay
->setRange(100, 5000, 100);
518 bounceKeysDelay
->setLabel(i18n("D&ebounce time:"), Qt::AlignVCenter
|Qt::AlignLeft
);;
519 hbox
->addWidget(bounceKeysDelay
);
521 hbox
= new QHBoxLayout();
522 vvbox
->addItem(hbox
);
523 hbox
->setSpacing(KDialog::spacingHint());
524 hbox
->addSpacing(24);
525 bounceKeysRejectBeep
= new QCheckBox(i18n("Use the system bell whenever a key is rejected"), grp
);
526 hbox
->addWidget(bounceKeysRejectBeep
);
528 connect(slowKeysDelay
, SIGNAL(valueChanged(int)), this, SLOT(configChanged()));
529 connect(slowKeys
, SIGNAL(clicked()), this, SLOT(configChanged()));
530 connect(slowKeys
, SIGNAL(clicked()), this, SLOT(checkAccess()));
532 connect(slowKeysPressBeep
, SIGNAL(clicked()), this, SLOT(configChanged()));
533 connect(slowKeysAcceptBeep
, SIGNAL(clicked()), this, SLOT(configChanged()));
534 connect(slowKeysRejectBeep
, SIGNAL(clicked()), this, SLOT(configChanged()));
536 connect(bounceKeysDelay
, SIGNAL(valueChanged(int)), this, SLOT(configChanged()));
537 connect(bounceKeys
, SIGNAL(clicked()), this, SLOT(configChanged()));
538 connect(bounceKeysRejectBeep
, SIGNAL(clicked()), this, SLOT(configChanged()));
539 connect(bounceKeys
, SIGNAL(clicked()), this, SLOT(checkAccess()));
543 tab
->addTab(filters
, i18n("&Keyboard Filters"));
545 // gestures --------------------------------------------
546 QWidget
*features
= new QWidget(this);
548 vbox
= new QVBoxLayout(features
);
549 vbox
->setMargin(KDialog::marginHint());
550 vbox
->setSpacing(KDialog::spacingHint());
552 grp
= new QGroupBox(i18n("Activation Gestures"), features
);
553 layout
= new QHBoxLayout
;
554 grp
->setLayout(layout
);
555 vbox
->addWidget(grp
);
557 vvbox
= new QVBoxLayout();
558 layout
->addLayout( vvbox
);
559 vvbox
->setSpacing(KDialog::spacingHint());
561 gestures
= new QCheckBox(i18n("Use gestures for activating sticky keys and slow keys"), grp
);
562 vvbox
->addWidget(gestures
);
563 QString shortcut
= mouseKeysShortcut(x11Info().display());
564 if (shortcut
.isEmpty())
565 gestures
->setWhatsThis( i18n("Here you can activate keyboard gestures that turn on the following features: \n"
566 "Sticky keys: Press Shift key 5 consecutive times\n"
567 "Slow keys: Hold down Shift for 8 seconds"));
569 gestures
->setWhatsThis( i18n("Here you can activate keyboard gestures that turn on the following features: \n"
571 "Sticky keys: Press Shift key 5 consecutive times\n"
572 "Slow keys: Hold down Shift for 8 seconds", shortcut
));
574 timeout
= new QCheckBox(i18n("Turn sticky keys and slow keys off after a certain period of inactivity."), grp
);
575 vvbox
->addWidget(timeout
);
577 hbox
= new QHBoxLayout();
578 vvbox
->addItem(hbox
);
579 hbox
->setSpacing(KDialog::spacingHint());
580 hbox
->addSpacing(24);
581 timeoutDelay
= new KIntNumInput(grp
);
582 timeoutDelay
->setSuffix(i18n(" min"));
583 timeoutDelay
->setRange(1, 30, 4);
584 timeoutDelay
->setLabel(i18n("Timeout:"), Qt::AlignVCenter
|Qt::AlignLeft
);;
585 hbox
->addWidget(timeoutDelay
);
587 grp
= new QGroupBox(i18n("Notification"), features
);
588 layout
= new QHBoxLayout
;
589 grp
->setLayout(layout
);
590 vbox
->addWidget(grp
);
592 vvbox
= new QVBoxLayout();
593 layout
->addLayout(vvbox
);
594 vvbox
->setSpacing(KDialog::spacingHint());
596 accessxBeep
= new QCheckBox(i18n("Use the system bell whenever a gesture is used to turn an accessibility feature on or off"), grp
);
597 vvbox
->addWidget(accessxBeep
);
599 gestureConfirmation
= new QCheckBox(i18n("Show a confirmation dialog whenever a keyboard accessibility feature is turned on or off"), grp
);
600 vvbox
->addWidget(gestureConfirmation
);
601 gestureConfirmation
->setWhatsThis( i18n("If this option is checked, KDE will show a confirmation dialog whenever a keyboard accessibility feature is turned on or off.\nEnsure you know what you are doing if you uncheck it, as the keyboard accessibility settings will then always be applied without confirmation.") );
603 kNotifyAccessX
= new QCheckBox(i18n("Use KDE's system notification mechanism whenever a keyboard accessibility feature is turned on or off"), grp
);
604 vvbox
->addWidget(kNotifyAccessX
);
606 hbox
= new QHBoxLayout();
607 vvbox
->addItem(hbox
);
608 hbox
->setSpacing(KDialog::spacingHint());
610 kNotifyAccessXButton
= new QPushButton(i18n("Configure &Notifications..."), grp
);
611 kNotifyAccessXButton
->setSizePolicy(QSizePolicy::Fixed
, QSizePolicy::Fixed
);
612 hbox
->addWidget(kNotifyAccessXButton
);
614 connect(gestures
, SIGNAL(clicked()), this, SLOT(configChanged()));
615 connect(timeout
, SIGNAL(clicked()), this, SLOT(configChanged()));
616 connect(timeout
, SIGNAL(clicked()), this, SLOT(checkAccess()));
617 connect(timeoutDelay
, SIGNAL(valueChanged(int)), this, SLOT(configChanged()));
618 connect(accessxBeep
, SIGNAL(clicked()), this, SLOT(configChanged()));
619 connect(gestureConfirmation
, SIGNAL(clicked()), this, SLOT(configChanged()));
620 connect(kNotifyAccessX
, SIGNAL(clicked()), this, SLOT(configChanged()));
621 connect(kNotifyAccessX
, SIGNAL(clicked()), this, SLOT(checkAccess()));
622 connect(kNotifyAccessXButton
, SIGNAL(clicked()), this, SLOT(configureKNotify()));
626 tab
->addTab(features
, i18n("Activation Gestures"));
630 KAccessConfig::~KAccessConfig()
634 void KAccessConfig::configureKNotify()
636 KNotifyConfigWidget::configure (this, "kaccess");
639 void KAccessConfig::changeFlashScreenColor()
641 invertScreen
->setChecked(false);
642 flashScreen
->setChecked(true);
646 void KAccessConfig::selectSound()
648 QStringList list
= KGlobal::dirs()->findDirs("sound", "");
652 // TODO: Why only wav's? How can I find out what artsd supports?
653 QString fname
= KFileDialog::getOpenFileName(start
, i18n("*.wav|WAV Files"));
654 if (!fname
.isEmpty())
655 soundEdit
->setText(fname
);
659 void KAccessConfig::configChanged()
665 void KAccessConfig::load()
667 KConfigGroup
cg(KSharedConfig::openConfig("kaccessrc"), "Bell");
669 systemBell
->setChecked(cg
.readEntry("SystemBell", true));
670 customBell
->setChecked(cg
.readEntry("ArtsBell", false));
671 soundEdit
->setText(cg
.readPathEntry("ArtsBellFile", QString()));
673 visibleBell
->setChecked(cg
.readEntry("VisibleBell", false));
674 invertScreen
->setChecked(cg
.readEntry("VisibleBellInvert", true));
675 flashScreen
->setChecked(!invertScreen
->isChecked());
676 colorButton
->setColor(cg
.readEntry("VisibleBellColor", QColor(Qt::red
)));
678 durationSlider
->setValue(cg
.readEntry("VisibleBellPause", 500));
680 KConfigGroup
keyboardGroup(KSharedConfig::openConfig("kaccessrc"),"Keyboard");
682 stickyKeys
->setChecked(keyboardGroup
.readEntry("StickyKeys", false));
683 stickyKeysLock
->setChecked(keyboardGroup
.readEntry("StickyKeysLatch", true));
684 stickyKeysAutoOff
->setChecked(keyboardGroup
.readEntry("StickyKeysAutoOff", false));
685 stickyKeysBeep
->setChecked(keyboardGroup
.readEntry("StickyKeysBeep", true));
686 toggleKeysBeep
->setChecked(keyboardGroup
.readEntry("ToggleKeysBeep", false));
687 kNotifyModifiers
->setChecked(keyboardGroup
.readEntry("kNotifyModifiers", false));
689 slowKeys
->setChecked(keyboardGroup
.readEntry("SlowKeys", false));
690 slowKeysDelay
->setValue(keyboardGroup
.readEntry("SlowKeysDelay", 500));
691 slowKeysPressBeep
->setChecked(keyboardGroup
.readEntry("SlowKeysPressBeep", true));
692 slowKeysAcceptBeep
->setChecked(keyboardGroup
.readEntry("SlowKeysAcceptBeep", true));
693 slowKeysRejectBeep
->setChecked(keyboardGroup
.readEntry("SlowKeysRejectBeep", true));
695 bounceKeys
->setChecked(keyboardGroup
.readEntry("BounceKeys", false));
696 bounceKeysDelay
->setValue(keyboardGroup
.readEntry("BounceKeysDelay", 500));
697 bounceKeysRejectBeep
->setChecked(keyboardGroup
.readEntry("BounceKeysRejectBeep", true));
699 gestures
->setChecked(keyboardGroup
.readEntry("Gestures", true));
700 timeout
->setChecked(keyboardGroup
.readEntry("AccessXTimeout", false));
701 timeoutDelay
->setValue(keyboardGroup
.readEntry("AccessXTimeoutDelay", 30));
703 accessxBeep
->setChecked(keyboardGroup
.readEntry("AccessXBeep", true));
704 gestureConfirmation
->setChecked(keyboardGroup
.readEntry("GestureConfirmation", false));
705 kNotifyAccessX
->setChecked(keyboardGroup
.readEntry("kNotifyAccessX", false));
713 void KAccessConfig::save()
715 KConfigGroup
cg(KSharedConfig::openConfig("kaccessrc"), "Bell");
717 cg
.writeEntry("SystemBell", systemBell
->isChecked());
718 cg
.writeEntry("ArtsBell", customBell
->isChecked());
719 cg
.writePathEntry("ArtsBellFile", soundEdit
->text());
721 cg
.writeEntry("VisibleBell", visibleBell
->isChecked());
722 cg
.writeEntry("VisibleBellInvert", invertScreen
->isChecked());
723 cg
.writeEntry("VisibleBellColor", colorButton
->color());
725 cg
.writeEntry("VisibleBellPause", durationSlider
->value());
727 KConfigGroup
keyboardGroup(KSharedConfig::openConfig("kaccessrc"),"Keyboard");
729 keyboardGroup
.writeEntry("StickyKeys", stickyKeys
->isChecked());
730 keyboardGroup
.writeEntry("StickyKeysLatch", stickyKeysLock
->isChecked());
731 keyboardGroup
.writeEntry("StickyKeysAutoOff", stickyKeysAutoOff
->isChecked());
732 keyboardGroup
.writeEntry("StickyKeysBeep", stickyKeysBeep
->isChecked());
733 keyboardGroup
.writeEntry("ToggleKeysBeep", toggleKeysBeep
->isChecked());
734 keyboardGroup
.writeEntry("kNotifyModifiers", kNotifyModifiers
->isChecked());
736 keyboardGroup
.writeEntry("SlowKeys", slowKeys
->isChecked());
737 keyboardGroup
.writeEntry("SlowKeysDelay", slowKeysDelay
->value());
738 keyboardGroup
.writeEntry("SlowKeysPressBeep", slowKeysPressBeep
->isChecked());
739 keyboardGroup
.writeEntry("SlowKeysAcceptBeep", slowKeysAcceptBeep
->isChecked());
740 keyboardGroup
.writeEntry("SlowKeysRejectBeep", slowKeysRejectBeep
->isChecked());
743 keyboardGroup
.writeEntry("BounceKeys", bounceKeys
->isChecked());
744 keyboardGroup
.writeEntry("BounceKeysDelay", bounceKeysDelay
->value());
745 keyboardGroup
.writeEntry("BounceKeysRejectBeep", bounceKeysRejectBeep
->isChecked());
747 keyboardGroup
.writeEntry("Gestures", gestures
->isChecked());
748 keyboardGroup
.writeEntry("AccessXTimeout", timeout
->isChecked());
749 keyboardGroup
.writeEntry("AccessXTimeoutDelay", timeoutDelay
->value());
751 keyboardGroup
.writeEntry("AccessXBeep", accessxBeep
->isChecked());
752 keyboardGroup
.writeEntry("GestureConfirmation", gestureConfirmation
->isChecked());
753 keyboardGroup
.writeEntry("kNotifyAccessX", kNotifyAccessX
->isChecked());
757 keyboardGroup
.sync();
759 if (systemBell
->isChecked() ||
760 customBell
->isChecked() ||
761 visibleBell
->isChecked())
763 KConfig
_cfg("kdeglobals", KConfig::NoGlobals
);
764 KConfigGroup
cfg(&_cfg
, "General");
765 cfg
.writeEntry("UseSystemBell", true);
769 // make kaccess reread the configuration
770 // When turning things off, it needs to be done by kaccess,
771 // so don't actually kill it *shrug*.
772 if ( true /*needToRunKAccessDaemon( config )*/ )
773 KToolInvocation::startServiceByDesktopName("kaccess");
775 else // don't need it -> kill it
778 #warning "kde4: dbus port: need to test it"
780 QDBusInterface
kaccess("org.kde.kaccess", "/KAccess", "org.kde.kaccess.KAccess");
781 kaccess
.call("quit");
782 //DCOPRef kaccess( "kaccess", "qt/kaccess" );
783 //kaccess.send( "quit" );
790 void KAccessConfig::defaults()
792 systemBell
->setChecked(true);
793 customBell
->setChecked(false);
794 soundEdit
->setText("");
796 visibleBell
->setChecked(false);
797 invertScreen
->setChecked(true);
798 flashScreen
->setChecked(false);
799 colorButton
->setColor(QColor(Qt::red
));
801 durationSlider
->setValue(500);
803 slowKeys
->setChecked(false);
804 slowKeysDelay
->setValue(500);
805 slowKeysPressBeep
->setChecked(true);
806 slowKeysAcceptBeep
->setChecked(true);
807 slowKeysRejectBeep
->setChecked(true);
809 bounceKeys
->setChecked(false);
810 bounceKeysDelay
->setValue(500);
811 bounceKeysRejectBeep
->setChecked(true);
813 stickyKeys
->setChecked(false);
814 stickyKeysLock
->setChecked(true);
815 stickyKeysAutoOff
->setChecked(false);
816 stickyKeysBeep
->setChecked(true);
817 toggleKeysBeep
->setChecked(false);
818 kNotifyModifiers
->setChecked(false);
820 gestures
->setChecked(true);
821 timeout
->setChecked(false);
822 timeoutDelay
->setValue(30);
824 accessxBeep
->setChecked(true);
825 gestureConfirmation
->setChecked(true);
826 kNotifyAccessX
->setChecked(false);
834 void KAccessConfig::invertClicked()
836 flashScreen
->setChecked(false);
840 void KAccessConfig::flashClicked()
842 invertScreen
->setChecked(false);
846 void KAccessConfig::checkAccess()
848 bool custom
= customBell
->isChecked();
849 soundEdit
->setEnabled(custom
);
850 soundButton
->setEnabled(custom
);
851 soundLabel
->setEnabled(custom
);
853 bool visible
= visibleBell
->isChecked();
854 invertScreen
->setEnabled(visible
);
855 flashScreen
->setEnabled(visible
);
856 colorButton
->setEnabled(visible
);
857 durationSlider
->setEnabled(visible
);
859 bool sticky
= stickyKeys
->isChecked();
860 stickyKeysLock
->setEnabled(sticky
);
861 stickyKeysAutoOff
->setEnabled(sticky
);
862 stickyKeysBeep
->setEnabled(sticky
);
864 bool slow
= slowKeys
->isChecked();
865 slowKeysDelay
->setEnabled(slow
);
866 slowKeysPressBeep
->setEnabled(slow
);
867 slowKeysAcceptBeep
->setEnabled(slow
);
868 slowKeysRejectBeep
->setEnabled(slow
);
870 bool bounce
= bounceKeys
->isChecked();
871 bounceKeysDelay
->setEnabled(bounce
);
872 bounceKeysRejectBeep
->setEnabled(bounce
);
874 bool useTimeout
= timeout
->isChecked();
875 timeoutDelay
->setEnabled(useTimeout
);
880 /* This one gets called by kcminit
883 KDE_EXPORT
void kcminit_access()
885 KConfig
*config
= new KConfig( "kaccessrc", KConfig::NoGlobals
);
886 bool run
= needToRunKAccessDaemon( config
);
890 KToolInvocation::startServiceByDesktopName("kaccess");