TDE base libraries and programs
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

897 lines
33KB

  1. #include <unistd.h>
  2. #include <stdlib.h>
  3. #include <tqtimer.h>
  4. #include <tqpainter.h>
  5. #include <tqvbox.h>
  6. #include <tqlayout.h>
  7. #include <tqlabel.h>
  8. #include <kdialogbase.h>
  9. #include <tdemessagebox.h>
  10. #include <kcombobox.h>
  11. #include <kiconloader.h>
  12. #include <kdebug.h>
  13. #include <kaudioplayer.h>
  14. #include <knotifyclient.h>
  15. #include <tdeconfig.h>
  16. #include <tdeglobal.h>
  17. #include <tdelocale.h>
  18. #include <netwm.h>
  19. #include <tdeshortcut.h>
  20. #include <kkeynative.h>
  21. #include <twin.h>
  22. #include <X11/XKBlib.h>
  23. #define XK_MISCELLANY
  24. #define XK_XKB_KEYS
  25. #include <X11/keysymdef.h>
  26. #include "kaccess.moc"
  27. struct ModifierKey {
  28. const unsigned int mask;
  29. const KeySym keysym;
  30. const char *name;
  31. const char *lockedText;
  32. const char *latchedText;
  33. const char *unlatchedText;
  34. };
  35. static ModifierKey modifierKeys[] = {
  36. { ShiftMask, 0, "Shift",
  37. I18N_NOOP("The Shift key has been locked and is now active for all of the following keypresses."),
  38. I18N_NOOP("The Shift key is now active."),
  39. I18N_NOOP("The Shift key is now inactive.") },
  40. { ControlMask, 0, "Control",
  41. I18N_NOOP("The Ctrl key has been locked and is now active for all of the following keypresses."),
  42. I18N_NOOP("The Ctrl key is now active."),
  43. I18N_NOOP("The Ctrl key is now inactive.") },
  44. { 0, XK_Alt_L, "Alt",
  45. I18N_NOOP("The Alt key has been locked and is now active for all of the following keypresses."),
  46. I18N_NOOP("The Alt key is now active."),
  47. I18N_NOOP("The Alt key is now inactive.") },
  48. { 0, 0, "Win",
  49. I18N_NOOP("The Win key has been locked and is now active for all of the following keypresses."),
  50. I18N_NOOP("The Win key is now active."),
  51. I18N_NOOP("The Win key is now inactive.") },
  52. { 0, XK_Meta_L, "Meta",
  53. I18N_NOOP("The Meta key has been locked and is now active for all of the following keypresses."),
  54. I18N_NOOP("The Meta key is now active."),
  55. I18N_NOOP("The Meta key is now inactive.") },
  56. { 0, XK_Super_L, "Super",
  57. I18N_NOOP("The Super key has been locked and is now active for all of the following keypresses."),
  58. I18N_NOOP("The Super key is now active."),
  59. I18N_NOOP("The Super key is now inactive.") },
  60. { 0, XK_Hyper_L, "Hyper",
  61. I18N_NOOP("The Hyper key has been locked and is now active for all of the following keypresses."),
  62. I18N_NOOP("The Hyper key is now active."),
  63. I18N_NOOP("The Hyper key is now inactive.") },
  64. { 0, 0, "Alt Graph",
  65. I18N_NOOP("The Alt Gr key has been locked and is now active for all of the following keypresses."),
  66. I18N_NOOP("The Alt Gr key is now active."),
  67. I18N_NOOP("The Alt Gr key is now inactive.") },
  68. { 0, XK_Num_Lock, "Num Lock",
  69. I18N_NOOP("The Num Lock key has been activated."),
  70. "",
  71. I18N_NOOP("The Num Lock key is now inactive.") },
  72. { LockMask, 0, "Caps Lock",
  73. I18N_NOOP("The Caps Lock key has been activated."),
  74. "",
  75. I18N_NOOP("The Caps Lock key is now inactive.") },
  76. { 0, XK_Scroll_Lock, "Scroll Lock",
  77. I18N_NOOP("The Scroll Lock key has been activated."),
  78. "",
  79. I18N_NOOP("The Scroll Lock key is now inactive.") },
  80. { 0, 0, "", "", "", "" }
  81. };
  82. /********************************************************************/
  83. KAccessApp::KAccessApp(bool allowStyles, bool GUIenabled)
  84. : KUniqueApplication(allowStyles, GUIenabled), _artsBellBlocked(false),
  85. overlay(0), wm(0, KWinModule::INFO_DESKTOP)
  86. {
  87. _activeWindow = wm.activeWindow();
  88. connect(&wm, TQT_SIGNAL(activeWindowChanged(WId)), this, TQT_SLOT(activeWindowChanged(WId)));
  89. artsBellTimer = new TQTimer( this );
  90. connect( artsBellTimer, TQT_SIGNAL( timeout() ), TQT_SLOT( slotArtsBellTimeout() ));
  91. features = 0;
  92. requestedFeatures = 0;
  93. dialog = 0;
  94. initMasks();
  95. XkbStateRec state_return;
  96. XkbGetState (tqt_xdisplay(), XkbUseCoreKbd, &state_return);
  97. unsigned char latched = XkbStateMods (&state_return);
  98. unsigned char locked = XkbModLocks (&state_return);
  99. state = ((int)locked)<<8 | latched;
  100. }
  101. int KAccessApp::newInstance()
  102. {
  103. TDEGlobal::config()->reparseConfiguration();
  104. readSettings();
  105. return 0;
  106. }
  107. void KAccessApp::readSettings()
  108. {
  109. TDEConfig *config = TDEGlobal::config();
  110. // bell ---------------------------------------------------------------
  111. config->setGroup("Bell");
  112. _systemBell = config->readBoolEntry("SystemBell", true);
  113. _artsBell = config->readBoolEntry("ArtsBell", false);
  114. _artsBellFile = config->readPathEntry("ArtsBellFile");
  115. _visibleBell = config->readBoolEntry("VisibleBell", false);
  116. _visibleBellInvert = config->readBoolEntry("VisibleBellInvert", false);
  117. TQColor def(Qt::red);
  118. _visibleBellColor = config->readColorEntry("VisibleBellColor", &def);
  119. _visibleBellPause = config->readNumEntry("VisibleBellPause", 500);
  120. // select bell events if we need them
  121. int state = (_artsBell || _visibleBell) ? XkbBellNotifyMask : 0;
  122. XkbSelectEvents(tqt_xdisplay(), XkbUseCoreKbd, XkbBellNotifyMask, state);
  123. // deactivate system bell if not needed
  124. if (!_systemBell)
  125. XkbChangeEnabledControls(tqt_xdisplay(), XkbUseCoreKbd, XkbAudibleBellMask, 0);
  126. else
  127. XkbChangeEnabledControls(tqt_xdisplay(), XkbUseCoreKbd, XkbAudibleBellMask, XkbAudibleBellMask);
  128. // keyboard -------------------------------------------------------------
  129. config->setGroup("Keyboard");
  130. // get keyboard state
  131. XkbDescPtr xkb = XkbGetMap(tqt_xdisplay(), 0, XkbUseCoreKbd);
  132. if (!xkb)
  133. return;
  134. if (XkbGetControls(tqt_xdisplay(), XkbAllControlsMask, xkb) != Success)
  135. return;
  136. // sticky keys
  137. if (config->readBoolEntry("StickyKeys", false))
  138. {
  139. if (config->readBoolEntry("StickyKeysLatch", true))
  140. xkb->ctrls->ax_options |= XkbAX_LatchToLockMask;
  141. else
  142. xkb->ctrls->ax_options &= ~XkbAX_LatchToLockMask;
  143. if (config->readBoolEntry("StickyKeysAutoOff", false))
  144. xkb->ctrls->ax_options |= XkbAX_TwoKeysMask;
  145. else
  146. xkb->ctrls->ax_options &= ~XkbAX_TwoKeysMask;
  147. if (config->readBoolEntry("StickyKeysBeep", false))
  148. xkb->ctrls->ax_options |= XkbAX_StickyKeysFBMask;
  149. else
  150. xkb->ctrls->ax_options &= ~XkbAX_StickyKeysFBMask;
  151. xkb->ctrls->enabled_ctrls |= XkbStickyKeysMask;
  152. }
  153. else
  154. xkb->ctrls->enabled_ctrls &= ~XkbStickyKeysMask;
  155. // toggle keys
  156. if (config->readBoolEntry("ToggleKeysBeep", false))
  157. xkb->ctrls->ax_options |= XkbAX_IndicatorFBMask;
  158. else
  159. xkb->ctrls->ax_options &= ~XkbAX_IndicatorFBMask;
  160. // slow keys
  161. if (config->readBoolEntry("SlowKeys", false)) {
  162. if (config->readBoolEntry("SlowKeysPressBeep", false))
  163. xkb->ctrls->ax_options |= XkbAX_SKPressFBMask;
  164. else
  165. xkb->ctrls->ax_options &= ~XkbAX_SKPressFBMask;
  166. if (config->readBoolEntry("SlowKeysAcceptBeep", false))
  167. xkb->ctrls->ax_options |= XkbAX_SKAcceptFBMask;
  168. else
  169. xkb->ctrls->ax_options &= ~XkbAX_SKAcceptFBMask;
  170. if (config->readBoolEntry("SlowKeysRejectBeep", false))
  171. xkb->ctrls->ax_options |= XkbAX_SKRejectFBMask;
  172. else
  173. xkb->ctrls->ax_options &= ~XkbAX_SKRejectFBMask;
  174. xkb->ctrls->enabled_ctrls |= XkbSlowKeysMask;
  175. }
  176. else
  177. xkb->ctrls->enabled_ctrls &= ~XkbSlowKeysMask;
  178. xkb->ctrls->slow_keys_delay = config->readNumEntry("SlowKeysDelay", 500);
  179. // bounce keys
  180. if (config->readBoolEntry("BounceKeys", false)) {
  181. if (config->readBoolEntry("BounceKeysRejectBeep", false))
  182. xkb->ctrls->ax_options |= XkbAX_BKRejectFBMask;
  183. else
  184. xkb->ctrls->ax_options &= ~XkbAX_BKRejectFBMask;
  185. xkb->ctrls->enabled_ctrls |= XkbBounceKeysMask;
  186. }
  187. else
  188. xkb->ctrls->enabled_ctrls &= ~XkbBounceKeysMask;
  189. xkb->ctrls->debounce_delay = config->readNumEntry("BounceKeysDelay", 500);
  190. // gestures for enabling the other features
  191. _gestures = config->readBoolEntry("Gestures", true);
  192. if (_gestures)
  193. xkb->ctrls->enabled_ctrls |= XkbAccessXKeysMask;
  194. else
  195. xkb->ctrls->enabled_ctrls &= ~XkbAccessXKeysMask;
  196. // timeout
  197. if (config->readBoolEntry("AccessXTimeout", false))
  198. {
  199. xkb->ctrls->ax_timeout = config->readNumEntry("AccessXTimeoutDelay", 30)*60;
  200. xkb->ctrls->axt_opts_mask = 0;
  201. xkb->ctrls->axt_opts_values = 0;
  202. xkb->ctrls->axt_ctrls_mask = XkbStickyKeysMask | XkbSlowKeysMask;
  203. xkb->ctrls->axt_ctrls_values = 0;
  204. xkb->ctrls->enabled_ctrls |= XkbAccessXTimeoutMask;
  205. }
  206. else
  207. xkb->ctrls->enabled_ctrls &= ~XkbAccessXTimeoutMask;
  208. // gestures for enabling the other features
  209. if (_gestures && config->readBoolEntry("AccessXBeep", true))
  210. xkb->ctrls->ax_options |= XkbAX_FeatureFBMask | XkbAX_SlowWarnFBMask;
  211. else
  212. xkb->ctrls->ax_options &= ~(XkbAX_FeatureFBMask | XkbAX_SlowWarnFBMask);
  213. _gestureConfirmation = config->readBoolEntry("GestureConfirmation", true);
  214. _kNotifyModifiers = config->readBoolEntry("kNotifyModifiers", false);
  215. _kNotifyAccessX = config->readBoolEntry("kNotifyAccessX", false);
  216. // mouse-by-keyboard ----------------------------------------------
  217. config->setGroup("Mouse");
  218. if (config->readBoolEntry("MouseKeys", false))
  219. {
  220. xkb->ctrls->mk_delay = config->readNumEntry("MKDelay", 160);
  221. // Default for initial velocity: 200 pixels/sec
  222. int interval = config->readNumEntry("MKInterval", 5);
  223. xkb->ctrls->mk_interval = interval;
  224. // Default time to reach maximum speed: 5000 msec
  225. xkb->ctrls->mk_time_to_max = config->readNumEntry("MKTimeToMax",
  226. (5000+interval/2)/interval);
  227. // Default maximum speed: 1000 pixels/sec
  228. // (The old default maximum speed from KDE <= 3.4
  229. // (100000 pixels/sec) was way too fast)
  230. xkb->ctrls->mk_max_speed = config->readNumEntry("MKMaxSpeed", interval);
  231. xkb->ctrls->mk_curve = config->readNumEntry("MKCurve", 0);
  232. xkb->ctrls->mk_dflt_btn = config->readNumEntry("MKDefaultButton", 0);
  233. xkb->ctrls->enabled_ctrls |= XkbMouseKeysMask;
  234. }
  235. else
  236. xkb->ctrls->enabled_ctrls &= ~XkbMouseKeysMask;
  237. features = xkb->ctrls->enabled_ctrls & (XkbSlowKeysMask | XkbBounceKeysMask | XkbStickyKeysMask | XkbMouseKeysMask);
  238. if (dialog == 0)
  239. requestedFeatures = features;
  240. // set state
  241. XkbSetControls(tqt_xdisplay(), XkbControlsEnabledMask | XkbMouseKeysAccelMask | XkbStickyKeysMask | XkbSlowKeysMask | XkbBounceKeysMask | XkbAccessXKeysMask | XkbAccessXTimeoutMask, xkb);
  242. // select AccessX events
  243. XkbSelectEvents(tqt_xdisplay(), XkbUseCoreKbd, XkbAllEventsMask, XkbAllEventsMask);
  244. if (!_artsBell && !_visibleBell && !_gestureConfirmation
  245. && !_kNotifyModifiers && !_kNotifyAccessX) {
  246. // We will exit, but the features need to stay configured
  247. uint ctrls = XkbStickyKeysMask | XkbSlowKeysMask | XkbBounceKeysMask | XkbMouseKeysMask | XkbAudibleBellMask | XkbControlsNotifyMask;
  248. uint values = xkb->ctrls->enabled_ctrls & ctrls;
  249. XkbSetAutoResetControls(tqt_xdisplay(), ctrls, &ctrls, &values);
  250. exit(0);
  251. } else {
  252. // reset them after program exit
  253. uint ctrls = XkbStickyKeysMask | XkbSlowKeysMask | XkbBounceKeysMask | XkbMouseKeysMask | XkbAudibleBellMask | XkbControlsNotifyMask;
  254. uint values = XkbAudibleBellMask;
  255. XkbSetAutoResetControls(tqt_xdisplay(), ctrls, &ctrls, &values);
  256. }
  257. delete overlay;
  258. overlay = 0;
  259. }
  260. static int maskToBit (int mask) {
  261. for (int i = 0; i < 8; i++)
  262. if (mask & (1 << i))
  263. return i;
  264. return -1;
  265. }
  266. void KAccessApp::initMasks() {
  267. for (int i = 0; i < 8; i++)
  268. keys [i] = -1;
  269. state = 0;
  270. for (int i = 0; strcmp (modifierKeys[i].name, "") != 0; i++) {
  271. int mask = modifierKeys[i].mask;
  272. if (mask == 0)
  273. if (modifierKeys[i].keysym != 0)
  274. mask = XkbKeysymToModifiers (tqt_xdisplay(), modifierKeys[i].keysym);
  275. else if (!strcmp(modifierKeys[i].name, "Win"))
  276. mask = KKeyNative::modX(KKey::WIN);
  277. else
  278. mask = XkbKeysymToModifiers (tqt_xdisplay(), XK_Mode_switch)
  279. | XkbKeysymToModifiers (tqt_xdisplay(), XK_ISO_Level3_Shift)
  280. | XkbKeysymToModifiers (tqt_xdisplay(), XK_ISO_Level3_Latch)
  281. | XkbKeysymToModifiers (tqt_xdisplay(), XK_ISO_Level3_Lock);
  282. int bit = maskToBit (mask);
  283. if (bit != -1 && keys[bit] == -1)
  284. keys[bit] = i;
  285. }
  286. }
  287. bool KAccessApp::x11EventFilter(XEvent *event)
  288. {
  289. // handle XKB events
  290. if (event->type == xkb_opcode)
  291. {
  292. XkbAnyEvent *ev = (XkbAnyEvent*) event;
  293. switch (ev->xkb_type) {
  294. case XkbStateNotify:
  295. xkbStateNotify();
  296. break;
  297. case XkbBellNotify:
  298. xkbBellNotify((XkbBellNotifyEvent*)event);
  299. break;
  300. case XkbControlsNotify:
  301. xkbControlsNotify((XkbControlsNotifyEvent*)event);
  302. break;
  303. }
  304. return true;
  305. }
  306. // process other events as usual
  307. return TDEApplication::x11EventFilter(event);
  308. }
  309. void VisualBell::paintEvent(TQPaintEvent *event)
  310. {
  311. TQWidget::paintEvent(event);
  312. TQTimer::singleShot(_pause, this, TQT_SLOT(hide()));
  313. }
  314. void KAccessApp::activeWindowChanged(WId wid)
  315. {
  316. _activeWindow = wid;
  317. }
  318. void KAccessApp::xkbStateNotify () {
  319. XkbStateRec state_return;
  320. XkbGetState (tqt_xdisplay(), XkbUseCoreKbd, &state_return);
  321. unsigned char latched = XkbStateMods (&state_return);
  322. unsigned char locked = XkbModLocks (&state_return);
  323. int mods = ((int)locked)<<8 | latched;
  324. if (state != mods) {
  325. if (_kNotifyModifiers)
  326. for (int i = 0; i < 8; i++) {
  327. if (keys[i] != -1) {
  328. if ( (!*modifierKeys[keys[i]].latchedText)
  329. && ( (((mods >> i) & 0x101) != 0) != (((state >> i) & 0x101) != 0) ))
  330. {
  331. if ((mods >> i) & 1) {
  332. KNotifyClient::event (0, "lockkey-locked", i18n(modifierKeys[keys[i]].lockedText));
  333. }
  334. else {
  335. KNotifyClient::event (0, "lockkey-unlocked", i18n(modifierKeys[keys[i]].unlatchedText));
  336. }
  337. }
  338. else if ((*modifierKeys[keys[i]].latchedText)
  339. && ( ((mods >> i) & 0x101) != ((state >> i) & 0x101) ))
  340. {
  341. if ((mods >> i) & 0x100) {
  342. KNotifyClient::event (0, "modifierkey-locked", i18n(modifierKeys[keys[i]].lockedText));
  343. }
  344. else if ((mods >> i) & 1) {
  345. KNotifyClient::event (0, "modifierkey-latched", i18n(modifierKeys[keys[i]].latchedText));
  346. }
  347. else {
  348. KNotifyClient::event (0, "modifierkey-unlatched", i18n(modifierKeys[keys[i]].unlatchedText));
  349. }
  350. }
  351. }
  352. }
  353. state = mods;
  354. }
  355. }
  356. void KAccessApp::xkbBellNotify(XkbBellNotifyEvent *event)
  357. {
  358. // bail out if we should not really ring
  359. if (event->event_only)
  360. return;
  361. // flash the visible bell
  362. if (_visibleBell)
  363. {
  364. // create overlay widget
  365. if (!overlay)
  366. overlay = new VisualBell(_visibleBellPause);
  367. WId id = _activeWindow;
  368. NETRect frame, window;
  369. NETWinInfo net(tqt_xdisplay(), id, desktop()->winId(), 0);
  370. net.kdeGeometry(frame, window);
  371. overlay->setGeometry(window.pos.x, window.pos.y, window.size.width, window.size.height);
  372. if (_visibleBellInvert)
  373. {
  374. TQPixmap screen = TQPixmap::grabWindow(id, 0, 0, window.size.width, window.size.height);
  375. TQPixmap invert(window.size.width, window.size.height);
  376. TQPainter p(&invert);
  377. p.setRasterOp(TQPainter::NotCopyROP);
  378. p.drawPixmap(0, 0, screen);
  379. overlay->setBackgroundPixmap(invert);
  380. }
  381. else
  382. overlay->setBackgroundColor(_visibleBellColor);
  383. // flash the overlay widget
  384. overlay->raise();
  385. overlay->show();
  386. flushX();
  387. }
  388. // ask artsd to ring a nice bell
  389. if (_artsBell && !_artsBellBlocked ) {
  390. KAudioPlayer::play(_artsBellFile);
  391. _artsBellBlocked = true;
  392. artsBellTimer->start( 300, true );
  393. }
  394. }
  395. TQString mouseKeysShortcut (Display *display) {
  396. // Calculate the keycode
  397. KeySym sym = XK_MouseKeys_Enable;
  398. KeyCode code = XKeysymToKeycode(display, sym);
  399. if (code == 0) {
  400. sym = XK_Pointer_EnableKeys;
  401. code = XKeysymToKeycode(display, sym);
  402. if (code == 0)
  403. return ""; // No shortcut available?
  404. }
  405. // Calculate the modifiers by searching the keysym in the X keyboard mapping
  406. XkbDescPtr xkbdesc = XkbGetMap(display, XkbKeyTypesMask | XkbKeySymsMask, XkbUseCoreKbd);
  407. if (!xkbdesc)
  408. return ""; // Failed to obtain the mapping from server
  409. bool found = false;
  410. unsigned char modifiers = 0;
  411. int groups = XkbKeyNumGroups(xkbdesc, code);
  412. for (int grp = 0; grp < groups && !found; grp++)
  413. {
  414. int levels = XkbKeyGroupWidth(xkbdesc, code, grp);
  415. for (int level = 0; level < levels && !found; level++)
  416. {
  417. if (sym == XkbKeySymEntry(xkbdesc, code, level, grp))
  418. {
  419. // keysym found => determine modifiers
  420. int typeIdx = xkbdesc->map->key_sym_map[code].kt_index[grp];
  421. XkbKeyTypePtr type = &(xkbdesc->map->types[typeIdx]);
  422. for (int i = 0; i < type->map_count && !found; i++)
  423. {
  424. if (type->map[i].active && (type->map[i].level == level))
  425. {
  426. modifiers = type->map[i].mods.mask;
  427. found = true;
  428. }
  429. }
  430. }
  431. }
  432. }
  433. XkbFreeClientMap (xkbdesc, 0, true);
  434. if (!found)
  435. return ""; // Somehow the keycode -> keysym mapping is flawed
  436. XEvent ev;
  437. ev.xkey.display = display;
  438. ev.xkey.keycode = code;
  439. ev.xkey.state = 0;
  440. KKey key = KKey(KKeyNative(&ev));
  441. TQString keyname = key.toString();
  442. unsigned int AltMask = KKeyNative::modX(KKey::ALT);
  443. unsigned int WinMask = KKeyNative::modX(KKey::WIN);
  444. unsigned int NumMask = KKeyNative::modXNumLock();
  445. unsigned int ScrollMask= KKeyNative::modXScrollLock();
  446. unsigned int MetaMask = XkbKeysymToModifiers (display, XK_Meta_L);
  447. unsigned int SuperMask = XkbKeysymToModifiers (display, XK_Super_L);
  448. unsigned int HyperMask = XkbKeysymToModifiers (display, XK_Hyper_L);
  449. unsigned int AltGrMask = XkbKeysymToModifiers (display, XK_Mode_switch)
  450. | XkbKeysymToModifiers (display, XK_ISO_Level3_Shift)
  451. | XkbKeysymToModifiers (display, XK_ISO_Level3_Latch)
  452. | XkbKeysymToModifiers (display, XK_ISO_Level3_Lock);
  453. unsigned int mods = ShiftMask | ControlMask | AltMask | WinMask
  454. | LockMask | NumMask | ScrollMask;
  455. AltGrMask &= ~mods;
  456. MetaMask &= ~(mods | AltGrMask);
  457. SuperMask &= ~(mods | AltGrMask | MetaMask);
  458. HyperMask &= ~(mods | AltGrMask | MetaMask | SuperMask);
  459. if ((modifiers & AltGrMask) != 0)
  460. keyname = i18n("AltGraph") + "+" + keyname;
  461. if ((modifiers & HyperMask) != 0)
  462. keyname = i18n("Hyper") + "+" + keyname;
  463. if ((modifiers & SuperMask) != 0)
  464. keyname = i18n("Super") + "+" + keyname;
  465. if ((modifiers & WinMask) != 0)
  466. keyname = i18n("Meta") + "+" + keyname;
  467. if ((modifiers & WinMask) != 0)
  468. keyname = KKey::modFlagLabel(KKey::WIN) + "+" + keyname;
  469. if ((modifiers & AltMask) != 0)
  470. keyname = KKey::modFlagLabel(KKey::ALT) + "+" + keyname;
  471. if ((modifiers & ControlMask) != 0)
  472. keyname = KKey::modFlagLabel(KKey::CTRL) + "+" + keyname;
  473. if ((modifiers & ShiftMask) != 0)
  474. keyname = KKey::modFlagLabel(KKey::SHIFT) + "+" + keyname;
  475. return keyname;
  476. }
  477. void KAccessApp::createDialogContents() {
  478. if (dialog == 0) {
  479. dialog = new KDialogBase(
  480. i18n("Warning"),
  481. KDialogBase::Yes | KDialogBase::No,
  482. KDialogBase::Yes, KDialogBase::Close,
  483. 0, "AccessXWarning", true, true,
  484. KStdGuiItem::cont(), KStdGuiItem::cancel());
  485. TQVBox *topcontents = new TQVBox (dialog);
  486. topcontents->setSpacing(KDialog::spacingHint()*2);
  487. topcontents->setMargin(KDialog::marginHint());
  488. TQWidget *contents = new TQWidget(topcontents);
  489. TQHBoxLayout * lay = new TQHBoxLayout(contents);
  490. lay->setSpacing(KDialog::spacingHint());
  491. TQLabel *label1 = new TQLabel( contents);
  492. TQPixmap pixmap = TDEApplication::kApplication()->iconLoader()->loadIcon("messagebox_warning", TDEIcon::NoGroup, TDEIcon::SizeMedium, TDEIcon::DefaultState, 0, true);
  493. if (pixmap.isNull())
  494. pixmap = TQMessageBox::standardIcon(TQMessageBox::Warning);
  495. label1->setPixmap(pixmap);
  496. lay->addWidget( label1, 0, Qt::AlignCenter );
  497. lay->addSpacing(KDialog::spacingHint());
  498. TQVBoxLayout * vlay = new TQVBoxLayout(lay);
  499. featuresLabel = new TQLabel( "", contents );
  500. featuresLabel->setAlignment( WordBreak|AlignVCenter );
  501. vlay->addWidget( featuresLabel );
  502. vlay->addStretch();
  503. TQHBoxLayout * hlay = new TQHBoxLayout(vlay);
  504. TQLabel *showModeLabel = new TQLabel( i18n("&When a gesture was used:"), contents );
  505. hlay->addWidget( showModeLabel );
  506. showModeCombobox = new KComboBox (contents);
  507. hlay->addWidget( showModeCombobox );
  508. showModeLabel->setBuddy(showModeCombobox);
  509. showModeCombobox->insertItem ( i18n("Change Settings Without Asking"), 0);
  510. showModeCombobox->insertItem ( i18n("Show This Confirmation Dialog"), 1);
  511. showModeCombobox->insertItem ( i18n("Deactivate All AccessX Features & Gestures"), 2);
  512. showModeCombobox->setCurrentItem (1);
  513. dialog->setMainWidget(topcontents);
  514. dialog->enableButtonSeparator(false);
  515. connect (dialog, TQT_SIGNAL(yesClicked()), this, TQT_SLOT(yesClicked()));
  516. connect (dialog, TQT_SIGNAL(noClicked()), this, TQT_SLOT(noClicked()));
  517. connect (dialog, TQT_SIGNAL(closeClicked()), this, TQT_SLOT(dialogClosed()));
  518. }
  519. }
  520. void KAccessApp::xkbControlsNotify(XkbControlsNotifyEvent *event)
  521. {
  522. unsigned int newFeatures = event->enabled_ctrls & (XkbSlowKeysMask | XkbBounceKeysMask | XkbStickyKeysMask | XkbMouseKeysMask);
  523. if (newFeatures != features) {
  524. unsigned int enabled = newFeatures & ~features;
  525. unsigned int disabled = features & ~newFeatures;
  526. if (!_gestureConfirmation) {
  527. requestedFeatures = enabled | (requestedFeatures & ~disabled);
  528. notifyChanges();
  529. features = newFeatures;
  530. }
  531. else {
  532. // set the AccessX features back to what they were. We will
  533. // apply the changes later if the user allows us to do that.
  534. readSettings();
  535. requestedFeatures = enabled | (requestedFeatures & ~disabled);
  536. enabled = requestedFeatures & ~features;
  537. disabled = features & ~requestedFeatures;
  538. TQStringList enabledFeatures;
  539. TQStringList disabledFeatures;
  540. if (enabled & XkbStickyKeysMask)
  541. enabledFeatures << i18n("Sticky keys");
  542. else if (disabled & XkbStickyKeysMask)
  543. disabledFeatures << i18n("Sticky keys");
  544. if (enabled & XkbSlowKeysMask)
  545. enabledFeatures << i18n("Slow keys");
  546. else if (disabled & XkbSlowKeysMask)
  547. disabledFeatures << i18n("Slow keys");
  548. if (enabled & XkbBounceKeysMask)
  549. enabledFeatures << i18n("Bounce keys");
  550. else if (disabled & XkbBounceKeysMask)
  551. disabledFeatures << i18n("Bounce keys");
  552. if (enabled & XkbMouseKeysMask)
  553. enabledFeatures << i18n("Mouse keys");
  554. else if (disabled & XkbMouseKeysMask)
  555. disabledFeatures << i18n("Mouse keys");
  556. TQString question;
  557. switch (enabledFeatures.count()) {
  558. case 0: switch (disabledFeatures.count()) {
  559. case 1: question = i18n("Do you really want to deactivate \"%1\"?")
  560. .arg(disabledFeatures[0]);
  561. break;
  562. case 2: question = i18n("Do you really want to deactivate \"%1\" and \"%2\"?")
  563. .arg(disabledFeatures[0]).arg(disabledFeatures[1]);
  564. break;
  565. case 3: question = i18n("Do you really want to deactivate \"%1\", \"%2\" and \"%3\"?")
  566. .arg(disabledFeatures[0]).arg(disabledFeatures[1])
  567. .arg(disabledFeatures[2]);
  568. break;
  569. case 4: question = i18n("Do you really want to deactivate \"%1\", \"%2\", \"%3\" and \"%4\"?")
  570. .arg(disabledFeatures[0]).arg(disabledFeatures[1])
  571. .arg(disabledFeatures[2]).arg(disabledFeatures[3]);
  572. break;
  573. }
  574. break;
  575. case 1: switch (disabledFeatures.count()) {
  576. case 0: question = i18n("Do you really want to activate \"%1\"?")
  577. .arg(enabledFeatures[0]);
  578. break;
  579. case 1: question = i18n("Do you really want to activate \"%1\" and to deactivate \"%2\"?")
  580. .arg(enabledFeatures[0]).arg(disabledFeatures[0]);
  581. break;
  582. case 2: question = i18n("Do you really want to activate \"%1\" and to deactivate \"%2\" and \"%3\"?")
  583. .arg(enabledFeatures[0]).arg(disabledFeatures[0])
  584. .arg(disabledFeatures[1]);
  585. break;
  586. case 3: question = i18n("Do you really want to activate \"%1\" and to deactivate \"%2\", \"%3\" and \"%4\"?")
  587. .arg(enabledFeatures[0]).arg(disabledFeatures[0])
  588. .arg(disabledFeatures[1]).arg(disabledFeatures[2]);
  589. break;
  590. }
  591. break;
  592. case 2: switch (disabledFeatures.count()) {
  593. case 0: question = i18n("Do you really want to activate \"%1\" and \"%2\"?")
  594. .arg(enabledFeatures[0]).arg(enabledFeatures[1]);
  595. break;
  596. case 1: question = i18n("Do you really want to activate \"%1\" and \"%2\" and to deactivate \"%3\"?")
  597. .arg(enabledFeatures[0]).arg(enabledFeatures[1])
  598. .arg(disabledFeatures[0]);
  599. break;
  600. case 2: question = i18n("Do you really want to activate \"%1\", and \"%2\" and to deactivate \"%3\" and \"%4\"?")
  601. .arg(enabledFeatures[0]).arg(enabledFeatures[1])
  602. .arg(enabledFeatures[0]).arg(disabledFeatures[1]);
  603. break;
  604. }
  605. break;
  606. case 3: switch (disabledFeatures.count()) {
  607. case 0: question = i18n("Do you really want to activate \"%1\", \"%2\" and \"%3\"?")
  608. .arg(enabledFeatures[0]).arg(enabledFeatures[1])
  609. .arg(enabledFeatures[2]);
  610. break;
  611. case 1: question = i18n("Do you really want to activate \"%1\", \"%2\" and \"%3\" and to deactivate \"%4\"?")
  612. .arg(enabledFeatures[0]).arg(enabledFeatures[1])
  613. .arg(enabledFeatures[2]).arg(disabledFeatures[0]);
  614. break;
  615. }
  616. break;
  617. case 4: question = i18n("Do you really want to activate \"%1\", \"%2\", \"%3\" and \"%4\"?")
  618. .arg(enabledFeatures[0]).arg(enabledFeatures[1])
  619. .arg(enabledFeatures[2]).arg(enabledFeatures[3]);
  620. break;
  621. }
  622. TQString explanation;
  623. if (enabledFeatures.count()+disabledFeatures.count() == 1) {
  624. explanation = i18n("An application has requested to change this setting.");
  625. if (_gestures) {
  626. if ((enabled | disabled) == XkbSlowKeysMask)
  627. explanation = i18n("You held down the Shift key for 8 seconds or an application has requested to change this setting.");
  628. else if ((enabled | disabled) == XkbStickyKeysMask)
  629. explanation = i18n("You pressed the Shift key 5 consecutive times or an application has requested to change this setting.");
  630. else if ((enabled | disabled) == XkbMouseKeysMask) {
  631. TQString shortcut = mouseKeysShortcut(tqt_xdisplay());
  632. if (!shortcut.isEmpty() && !shortcut.isNull())
  633. explanation = i18n("You pressed %1 or an application has requested to change this setting.").arg(shortcut);
  634. }
  635. }
  636. }
  637. else {
  638. if (_gestures)
  639. explanation = i18n("An application has requested to change these settings, or you used a combination of several keyboard gestures.");
  640. else
  641. explanation = i18n("An application has requested to change these settings.");
  642. }
  643. createDialogContents();
  644. featuresLabel->setText ( question+"\n\n"+explanation
  645. +" "+i18n("These AccessX settings are needed for some users with motion impairments and can be configured in the Trinity 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\".") );
  646. KWin::setState( dialog->winId(), NET::KeepAbove );
  647. kapp->updateUserTimestamp();
  648. dialog->show();
  649. }
  650. }
  651. }
  652. void KAccessApp::notifyChanges() {
  653. if (!_kNotifyAccessX)
  654. return;
  655. unsigned int enabled = requestedFeatures & ~features;
  656. unsigned int disabled = features & ~requestedFeatures;
  657. if (enabled & XkbSlowKeysMask)
  658. KNotifyClient::event (0, "slowkeys", i18n("Slow keys has been enabled. From now on, you need to press each key for a certain length of time before it is accepted."));
  659. else if (disabled & XkbSlowKeysMask)
  660. KNotifyClient::event (0, "slowkeys", i18n("Slow keys has been disabled."));
  661. if (enabled & XkbBounceKeysMask)
  662. KNotifyClient::event (0, "bouncekeys", i18n("Bounce keys has been enabled. From now on, each key will be blocked for a certain length of time after it is used."));
  663. else if (disabled & XkbBounceKeysMask)
  664. KNotifyClient::event (0, "bouncekeys", i18n("Bounce keys has been disabled."));
  665. if (enabled & XkbStickyKeysMask)
  666. KNotifyClient::event (0, "stickykeys", i18n("Sticky keys has been enabled. From now on, modifier keys will stay latched after you have released them."));
  667. else if (disabled & XkbStickyKeysMask)
  668. KNotifyClient::event (0, "stickykeys", i18n("Sticky keys has been disabled."));
  669. if (enabled & XkbMouseKeysMask)
  670. KNotifyClient::event (0, "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."));
  671. else if (disabled & XkbMouseKeysMask)
  672. KNotifyClient::event (0, "mousekeys", i18n("Mouse keys has been disabled."));
  673. }
  674. void KAccessApp::applyChanges() {
  675. notifyChanges();
  676. unsigned int enabled = requestedFeatures & ~features;
  677. unsigned int disabled = features & ~requestedFeatures;
  678. TDEConfig *config = TDEGlobal::config();
  679. config->setGroup("Keyboard");
  680. if (enabled & XkbSlowKeysMask)
  681. config->writeEntry("SlowKeys", true);
  682. else if (disabled & XkbSlowKeysMask)
  683. config->writeEntry("SlowKeys", false);
  684. if (enabled & XkbBounceKeysMask)
  685. config->writeEntry("BounceKeys", true);
  686. else if (disabled & XkbBounceKeysMask)
  687. config->writeEntry("BounceKeys", false);
  688. if (enabled & XkbStickyKeysMask)
  689. config->writeEntry("StickyKeys", true);
  690. else if (disabled & XkbStickyKeysMask)
  691. config->writeEntry("StickyKeys", false);
  692. config->setGroup("Mouse");
  693. if (enabled & XkbMouseKeysMask)
  694. config->writeEntry("MouseKeys", true);
  695. else if (disabled & XkbMouseKeysMask)
  696. config->writeEntry("MouseKeys", false);
  697. config->sync();
  698. }
  699. void KAccessApp::yesClicked() {
  700. if (dialog != 0)
  701. dialog->deleteLater();
  702. dialog = 0;
  703. TDEConfig *config = TDEGlobal::config();
  704. config->setGroup("Keyboard");
  705. switch (showModeCombobox->currentItem()) {
  706. case 0:
  707. config->writeEntry("Gestures", true);
  708. config->writeEntry("GestureConfirmation", false);
  709. break;
  710. default:
  711. config->writeEntry("Gestures", true);
  712. config->writeEntry("GestureConfirmation", true);
  713. break;
  714. case 2:
  715. requestedFeatures = 0;
  716. config->writeEntry("Gestures", false);
  717. config->writeEntry("GestureConfirmation", false);
  718. }
  719. config->sync();
  720. if (features != requestedFeatures) {
  721. notifyChanges();
  722. applyChanges();
  723. }
  724. readSettings();
  725. }
  726. void KAccessApp::noClicked() {
  727. if (dialog != 0)
  728. dialog->deleteLater();
  729. dialog = 0;
  730. requestedFeatures = features;
  731. TDEConfig *config = TDEGlobal::config();
  732. config->setGroup("Keyboard");
  733. switch (showModeCombobox->currentItem()) {
  734. case 0:
  735. config->writeEntry("Gestures", true);
  736. config->writeEntry("GestureConfirmation", false);
  737. break;
  738. default:
  739. config->writeEntry("Gestures", true);
  740. config->writeEntry("GestureConfirmation", true);
  741. break;
  742. case 2:
  743. requestedFeatures = 0;
  744. config->writeEntry("Gestures", false);
  745. config->writeEntry("GestureConfirmation", true);
  746. }
  747. config->sync();
  748. if (features != requestedFeatures)
  749. applyChanges();
  750. readSettings();
  751. }
  752. void KAccessApp::dialogClosed() {
  753. if (dialog != 0)
  754. dialog->deleteLater();
  755. dialog = 0;
  756. requestedFeatures = features;
  757. }
  758. void KAccessApp::slotArtsBellTimeout()
  759. {
  760. _artsBellBlocked = false;
  761. }
  762. void KAccessApp::setXkbOpcode(int opcode)
  763. {
  764. xkb_opcode = opcode;
  765. }