8 #include <QtGui/QDesktopWidget>
10 #include <QHBoxLayout>
11 #include <QVBoxLayout>
14 #include <KMessageBox>
16 #include <KIconLoader>
18 #include <KNotification>
24 #include <kwindowsystem.h>
25 #include <kkeyserver.h>
27 #include <X11/XKBlib.h>
30 #include <X11/keysymdef.h>
33 #include "kaccess.moc"
38 const unsigned int mask
;
41 const char *lockedText
;
42 const char *latchedText
;
43 const char *unlatchedText
;
46 static ModifierKey modifierKeys
[] = {
47 { ShiftMask
, 0, "Shift",
48 I18N_NOOP("The Shift key has been locked and is now active for all of the following keypresses."),
49 I18N_NOOP("The Shift key is now active."),
50 I18N_NOOP("The Shift key is now inactive.") },
51 { ControlMask
, 0, "Control",
52 I18N_NOOP("The Control key has been locked and is now active for all of the following keypresses."),
53 I18N_NOOP("The Control key is now active."),
54 I18N_NOOP("The Control key is now inactive.") },
56 I18N_NOOP("The Alt key has been locked and is now active for all of the following keypresses."),
57 I18N_NOOP("The Alt key is now active."),
58 I18N_NOOP("The Alt key is now inactive.") },
60 I18N_NOOP("The Win key has been locked and is now active for all of the following keypresses."),
61 I18N_NOOP("The Win key is now active."),
62 I18N_NOOP("The Win key is now inactive.") },
63 { 0, XK_Meta_L
, "Meta",
64 I18N_NOOP("The Meta key has been locked and is now active for all of the following keypresses."),
65 I18N_NOOP("The Meta key is now active."),
66 I18N_NOOP("The Meta key is now inactive.") },
67 { 0, XK_Super_L
, "Super",
68 I18N_NOOP("The Super key has been locked and is now active for all of the following keypresses."),
69 I18N_NOOP("The Super key is now active."),
70 I18N_NOOP("The Super key is now inactive.") },
71 { 0, XK_Hyper_L
, "Hyper",
72 I18N_NOOP("The Hyper key has been locked and is now active for all of the following keypresses."),
73 I18N_NOOP("The Hyper key is now active."),
74 I18N_NOOP("The Hyper key is now inactive.") },
76 I18N_NOOP("The Alt Graph key has been locked and is now active for all of the following keypresses."),
77 I18N_NOOP("The Alt Graph key is now active."),
78 I18N_NOOP("The Alt Graph key is now inactive.") },
79 { 0, XK_Num_Lock
, "Num Lock",
80 I18N_NOOP("The Num Lock key has been activated."),
82 I18N_NOOP("The Num Lock key is now inactive.") },
83 { LockMask
, 0, "Caps Lock",
84 I18N_NOOP("The Caps Lock key has been activated."),
86 I18N_NOOP("The Caps Lock key is now inactive.") },
87 { 0, XK_Scroll_Lock
, "Scroll Lock",
88 I18N_NOOP("The Scroll Lock key has been activated."),
90 I18N_NOOP("The Scroll Lock key is now inactive.") },
91 { 0, 0, "", "", "", "" }
95 /********************************************************************/
98 KAccessApp::KAccessApp(bool allowStyles
, bool GUIenabled
)
99 : KUniqueApplication(allowStyles
, GUIenabled
),
100 overlay(0), _player(0)
102 _activeWindow
= KWindowSystem::activeWindow();
103 connect(KWindowSystem::self(), SIGNAL(activeWindowChanged(WId
)), this, SLOT(activeWindowChanged(WId
)));
106 requestedFeatures
= 0;
110 XkbStateRec state_return
;
111 XkbGetState (QX11Info::display(), XkbUseCoreKbd
, &state_return
);
112 unsigned char latched
= XkbStateMods (&state_return
);
113 unsigned char locked
= XkbModLocks (&state_return
);
114 state
= ((int)locked
)<<8 | latched
;
117 int KAccessApp::newInstance()
119 KGlobal::config()->reparseConfiguration();
124 void KAccessApp::readSettings()
126 KSharedConfig::Ptr _config
= KGlobal::config();
127 KConfigGroup
cg(_config
, "Bell");
129 // bell ---------------------------------------------------------------
130 _systemBell
= cg
.readEntry("SystemBell", true);
131 _artsBell
= cg
.readEntry("ArtsBell", false);
132 _currentPlayerSource
= cg
.readPathEntry("ArtsBellFile", QString());
133 _visibleBell
= cg
.readEntry("VisibleBell", false);
134 _visibleBellInvert
= cg
.readEntry("VisibleBellInvert", false);
135 _visibleBellColor
= cg
.readEntry("VisibleBellColor", QColor(Qt::red
));
136 _visibleBellPause
= cg
.readEntry("VisibleBellPause", 500);
138 // select bell events if we need them
139 int state
= (_artsBell
|| _visibleBell
) ? XkbBellNotifyMask
: 0;
140 XkbSelectEvents(QX11Info::display(), XkbUseCoreKbd
, XkbBellNotifyMask
, state
);
142 // deactivate system bell if not needed
144 XkbChangeEnabledControls(QX11Info::display(), XkbUseCoreKbd
, XkbAudibleBellMask
, 0);
146 XkbChangeEnabledControls(QX11Info::display(), XkbUseCoreKbd
, XkbAudibleBellMask
, XkbAudibleBellMask
);
148 // keyboard -------------------------------------------------------------
149 KConfigGroup
keyboardGroup(_config
,"Keyboard");
151 // get keyboard state
152 XkbDescPtr xkb
= XkbGetMap(QX11Info::display(), 0, XkbUseCoreKbd
);
155 if (XkbGetControls(QX11Info::display(), XkbAllControlsMask
, xkb
) != Success
)
159 if (keyboardGroup
.readEntry("StickyKeys", false))
161 if (keyboardGroup
.readEntry("StickyKeysLatch", true))
162 xkb
->ctrls
->ax_options
|= XkbAX_LatchToLockMask
;
164 xkb
->ctrls
->ax_options
&= ~XkbAX_LatchToLockMask
;
165 if (keyboardGroup
.readEntry("StickyKeysAutoOff", false))
166 xkb
->ctrls
->ax_options
|= XkbAX_TwoKeysMask
;
168 xkb
->ctrls
->ax_options
&= ~XkbAX_TwoKeysMask
;
169 if (keyboardGroup
.readEntry("StickyKeysBeep", false))
170 xkb
->ctrls
->ax_options
|= XkbAX_StickyKeysFBMask
;
172 xkb
->ctrls
->ax_options
&= ~XkbAX_StickyKeysFBMask
;
173 xkb
->ctrls
->enabled_ctrls
|= XkbStickyKeysMask
;
176 xkb
->ctrls
->enabled_ctrls
&= ~XkbStickyKeysMask
;
179 if (keyboardGroup
.readEntry("ToggleKeysBeep", false))
180 xkb
->ctrls
->ax_options
|= XkbAX_IndicatorFBMask
;
182 xkb
->ctrls
->ax_options
&= ~XkbAX_IndicatorFBMask
;
185 if (keyboardGroup
.readEntry("SlowKeys", false)) {
186 if (keyboardGroup
.readEntry("SlowKeysPressBeep", false))
187 xkb
->ctrls
->ax_options
|= XkbAX_SKPressFBMask
;
189 xkb
->ctrls
->ax_options
&= ~XkbAX_SKPressFBMask
;
190 if (keyboardGroup
.readEntry("SlowKeysAcceptBeep", false))
191 xkb
->ctrls
->ax_options
|= XkbAX_SKAcceptFBMask
;
193 xkb
->ctrls
->ax_options
&= ~XkbAX_SKAcceptFBMask
;
194 if (keyboardGroup
.readEntry("SlowKeysRejectBeep", false))
195 xkb
->ctrls
->ax_options
|= XkbAX_SKRejectFBMask
;
197 xkb
->ctrls
->ax_options
&= ~XkbAX_SKRejectFBMask
;
198 xkb
->ctrls
->enabled_ctrls
|= XkbSlowKeysMask
;
201 xkb
->ctrls
->enabled_ctrls
&= ~XkbSlowKeysMask
;
202 xkb
->ctrls
->slow_keys_delay
= keyboardGroup
.readEntry("SlowKeysDelay", 500);
205 if (keyboardGroup
.readEntry("BounceKeys", false)) {
206 if (keyboardGroup
.readEntry("BounceKeysRejectBeep", false))
207 xkb
->ctrls
->ax_options
|= XkbAX_BKRejectFBMask
;
209 xkb
->ctrls
->ax_options
&= ~XkbAX_BKRejectFBMask
;
210 xkb
->ctrls
->enabled_ctrls
|= XkbBounceKeysMask
;
213 xkb
->ctrls
->enabled_ctrls
&= ~XkbBounceKeysMask
;
214 xkb
->ctrls
->debounce_delay
= keyboardGroup
.readEntry("BounceKeysDelay", 500);
216 // gestures for enabling the other features
217 _gestures
= keyboardGroup
.readEntry("Gestures", true);
219 xkb
->ctrls
->enabled_ctrls
|= XkbAccessXKeysMask
;
221 xkb
->ctrls
->enabled_ctrls
&= ~XkbAccessXKeysMask
;
224 if (keyboardGroup
.readEntry("AccessXTimeout", false))
226 xkb
->ctrls
->ax_timeout
= keyboardGroup
.readEntry("AccessXTimeoutDelay", 30)*60;
227 xkb
->ctrls
->axt_opts_mask
= 0;
228 xkb
->ctrls
->axt_opts_values
= 0;
229 xkb
->ctrls
->axt_ctrls_mask
= XkbStickyKeysMask
| XkbSlowKeysMask
;
230 xkb
->ctrls
->axt_ctrls_values
= 0;
231 xkb
->ctrls
->enabled_ctrls
|= XkbAccessXTimeoutMask
;
234 xkb
->ctrls
->enabled_ctrls
&= ~XkbAccessXTimeoutMask
;
236 // gestures for enabling the other features
237 if (keyboardGroup
.readEntry("AccessXBeep", true))
238 xkb
->ctrls
->ax_options
|= XkbAX_FeatureFBMask
| XkbAX_SlowWarnFBMask
;
240 xkb
->ctrls
->ax_options
&= ~(XkbAX_FeatureFBMask
| XkbAX_SlowWarnFBMask
);
242 _gestureConfirmation
= keyboardGroup
.readEntry("GestureConfirmation", true);
244 _kNotifyModifiers
= keyboardGroup
.readEntry("kNotifyModifiers", false);
245 _kNotifyAccessX
= keyboardGroup
.readEntry("kNotifyAccessX", false);
247 // mouse-by-keyboard ----------------------------------------------
249 KConfigGroup
mouseGroup(_config
,"Mouse");
251 if (mouseGroup
.readEntry("MouseKeys", false))
253 xkb
->ctrls
->mk_delay
= mouseGroup
.readEntry("MKDelay", 160);
255 // Default for initial velocity: 200 pixels/sec
256 int interval
= mouseGroup
.readEntry("MKInterval", 5);
257 xkb
->ctrls
->mk_interval
= interval
;
259 // Default time to reach maximum speed: 5000 msec
260 xkb
->ctrls
->mk_time_to_max
= mouseGroup
.readEntry("MKTimeToMax",
261 (5000+interval
/2)/interval
);
263 // Default maximum speed: 1000 pixels/sec
264 // (The old default maximum speed from KDE <= 3.4
265 // (100000 pixels/sec) was way too fast)
266 xkb
->ctrls
->mk_max_speed
= mouseGroup
.readEntry("MKMaxSpeed", interval
);
268 xkb
->ctrls
->mk_curve
= mouseGroup
.readEntry("MKCurve", 0);
269 xkb
->ctrls
->mk_dflt_btn
= mouseGroup
.readEntry("MKDefaultButton", 0);
271 xkb
->ctrls
->enabled_ctrls
|= XkbMouseKeysMask
;
274 xkb
->ctrls
->enabled_ctrls
&= ~XkbMouseKeysMask
;
276 features
= xkb
->ctrls
->enabled_ctrls
& (XkbSlowKeysMask
| XkbBounceKeysMask
| XkbStickyKeysMask
| XkbMouseKeysMask
);
278 requestedFeatures
= features
;
280 XkbSetControls(QX11Info::display(), XkbControlsEnabledMask
| XkbMouseKeysAccelMask
| XkbStickyKeysMask
| XkbSlowKeysMask
| XkbBounceKeysMask
| XkbAccessXKeysMask
| XkbAccessXTimeoutMask
, xkb
);
282 // select AccessX events
283 XkbSelectEvents(QX11Info::display(), XkbUseCoreKbd
, XkbAllEventsMask
, XkbAllEventsMask
);
285 if (!_artsBell
&& !_visibleBell
&& !_gestureConfirmation
286 && !_kNotifyModifiers
&& !_kNotifyAccessX
) {
288 // We will exit, but the features need to stay configured
289 uint ctrls
= XkbStickyKeysMask
| XkbSlowKeysMask
| XkbBounceKeysMask
| XkbMouseKeysMask
| XkbAudibleBellMask
| XkbControlsNotifyMask
;
290 uint values
= xkb
->ctrls
->enabled_ctrls
& ctrls
;
291 XkbSetAutoResetControls(QX11Info::display(), ctrls
, &ctrls
, &values
);
294 // reset them after program exit
295 uint ctrls
= XkbStickyKeysMask
| XkbSlowKeysMask
| XkbBounceKeysMask
| XkbMouseKeysMask
| XkbAudibleBellMask
| XkbControlsNotifyMask
;
296 uint values
= XkbAudibleBellMask
;
297 XkbSetAutoResetControls(QX11Info::display(), ctrls
, &ctrls
, &values
);
304 static int maskToBit (int mask
) {
305 for (int i
= 0; i
< 8; i
++)
311 void KAccessApp::initMasks() {
312 for (int i
= 0; i
< 8; i
++)
316 for (int i
= 0; strcmp (modifierKeys
[i
].name
, "") != 0; i
++) {
317 int mask
= modifierKeys
[i
].mask
;
319 if (modifierKeys
[i
].keysym
!= 0) {
320 mask
= XkbKeysymToModifiers (QX11Info::display(), modifierKeys
[i
].keysym
);
322 if (!strcmp(modifierKeys
[i
].name
, "Win")) {
323 mask
= KKeyServer::modXMeta();
325 mask
= XkbKeysymToModifiers (QX11Info::display(), XK_Mode_switch
)
326 | XkbKeysymToModifiers (QX11Info::display(), XK_ISO_Level3_Shift
)
327 | XkbKeysymToModifiers (QX11Info::display(), XK_ISO_Level3_Latch
)
328 | XkbKeysymToModifiers (QX11Info::display(), XK_ISO_Level3_Lock
);
334 int bit
= maskToBit (mask
);
335 if (bit
!= -1 && keys
[bit
] == -1)
341 bool KAccessApp::x11EventFilter(XEvent
*event
)
344 if (event
->type
== xkb_opcode
)
346 XkbAnyEvent
*ev
= (XkbAnyEvent
*) event
;
348 switch (ev
->xkb_type
) {
353 xkbBellNotify((XkbBellNotifyEvent
*)event
);
355 case XkbControlsNotify
:
356 xkbControlsNotify((XkbControlsNotifyEvent
*)event
);
362 // process other events as usual
363 return KApplication::x11EventFilter(event
);
367 void VisualBell::paintEvent(QPaintEvent
*event
)
369 QWidget::paintEvent(event
);
370 QTimer::singleShot(_pause
, this, SLOT(hide()));
374 void KAccessApp::activeWindowChanged(WId wid
)
380 void KAccessApp::xkbStateNotify () {
381 XkbStateRec state_return
;
382 XkbGetState (QX11Info::display(), XkbUseCoreKbd
, &state_return
);
383 unsigned char latched
= XkbStateMods (&state_return
);
384 unsigned char locked
= XkbModLocks (&state_return
);
385 int mods
= ((int)locked
)<<8 | latched
;
388 if (_kNotifyModifiers
)
389 for (int i
= 0; i
< 8; i
++) {
391 if ( !strcmp(modifierKeys
[keys
[i
]].latchedText
, "")
392 && ( (((mods
>> i
) & 0x101) != 0) != (((state
>> i
) & 0x101) != 0) ))
394 if ((mods
>> i
) & 1) {
395 KNotification::event ("lockkey-locked", i18n(modifierKeys
[keys
[i
]].lockedText
));
398 KNotification::event ("lockkey-unlocked", i18n(modifierKeys
[keys
[i
]].unlatchedText
));
401 else if (strcmp(modifierKeys
[keys
[i
]].latchedText
, "")
402 && ( ((mods
>> i
) & 0x101) != ((state
>> i
) & 0x101) ))
404 if ((mods
>> i
) & 0x100) {
405 KNotification::event ("modifierkey-locked", i18n(modifierKeys
[keys
[i
]].lockedText
));
407 else if ((mods
>> i
) & 1) {
408 KNotification::event ( "modifierkey-latched", i18n(modifierKeys
[keys
[i
]].latchedText
));
411 KNotification::event ("modifierkey-unlatched", i18n(modifierKeys
[keys
[i
]].unlatchedText
));
420 void KAccessApp::xkbBellNotify(XkbBellNotifyEvent
*event
)
422 // bail out if we should not really ring
423 if (event
->event_only
)
426 // flash the visible bell
429 // create overlay widget
431 overlay
= new VisualBell(_visibleBellPause
);
433 WId id
= _activeWindow
;
435 NETRect frame
, window
;
436 NETWinInfo
net(QX11Info::display(), id
, desktop()->winId(), 0);
438 net
.kdeGeometry(frame
, window
);
440 overlay
->setGeometry(window
.pos
.x
, window
.pos
.y
, window
.size
.width
, window
.size
.height
);
442 if (_visibleBellInvert
)
444 QPixmap screen
= QPixmap::grabWindow(id
, 0, 0, window
.size
.width
, window
.size
.height
);
446 #warning is this the best way to invert a pixmap?
448 // QPixmap invert(window.size.width, window.size.height);
449 QImage i
= screen
.toImage();
451 QPalette pal
= overlay
->palette();
452 pal
.setBrush(overlay
->backgroundRole(), QBrush(QPixmap::fromImage(i
)));
453 overlay
->setPalette(pal
);
456 p.setRasterOp(QPainter::NotCopyROP);
457 p.drawPixmap(0, 0, screen);
458 overlay->setBackgroundPixmap(invert);
463 QPalette pal
= overlay
->palette();
464 pal
.setColor(overlay
->backgroundRole(), _visibleBellColor
);
465 overlay
->setPalette(pal
);
468 // flash the overlay widget
474 // ask Phonon to ring a nice bell
476 if (!_player
) { // as creating the player is expensive, delay the creation
477 _player
= Phonon::createPlayer(Phonon::AccessibilityCategory
);
478 _player
->setParent(this);
479 _player
->setCurrentSource(_currentPlayerSource
);
485 QString
mouseKeysShortcut (Display
*display
) {
486 // Calculate the keycode
487 KeySym sym
= XK_MouseKeys_Enable
;
488 KeyCode code
= XKeysymToKeycode(display
, sym
);
490 sym
= XK_Pointer_EnableKeys
;
491 code
= XKeysymToKeycode(display
, sym
);
493 return ""; // No shortcut available?
496 // Calculate the modifiers by searching the keysym in the X keyboard mapping
497 XkbDescPtr xkbdesc
= XkbGetMap(display
, XkbKeyTypesMask
| XkbKeySymsMask
, XkbUseCoreKbd
);
500 return ""; // Failed to obtain the mapping from server
503 unsigned char modifiers
= 0;
504 int groups
= XkbKeyNumGroups(xkbdesc
, code
);
505 for (int grp
= 0; grp
< groups
&& !found
; grp
++)
507 int levels
= XkbKeyGroupWidth(xkbdesc
, code
, grp
);
508 for (int level
= 0; level
< levels
&& !found
; level
++)
510 if (sym
== XkbKeySymEntry(xkbdesc
, code
, level
, grp
))
512 // keysym found => determine modifiers
513 int typeIdx
= xkbdesc
->map
->key_sym_map
[code
].kt_index
[grp
];
514 XkbKeyTypePtr type
= &(xkbdesc
->map
->types
[typeIdx
]);
515 for (int i
= 0; i
< type
->map_count
&& !found
; i
++)
517 if (type
->map
[i
].active
&& (type
->map
[i
].level
== level
))
519 modifiers
= type
->map
[i
].mods
.mask
;
526 XkbFreeClientMap (xkbdesc
, 0, true);
529 return ""; // Somehow the keycode -> keysym mapping is flawed
532 ev
.xkey
.display
= display
;
533 ev
.xkey
.keycode
= code
;
536 KKeyServer::xEventToQt(&ev
, &key
);
537 QString keyname
= QKeySequence(key
).toString();
539 unsigned int AltMask
= KKeyServer::modXAlt();
540 unsigned int WinMask
= KKeyServer::modXMeta();
541 unsigned int NumMask
= KKeyServer::modXNumLock();
542 unsigned int ScrollMask
= KKeyServer::modXScrollLock();
544 unsigned int MetaMask
= XkbKeysymToModifiers (display
, XK_Meta_L
);
545 unsigned int SuperMask
= XkbKeysymToModifiers (display
, XK_Super_L
);
546 unsigned int HyperMask
= XkbKeysymToModifiers (display
, XK_Hyper_L
);
547 unsigned int AltGrMask
= XkbKeysymToModifiers (display
, XK_Mode_switch
)
548 | XkbKeysymToModifiers (display
, XK_ISO_Level3_Shift
)
549 | XkbKeysymToModifiers (display
, XK_ISO_Level3_Latch
)
550 | XkbKeysymToModifiers (display
, XK_ISO_Level3_Lock
);
552 unsigned int mods
= ShiftMask
| ControlMask
| AltMask
| WinMask
553 | LockMask
| NumMask
| ScrollMask
;
556 MetaMask
&= ~(mods
| AltGrMask
);
557 SuperMask
&= ~(mods
| AltGrMask
| MetaMask
);
558 HyperMask
&= ~(mods
| AltGrMask
| MetaMask
| SuperMask
);
560 if ((modifiers
& AltGrMask
) != 0)
561 keyname
= i18n("AltGraph") + '+' + keyname
;
562 if ((modifiers
& HyperMask
) != 0)
563 keyname
= i18n("Hyper") + '+' + keyname
;
564 if ((modifiers
& SuperMask
) != 0)
565 keyname
= i18n("Super") + '+' + keyname
;
566 if ((modifiers
& WinMask
) != 0)
567 keyname
= i18n("Meta") + '+' + keyname
;
568 if ((modifiers
& WinMask
) != 0)
569 keyname
= QKeySequence(Qt::META
).toString() + '+' + keyname
;
570 if ((modifiers
& AltMask
) != 0)
571 keyname
= QKeySequence(Qt::ALT
).toString() + '+' + keyname
;
572 if ((modifiers
& ControlMask
) != 0)
573 keyname
= QKeySequence(Qt::CTRL
).toString() + '+' + keyname
;
574 if ((modifiers
& ShiftMask
) != 0)
575 keyname
= QKeySequence(Qt::SHIFT
).toString() + '+' + keyname
;
580 void KAccessApp::createDialogContents() {
582 dialog
= new KDialog( 0 );
583 dialog
->setCaption( i18n("Warning") );
584 dialog
->setButtons( KDialog::Yes
| KDialog::No
);
585 dialog
->setButtonGuiItem( KDialog::Yes
, KStandardGuiItem::yes() );
586 dialog
->setButtonGuiItem( KDialog::No
, KStandardGuiItem::no() );
587 dialog
->setEscapeButton( KDialog::Close
);
588 dialog
->setObjectName( "AccessXWarning" );
589 dialog
->setModal( true );
590 dialog
->showButtonSeparator( true );
592 KVBox
*topcontents
= new KVBox (dialog
);
593 topcontents
->setSpacing(KDialog::spacingHint()*2);
595 #warning "kde4 fixme"
597 //topcontents->setMargin(KDialog::marginHint());
599 QWidget
*contents
= new QWidget(topcontents
);
600 QHBoxLayout
* lay
= new QHBoxLayout(contents
);
601 lay
->setSpacing(KDialog::spacingHint());
603 QLabel
*label1
= new QLabel( contents
);
604 QPixmap pixmap
= KIconLoader::global()->loadIcon("dialog-warning", KIconLoader::NoGroup
, KIconLoader::SizeMedium
, KIconLoader::DefaultState
, QStringList(), 0, true);
606 pixmap
= QMessageBox::standardIcon(QMessageBox::Warning
);
607 label1
->setPixmap(pixmap
);
609 lay
->addWidget( label1
, 0, Qt::AlignCenter
);
610 lay
->addSpacing(KDialog::spacingHint());
612 QVBoxLayout
* vlay
= new QVBoxLayout();
613 lay
->addItem( vlay
);
615 featuresLabel
= new QLabel( "", contents
);
616 featuresLabel
->setAlignment( Qt::AlignVCenter
);
617 featuresLabel
->setWordWrap( true );
618 vlay
->addWidget( featuresLabel
);
621 QHBoxLayout
* hlay
= new QHBoxLayout();
624 QLabel
*showModeLabel
= new QLabel( i18n("&When a gesture was used:"), contents
);
625 hlay
->addWidget( showModeLabel
);
627 showModeCombobox
= new KComboBox (contents
);
628 hlay
->addWidget( showModeCombobox
);
629 showModeLabel
->setBuddy(showModeCombobox
);
630 showModeCombobox
->insertItem ( 0, i18n("Change Settings Without Asking"));
631 showModeCombobox
->insertItem ( 1, i18n("Show This Confirmation Dialog"));
632 showModeCombobox
->insertItem ( 2, i18n("Deactivate All AccessX Features & Gestures"));
633 showModeCombobox
->setCurrentIndex (1);
635 dialog
->setMainWidget(topcontents
);
636 dialog
->showButtonSeparator(false);
638 connect (dialog
, SIGNAL(yesClicked()), this, SLOT(yesClicked()));
639 connect (dialog
, SIGNAL(noClicked()), this, SLOT(noClicked()));
640 connect (dialog
, SIGNAL(closeClicked()), this, SLOT(dialogClosed()));
644 void KAccessApp::xkbControlsNotify(XkbControlsNotifyEvent
*event
)
646 unsigned int newFeatures
= event
->enabled_ctrls
& (XkbSlowKeysMask
| XkbBounceKeysMask
| XkbStickyKeysMask
| XkbMouseKeysMask
);
648 if (newFeatures
!= features
) {
649 unsigned int enabled
= newFeatures
& ~features
;
650 unsigned int disabled
= features
& ~newFeatures
;
652 if (!_gestureConfirmation
) {
653 requestedFeatures
= enabled
| (requestedFeatures
& ~disabled
);
655 features
= newFeatures
;
658 // set the AccessX features back to what they were. We will
659 // apply the changes later if the user allows us to do that.
662 requestedFeatures
= enabled
| (requestedFeatures
& ~disabled
);
664 enabled
= requestedFeatures
& ~features
;
665 disabled
= features
& ~requestedFeatures
;
667 QStringList enabledFeatures
;
668 QStringList disabledFeatures
;
670 if (enabled
& XkbStickyKeysMask
)
671 enabledFeatures
<< i18n("Sticky keys");
672 else if (disabled
& XkbStickyKeysMask
)
673 disabledFeatures
<< i18n("Sticky keys");
675 if (enabled
& XkbSlowKeysMask
)
676 enabledFeatures
<< i18n("Slow keys");
677 else if (disabled
& XkbSlowKeysMask
)
678 disabledFeatures
<< i18n("Slow keys");
680 if (enabled
& XkbBounceKeysMask
)
681 enabledFeatures
<< i18n("Bounce keys");
682 else if (disabled
& XkbBounceKeysMask
)
683 disabledFeatures
<< i18n("Bounce keys");
685 if (enabled
& XkbMouseKeysMask
)
686 enabledFeatures
<< i18n("Mouse keys");
687 else if (disabled
& XkbMouseKeysMask
)
688 disabledFeatures
<< i18n("Mouse keys");
691 switch (enabledFeatures
.count()) {
692 case 0: switch (disabledFeatures
.count()) {
693 case 1: question
= i18n("Do you really want to deactivate \"%1\"?",
694 disabledFeatures
[0]);
696 case 2: question
= i18n("Do you really want to deactivate \"%1\" and \"%2\"?",
697 disabledFeatures
[0], disabledFeatures
[1]);
699 case 3: question
= i18n("Do you really want to deactivate \"%1\", \"%2\" and \"%3\"?",
700 disabledFeatures
[0], disabledFeatures
[1],
701 disabledFeatures
[2]);
703 case 4: question
= i18n("Do you really want to deactivate \"%1\", \"%2\", \"%3\" and \"%4\"?",
704 disabledFeatures
[0], disabledFeatures
[1],
705 disabledFeatures
[2], disabledFeatures
[3]);
709 case 1: switch (disabledFeatures
.count()) {
710 case 0: question
= i18n("Do you really want to activate \"%1\"?",
713 case 1: question
= i18n("Do you really want to activate \"%1\" and to deactivate \"%2\"?",
714 enabledFeatures
[0], disabledFeatures
[0]);
716 case 2: question
= i18n("Do you really want to activate \"%1\" and to deactivate \"%2\" and \"%3\"?",
717 enabledFeatures
[0], disabledFeatures
[0],
718 disabledFeatures
[1]);
720 case 3: question
= i18n("Do you really want to activate \"%1\" and to deactivate \"%2\", \"%3\" and \"%4\"?",
721 enabledFeatures
[0], disabledFeatures
[0],
722 disabledFeatures
[1], disabledFeatures
[2]);
726 case 2: switch (disabledFeatures
.count()) {
727 case 0: question
= i18n("Do you really want to activate \"%1\" and \"%2\"?",
728 enabledFeatures
[0], enabledFeatures
[1]);
730 case 1: question
= i18n("Do you really want to activate \"%1\" and \"%2\" and to deactivate \"%3\"?",
731 enabledFeatures
[0], enabledFeatures
[1],
732 disabledFeatures
[0]);
734 case 2: question
= i18n("Do you really want to activate \"%1\", and \"%2\" and to deactivate \"%3\" and \"%4\"?",
735 enabledFeatures
[0], enabledFeatures
[1],
736 enabledFeatures
[0], disabledFeatures
[1]);
740 case 3: switch (disabledFeatures
.count()) {
741 case 0: question
= i18n("Do you really want to activate \"%1\", \"%2\" and \"%3\"?",
742 enabledFeatures
[0], enabledFeatures
[1],
745 case 1: question
= i18n("Do you really want to activate \"%1\", \"%2\" and \"%3\" and to deactivate \"%4\"?",
746 enabledFeatures
[0], enabledFeatures
[1],
747 enabledFeatures
[2], disabledFeatures
[0]);
751 case 4: question
= i18n("Do you really want to activate \"%1\", \"%2\", \"%3\" and \"%4\"?",
752 enabledFeatures
[0], enabledFeatures
[1],
753 enabledFeatures
[2], enabledFeatures
[3]);
757 if (enabledFeatures
.count()+disabledFeatures
.count() == 1) {
758 explanation
= i18n("An application has requested to change this setting.");
761 if ((enabled
| disabled
) == XkbSlowKeysMask
)
762 explanation
= i18n("You held down the Shift key for 8 seconds or an application has requested to change this setting.");
763 else if ((enabled
| disabled
) == XkbStickyKeysMask
)
764 explanation
= i18n("You pressed the Shift key 5 consecutive times or an application has requested to change this setting.");
765 else if ((enabled
| disabled
) == XkbMouseKeysMask
) {
766 QString shortcut
= mouseKeysShortcut(QX11Info::display());
767 if (!shortcut
.isEmpty() && !shortcut
.isNull())
768 explanation
= i18n("You pressed %1 or an application has requested to change this setting.", shortcut
);
774 explanation
= i18n("An application has requested to change these settings, or you used a combination of several keyboard gestures.");
776 explanation
= i18n("An application has requested to change these settings.");
779 createDialogContents();
780 featuresLabel
->setText ( question
+"\n\n"+explanation
781 +" "+i18n("These AccessX settings are needed for some users with motion impairments and can be configured in the KDE Control Center. You can also turn them on and off with standardized keyboard gestures.\n\nIf you do not need them, you can select \"Deactivate all AccessX features and gestures\".") );
783 KWindowSystem::setState( dialog
->winId(), NET::KeepAbove
);
784 kapp
->updateUserTimestamp();
790 void KAccessApp::notifyChanges() {
791 if (!_kNotifyAccessX
)
794 unsigned int enabled
= requestedFeatures
& ~features
;
795 unsigned int disabled
= features
& ~requestedFeatures
;
797 if (enabled
& XkbSlowKeysMask
)
798 KNotification::event ("slowkeys", i18n("Slow keys has been enabled. From now on, you need to press each key for a certain length of time before it gets accepted."));
799 else if (disabled
& XkbSlowKeysMask
)
800 KNotification::event ("slowkeys", i18n("Slow keys has been disabled."));
802 if (enabled
& XkbBounceKeysMask
)
803 KNotification::event ("bouncekeys", i18n("Bounce keys has been enabled. From now on, each key will be blocked for a certain length of time after it was used."));
804 else if (disabled
& XkbBounceKeysMask
)
805 KNotification::event ("bouncekeys", i18n("Bounce keys has been disabled."));
807 if (enabled
& XkbStickyKeysMask
)
808 KNotification::event ("stickykeys", i18n("Sticky keys has been enabled. From now on, modifier keys will stay latched after you have released them."));
809 else if (disabled
& XkbStickyKeysMask
)
810 KNotification::event ("stickykeys", i18n("Sticky keys has been disabled."));
812 if (enabled
& XkbMouseKeysMask
)
813 KNotification::event ("mousekeys", i18n("Mouse keys has been enabled. From now on, you can use the number pad of your keyboard in order to control the mouse."));
814 else if (disabled
& XkbMouseKeysMask
)
815 KNotification::event ("mousekeys", i18n("Mouse keys has been disabled."));
818 void KAccessApp::applyChanges() {
820 unsigned int enabled
= requestedFeatures
& ~features
;
821 unsigned int disabled
= features
& ~requestedFeatures
;
823 KConfigGroup
config(KGlobal::config(), "Keyboard");
825 if (enabled
& XkbSlowKeysMask
)
826 config
.writeEntry("SlowKeys", true);
827 else if (disabled
& XkbSlowKeysMask
)
828 config
.writeEntry("SlowKeys", false);
830 if (enabled
& XkbBounceKeysMask
)
831 config
.writeEntry("BounceKeys", true);
832 else if (disabled
& XkbBounceKeysMask
)
833 config
.writeEntry("BounceKeys", false);
835 if (enabled
& XkbStickyKeysMask
)
836 config
.writeEntry("StickyKeys", true);
837 else if (disabled
& XkbStickyKeysMask
)
838 config
.writeEntry("StickyKeys", false);
840 KConfigGroup
mousegrp(KGlobal::config(),"Mouse");
842 if (enabled
& XkbMouseKeysMask
)
843 mousegrp
.writeEntry("MouseKeys", true);
844 else if (disabled
& XkbMouseKeysMask
)
845 mousegrp
.writeEntry("MouseKeys", false);
850 void KAccessApp::yesClicked() {
852 dialog
->deleteLater();
855 KConfigGroup
config(KGlobal::config(), "Keyboard");
856 switch (showModeCombobox
->currentIndex()) {
858 config
.writeEntry("Gestures", true);
859 config
.writeEntry("GestureConfirmation", false);
862 config
.writeEntry("Gestures", true);
863 config
.writeEntry("GestureConfirmation", true);
866 requestedFeatures
= 0;
867 config
.writeEntry("Gestures", false);
868 config
.writeEntry("GestureConfirmation", true);
872 if (features
!= requestedFeatures
) {
879 void KAccessApp::noClicked() {
881 dialog
->deleteLater();
883 requestedFeatures
= features
;
885 KConfigGroup
config(KGlobal::config(), "Keyboard");
886 switch (showModeCombobox
->currentIndex()) {
888 config
.writeEntry("Gestures", true);
889 config
.writeEntry("GestureConfirmation", false);
892 config
.writeEntry("Gestures", true);
893 config
.writeEntry("GestureConfirmation", true);
896 requestedFeatures
= 0;
897 config
.writeEntry("Gestures", false);
898 config
.writeEntry("GestureConfirmation", true);
902 if (features
!= requestedFeatures
)
907 void KAccessApp::dialogClosed() {
909 dialog
->deleteLater();
912 requestedFeatures
= features
;
915 void KAccessApp::setXkbOpcode(int opcode
) {