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>
35 #include <KButtonGroup>
39 #include <knuminput.h>
40 #include <kapplication.h>
42 #include <kstandarddirs.h>
45 #include <KPluginFactory>
46 #include <KPluginLoader>
49 #include "ui_kcmmiscwidget.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
)
61 // QBoxLayout* lay = new QVBoxLayout(this, 0, KDialog::spacingHint());
62 ui
= new Ui_KeyboardConfigWidget();
64 // lay->addWidget(ui);
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 );
95 #if !defined(HAVE_XKB) && !defined(HAVE_XF86MISC)
96 // delay->setDisabled( true );
97 // rate->setDisabled( true );
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();
128 void KeyboardConfig::setNumLockState( int s
)
130 ui
->numlockGroup
->setSelected( s
);
133 void KeyboardConfig::load()
135 KConfigGroup
config(KSharedConfig::openConfig("kcminputrc", KConfig::NoGlobals
), "Keyboard");
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
,
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
);
188 void KeyboardConfig::defaults()
191 setRepeat(true, 660, 25);
192 setNumLockState( 2 );
193 emit
KCModule::changed(true);
196 QString
KeyboardConfig::quickHelp() const
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
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>
274 #include <X11/extensions/XTest.h>
278 #define explicit myexplicit
279 #include <X11/XKBlib.h>
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> */
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
)
302 if( !xkb
|| !xkb
->names
)
305 i
< XkbNumVirtualMods
;
308 char* modStr
= XGetAtomName( xkb
->dpy
, xkb
->names
->vmods
[i
] );
309 if( modStr
!= NULL
&& strcmp(name
, modStr
) == 0 )
312 XkbVirtualModsToReal( xkb
, 1 << i
, &mask
);
319 unsigned int xkb_numlock_mask()
322 if(( xkb
= XkbGetKeyboard( QX11Info::display(), XkbAllComponentsMask
, XkbUseCoreKbd
)) != NULL
)
324 unsigned int mask
= xkb_mask_modifier( xkb
, "NumLock" );
325 XkbFreeKeyboard( xkb
, 0, True
);
336 mask
= xkb_numlock_mask();
339 XkbLockModifiers ( QX11Info::display(), XkbUseCoreKbd
, mask
, mask
);
348 mask
= xkb_numlock_mask();
351 XkbLockModifiers ( QX11Info::display(), XkbUseCoreKbd
, mask
, 0);
357 int xtest_get_numlock_state()
360 int numlock_mask
= 0;
361 Window dummy1
, dummy2
;
362 int dummy3
, dummy4
, dummy5
, dummy6
;
364 KeyCode numlock_keycode
= XKeysymToKeycode( QX11Info::display(), XK_Num_Lock
);
365 if( numlock_keycode
== NoSymbol
)
367 XModifierKeymap
* map
= XGetModifierMapping( QX11Info::display() );
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
);
389 if( !xtest_get_numlock_state())
390 xtest_change_numlock();
395 if( xtest_get_numlock_state())
396 xtest_change_numlock();
400 void numlock_set_on()
411 void numlock_set_off()
422 void numlockx_change_numlock_state( bool set_P
)
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/)
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
;
448 XF86MiscSetKbdSettings(dpy
, &values
);
452 void set_repeatrate(int delay
, double rate
)
455 Display
* dpy
= QX11Info::display();
456 int xkbmajor
= XkbMajorVersion
, xkbminor
= XkbMinorVersion
;
457 int xkbopcode
, xkbevent
, xkberror
;
459 if (XkbQueryExtension(dpy
, &xkbopcode
, &xkbevent
, &xkberror
, &xkbmajor
,
461 XkbDescPtr xkb
= XkbAllocKeyboard();
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
);
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)
481 r
= (int)floor(rate
+ 0.5);
483 QString exe
= KGlobal::dirs()->findExe("xset");
488 p
<< exe
<< "r" << "rate" << QString::number(delay
) << QString::number(r
);
493 void KeyboardConfig::init_keyboard()
495 KConfigGroup
config(KSharedConfig::openConfig( "kcminputrc" ), "Keyboard");
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
,
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 );
524 KDE_EXPORT
void kcminit_keyboard()
526 KeyboardConfig::init_keyboard();
530 #include "kcmmisc.moc"