not quite so much needs to be delayed to the init() function
[personal-kdebase.git] / workspace / kcontrol / keyboard / kcmmisc.cpp
blob07ed16ca723eac806b00cd49bb100af84d893dc9
1 /*
2 * kcmmisc.cpp
4 * Copyright (c) 1997 Patrick Dowler dowler@morgul.fsh.uvic.ca
6 * Layout management, cleanups:
7 * Copyright (c) 1999 Dirk A. Mueller <dmuell@gmx.net>
9 * Requires the Qt widget libraries, available at no cost at
10 * http://www.troll.no/
12 * This program is free software; you can redistribute it and/or modify
13 * it under the terms of the GNU General Public License as published by
14 * the Free Software Foundation; either version 2 of the License, or
15 * (at your option) any later version.
17 * This program is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU General Public License for more details.
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, write to the Free Software
24 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
28 #include <config-workspace.h>
29 #include <config-X11.h>
30 #include <math.h>
32 #include <QCheckBox>
34 #include <QWhatsThis>
35 #include <KButtonGroup>
37 #include <klocale.h>
38 #include <kconfig.h>
39 #include <knuminput.h>
40 #include <kapplication.h>
41 #include <kglobal.h>
42 #include <kstandarddirs.h>
43 #include <kprocess.h>
44 #include <kdialog.h>
45 #include <KPluginFactory>
46 #include <KPluginLoader>
48 #include "kcmmisc.h"
49 #include "ui_kcmmiscwidget.h"
50 #include <X11/Xlib.h>
52 K_PLUGIN_FACTORY(KeyboardConfigFactory,
53 registerPlugin<KeyboardConfig>("keyboard");
55 K_EXPORT_PLUGIN(KeyboardConfigFactory("kcmkeyboard"))
57 KeyboardConfig::KeyboardConfig(QWidget *parent, const QVariantList &)
58 : KCModule(KeyboardConfigFactory::componentData(), parent)
60 QString wtstr;
61 // QBoxLayout* lay = new QVBoxLayout(this, 0, KDialog::spacingHint());
62 ui = new Ui_KeyboardConfigWidget();
63 ui->setupUi(this);
64 // lay->addWidget(ui);
65 // lay->addStretch();
67 ui->click->setRange(0, 100, 10);
68 ui->delay->setRange(100, 5000, 50);
69 ui->delay->setSliderEnabled(false);
70 ui->rate->setRange(0.2, 50, 5, false);
72 sliderMax = (int)floor (0.5 + 2*(log(5000.0L)-log(100.0L)) / (log(5000.0L)-log(4999.0L)));
73 ui->delaySlider->setRange(0, sliderMax);
74 ui->delaySlider->setSingleStep(sliderMax/100);
75 ui->delaySlider->setPageStep(sliderMax/10);
76 ui->delaySlider->setTickInterval(sliderMax/10);
78 ui->rateSlider->setRange(20, 5000);
79 ui->rateSlider->setSingleStep(30);
80 ui->rateSlider->setPageStep(500);
81 ui->rateSlider->setTickInterval(498);
83 connect(ui->repeatBox, SIGNAL(clicked()), this, SLOT(changed()));
84 connect(ui->delay, SIGNAL(valueChanged(int)), this, SLOT(delaySpinboxChanged(int)));
85 connect(ui->delaySlider, SIGNAL(valueChanged(int)), this, SLOT(delaySliderChanged(int)));
86 connect(ui->rate, SIGNAL(valueChanged(double)), this, SLOT(rateSpinboxChanged(double)));
87 connect(ui->rateSlider, SIGNAL(valueChanged(int)), this, SLOT(rateSliderChanged(int)));
89 connect(ui->click, SIGNAL(valueChanged(int)), this, SLOT(changed()));
90 connect(ui->numlockGroup, SIGNAL(released(int)), this, SLOT(changed()));
92 #if !defined(HAVE_XTEST) && !defined(HAVE_XKB)
93 ui->numlockGroup->setDisabled( true );
94 #endif
95 #if !defined(HAVE_XKB) && !defined(HAVE_XF86MISC)
96 // delay->setDisabled( true );
97 // rate->setDisabled( true );
98 #endif
99 // lay->addStretch();
102 int KeyboardConfig::getClick()
104 return ui->click->value();
107 // set the slider and LCD values
108 void KeyboardConfig::setRepeat(int r, int delay_, double rate_)
110 ui->repeatBox->setChecked(r == AutoRepeatModeOn);
111 ui->delay->setValue(delay_);
112 ui->rate->setValue(rate_);
115 void KeyboardConfig::setClick(int v)
117 ui->click->setValue(v);
120 int KeyboardConfig::getNumLockState()
122 int selected = ui->numlockGroup->selected();
123 if( selected < 0 )
124 return 2;
125 return selected;
128 void KeyboardConfig::setNumLockState( int s )
130 ui->numlockGroup->setSelected( s );
133 void KeyboardConfig::load()
135 KConfigGroup config(KSharedConfig::openConfig("kcminputrc", KConfig::NoGlobals), "Keyboard");
137 XKeyboardState kbd;
139 XGetKeyboardControl(QX11Info::display(), &kbd);
141 ui->delay->blockSignals(true);
142 ui->rate->blockSignals(true);
143 ui->click->blockSignals(true);
145 bool key = config.readEntry("KeyboardRepeating", true);
146 keyboardRepeat = (key ? AutoRepeatModeOn : AutoRepeatModeOff);
147 ui->delay->setValue(config.readEntry( "RepeatDelay", 660 ));
148 ui->rate->setValue(config.readEntry( "RepeatRate", 25. ));
149 clickVolume = config.readEntry("ClickVolume", kbd.key_click_percent);
150 numlockState = config.readEntry( "NumLock", 2 );
152 setClick(kbd.key_click_percent);
153 setRepeat(kbd.global_auto_repeat, ui->delay->value(), ui->rate->value());
154 setNumLockState( numlockState );
156 ui->delay->blockSignals(false);
157 ui->rate->blockSignals(false);
158 ui->click->blockSignals(false);
161 void KeyboardConfig::save()
163 KConfigGroup config(KSharedConfig::openConfig("kcminputrc", KConfig::NoGlobals), "Keyboard");
165 XKeyboardControl kbd;
167 clickVolume = getClick();
168 keyboardRepeat = ui->repeatBox->isChecked() ? AutoRepeatModeOn : AutoRepeatModeOff;
169 numlockState = getNumLockState();
171 kbd.key_click_percent = clickVolume;
172 kbd.auto_repeat_mode = keyboardRepeat;
173 XChangeKeyboardControl(QX11Info::display(),
174 KBKeyClickPercent | KBAutoRepeatMode,
175 &kbd);
176 if( keyboardRepeat ) {
177 set_repeatrate(ui->delay->value(), ui->rate->value());
180 config.writeEntry("ClickVolume",clickVolume);
181 config.writeEntry("KeyboardRepeating", (keyboardRepeat == AutoRepeatModeOn));
182 config.writeEntry("RepeatRate", ui->rate->value() );
183 config.writeEntry("RepeatDelay", ui->delay->value() );
184 config.writeEntry("NumLock", numlockState );
185 config.sync();
188 void KeyboardConfig::defaults()
190 setClick(50);
191 setRepeat(true, 660, 25);
192 setNumLockState( 2 );
193 emit KCModule::changed(true);
196 QString KeyboardConfig::quickHelp() const
198 return QString();
200 /* "<h1>Keyboard</h1> This module allows you to choose options"
201 " for the way in which your keyboard works. The actual effect of"
202 " setting these options depends upon the features provided by your"
203 " keyboard hardware and the X server on which KDE is running.<p>"
204 " For example, you may find that changing the key click volume"
205 " has no effect because this feature is not available on your system." */
208 void KeyboardConfig::delaySliderChanged (int value) {
209 double alpha = sliderMax / (log(5000.0L) - log(100.0L));
210 double linearValue = exp (value/alpha + log(100.0L));
212 ui->delay->setValue((int)floor(0.5 + linearValue));
214 emit KCModule::changed(true);
217 void KeyboardConfig::delaySpinboxChanged (int value) {
218 double alpha = sliderMax / (log(5000.0L) - log(100.0L));
219 double logVal = alpha * (log((double)value)-log(100.0L));
221 ui->delaySlider->setValue ((int)floor (0.5 + logVal));
223 emit KCModule::changed(true);
226 void KeyboardConfig::rateSliderChanged (int value) {
227 ui->rate->setValue(value/100.0);
229 emit KCModule::changed(true);
232 void KeyboardConfig::rateSpinboxChanged (double value) {
233 ui->rateSlider->setValue ((int)(value*100));
235 emit KCModule::changed(true);
238 void KeyboardConfig::changed()
240 emit KCModule::changed(true);
244 Originally comes from NumLockX http://dforce.sh.cvut.cz/~seli/en/numlockx
246 NumLockX
248 Copyright (C) 2000-2001 Lubos Lunak <l.lunak@kde.org>
249 Copyright (C) 2001 Oswald Buddenhagen <ossi@kde.org>
251 Permission is hereby granted, free of charge, to any person obtaining a
252 copy of this software and associated documentation files (the "Software"),
253 to deal in the Software without restriction, including without limitation
254 the rights to use, copy, modify, merge, publish, distribute, sublicense,
255 and/or sell copies of the Software, and to permit persons to whom the
256 Software is furnished to do so, subject to the following conditions:
258 The above copyright notice and this permission notice shall be included in
259 all copies or substantial portions of the Software.
261 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
262 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
263 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
264 THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
265 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
266 FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
267 DEALINGS IN THE SOFTWARE.
269 ****************************************************************************/
271 #include <X11/Xlib.h>
273 #ifdef HAVE_XTEST
274 #include <X11/extensions/XTest.h>
275 #endif
277 #ifdef HAVE_XKB
278 #define explicit myexplicit
279 #include <X11/XKBlib.h>
280 #undef explicit
281 #endif
283 #include <X11/keysym.h>
285 #if defined(HAVE_XTEST) || defined(HAVE_XKB)
287 /* the XKB stuff is based on code created by Oswald Buddenhagen <ossi@kde.org> */
288 #ifdef HAVE_XKB
289 int xkb_init()
291 int xkb_opcode, xkb_event, xkb_error;
292 int xkb_lmaj = XkbMajorVersion;
293 int xkb_lmin = XkbMinorVersion;
294 return XkbLibraryVersion( &xkb_lmaj, &xkb_lmin )
295 && XkbQueryExtension( QX11Info::display(), &xkb_opcode, &xkb_event, &xkb_error,
296 &xkb_lmaj, &xkb_lmin );
299 unsigned int xkb_mask_modifier( XkbDescPtr xkb, const char *name )
301 int i;
302 if( !xkb || !xkb->names )
303 return 0;
304 for( i = 0;
305 i < XkbNumVirtualMods;
306 i++ )
308 char* modStr = XGetAtomName( xkb->dpy, xkb->names->vmods[i] );
309 if( modStr != NULL && strcmp(name, modStr) == 0 )
311 unsigned int mask;
312 XkbVirtualModsToReal( xkb, 1 << i, &mask );
313 return mask;
316 return 0;
319 unsigned int xkb_numlock_mask()
321 XkbDescPtr xkb;
322 if(( xkb = XkbGetKeyboard( QX11Info::display(), XkbAllComponentsMask, XkbUseCoreKbd )) != NULL )
324 unsigned int mask = xkb_mask_modifier( xkb, "NumLock" );
325 XkbFreeKeyboard( xkb, 0, True );
326 return mask;
328 return 0;
331 int xkb_set_on()
333 unsigned int mask;
334 if( !xkb_init())
335 return 0;
336 mask = xkb_numlock_mask();
337 if( mask == 0 )
338 return 0;
339 XkbLockModifiers ( QX11Info::display(), XkbUseCoreKbd, mask, mask);
340 return 1;
343 int xkb_set_off()
345 unsigned int mask;
346 if( !xkb_init())
347 return 0;
348 mask = xkb_numlock_mask();
349 if( mask == 0 )
350 return 0;
351 XkbLockModifiers ( QX11Info::display(), XkbUseCoreKbd, mask, 0);
352 return 1;
354 #endif
356 #ifdef HAVE_XTEST
357 int xtest_get_numlock_state()
359 int i;
360 int numlock_mask = 0;
361 Window dummy1, dummy2;
362 int dummy3, dummy4, dummy5, dummy6;
363 unsigned int mask;
364 KeyCode numlock_keycode = XKeysymToKeycode( QX11Info::display(), XK_Num_Lock );
365 if( numlock_keycode == NoSymbol )
366 return 0;
367 XModifierKeymap* map = XGetModifierMapping( QX11Info::display() );
368 for( i = 0;
369 i < 8;
370 ++i )
372 if( map->modifiermap[ map->max_keypermod * i ] == numlock_keycode )
373 numlock_mask = 1 << i;
375 XQueryPointer( QX11Info::display(), DefaultRootWindow( QX11Info::display() ), &dummy1, &dummy2,
376 &dummy3, &dummy4, &dummy5, &dummy6, &mask );
377 XFreeModifiermap( map );
378 return mask & numlock_mask;
381 void xtest_change_numlock()
383 XTestFakeKeyEvent( QX11Info::display(), XKeysymToKeycode( QX11Info::display(), XK_Num_Lock ), True, CurrentTime );
384 XTestFakeKeyEvent( QX11Info::display(), XKeysymToKeycode( QX11Info::display(), XK_Num_Lock ), False, CurrentTime );
387 void xtest_set_on()
389 if( !xtest_get_numlock_state())
390 xtest_change_numlock();
393 void xtest_set_off()
395 if( xtest_get_numlock_state())
396 xtest_change_numlock();
398 #endif
400 void numlock_set_on()
402 #ifdef HAVE_XKB
403 if( xkb_set_on())
404 return;
405 #endif
406 #ifdef HAVE_XTEST
407 xtest_set_on();
408 #endif
411 void numlock_set_off()
413 #ifdef HAVE_XKB
414 if( xkb_set_off())
415 return;
416 #endif
417 #ifdef HAVE_XTEST
418 xtest_set_off();
419 #endif
422 void numlockx_change_numlock_state( bool set_P )
424 if( set_P )
425 numlock_set_on();
426 else
427 numlock_set_off();
429 #else
430 void numlockx_change_numlock_state( bool ) {} // dummy
431 #endif // defined(HAVE_XTEST) || defined(HAVE_XKB)
434 // This code is taken from xset utility from XFree 4.3 (http://www.xfree86.org/)
437 #if 0
438 //HAVE_XF86MISC
439 #include <X11/extensions/xf86misc.h>
440 void set_repeatrate(int delay, double rate)
442 Display* dpy = QX11Info::display();
443 XF86MiscKbdSettings values;
445 XF86MiscGetKbdSettings(dpy, &values);
446 values.delay = delay;
447 values.rate = rate;
448 XF86MiscSetKbdSettings(dpy, &values);
449 return;
451 #else
452 void set_repeatrate(int delay, double rate)
454 #if HAVE_XKB
455 Display* dpy = QX11Info::display();
456 int xkbmajor = XkbMajorVersion, xkbminor = XkbMinorVersion;
457 int xkbopcode, xkbevent, xkberror;
459 if (XkbQueryExtension(dpy, &xkbopcode, &xkbevent, &xkberror, &xkbmajor,
460 &xkbminor)) {
461 XkbDescPtr xkb = XkbAllocKeyboard();
462 if (xkb) {
463 int res = XkbGetControls(dpy, XkbRepeatKeysMask, xkb);
464 xkb->ctrls->repeat_delay = delay;
465 xkb->ctrls->repeat_interval = (int)floor(1000/rate + 0.5);
466 res = XkbSetControls(dpy, XkbRepeatKeysMask, xkb);
467 return;
470 #endif
471 // Fallback: use the xset utility.
473 // Unfortunately xset does only support int parameters, so
474 // really slow repeat rates cannot be supported this way.
475 // (the FSG Accessibility standard requires support for repeat rates
476 // of several seconds per character)
477 int r;
478 if (rate < 1)
479 r = 1;
480 else
481 r = (int)floor(rate + 0.5);
483 QString exe = KGlobal::dirs()->findExe("xset");
484 if (exe.isEmpty())
485 return;
487 KProcess p;
488 p << exe << "r" << "rate" << QString::number(delay) << QString::number(r);
489 p.execute();
491 #endif
493 void KeyboardConfig::init_keyboard()
495 KConfigGroup config(KSharedConfig::openConfig( "kcminputrc" ), "Keyboard");
497 XKeyboardState kbd;
498 XKeyboardControl kbdc;
500 XGetKeyboardControl(QX11Info::display(), &kbd);
501 bool key = config.readEntry("KeyboardRepeating", true);
502 kbdc.key_click_percent = config.readEntry("ClickVolume", kbd.key_click_percent);
503 kbdc.auto_repeat_mode = (key ? AutoRepeatModeOn : AutoRepeatModeOff);
505 XChangeKeyboardControl(QX11Info::display(),
506 KBKeyClickPercent | KBAutoRepeatMode,
507 &kbdc);
509 if( key ) {
510 int delay_ = config.readEntry("RepeatDelay", 250);
511 double rate_ = config.readEntry("RepeatRate", 30.);
512 set_repeatrate(delay_, rate_);
516 int numlockState = config.readEntry( "NumLock", 2 );
517 if( numlockState != 2 )
518 numlockx_change_numlock_state( numlockState == 0 );
522 extern "C"
524 KDE_EXPORT void kcminit_keyboard()
526 KeyboardConfig::init_keyboard();
530 #include "kcmmisc.moc"