~ubuntu-branches/ubuntu/gutsy/kdebase-workspace/gutsy-backports

« back to all changes in this revision

Viewing changes to kcontrol/keyboard/kcmmisc.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Jonathan Riddell
  • Date: 2007-10-31 19:16:54 UTC
  • Revision ID: james.westby@ubuntu.com-20071031191654-xuof6e1jg6uxqaze
Tags: 3.95.0-0ubuntu1~gutsy1
New upstream release

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * kcmmisc.cpp
 
3
 *
 
4
 * Copyright (c) 1997 Patrick Dowler dowler@morgul.fsh.uvic.ca
 
5
 *
 
6
 * Layout management, cleanups:
 
7
 * Copyright (c) 1999 Dirk A. Mueller <dmuell@gmx.net>
 
8
 *
 
9
 * Requires the Qt widget libraries, available at no cost at
 
10
 * http://www.troll.no/
 
11
 *
 
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.
 
16
 *
 
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.
 
21
 *
 
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.
 
25
 */
 
26
 
 
27
 
 
28
#include <config-workspace.h>
 
29
#include <config-X11.h>
 
30
#include <math.h>
 
31
 
 
32
#include <QSlider>
 
33
#include <QFileInfo>
 
34
#include <QCheckBox>
 
35
 
 
36
#include <QLayout>
 
37
#include <QWhatsThis>
 
38
#include <KButtonGroup>
 
39
#include <QRadioButton>
 
40
 
 
41
#include <klocale.h>
 
42
#include <kconfig.h>
 
43
#include <knuminput.h>
 
44
#include <kapplication.h>
 
45
#include <kglobal.h>
 
46
#include <kstandarddirs.h>
 
47
#include <kprocess.h>
 
48
#include <kdialog.h>
 
49
#include <KPluginFactory>
 
50
#include <KPluginLoader>
 
51
 
 
52
#include "kcmmisc.h"
 
53
#include "ui_kcmmiscwidget.h"
 
54
#include <X11/Xlib.h>
 
55
 
 
56
K_PLUGIN_FACTORY(KeyboardConfigFactory,
 
57
        registerPlugin<KeyboardConfig>("keyboard");
 
58
        )
 
59
K_EXPORT_PLUGIN(KeyboardConfigFactory("kcmmisc")) // Messages.sh extracts into kxkb.pot
 
60
 
 
61
KeyboardConfig::KeyboardConfig(QWidget *parent, const QVariantList &)
 
62
        : KCModule(KeyboardConfigFactory::componentData(), parent)
 
63
{
 
64
  QString wtstr;
 
65
//   QBoxLayout* lay = new QVBoxLayout(this, 0, KDialog::spacingHint());
 
66
  ui = new Ui_KeyboardConfigWidget();
 
67
  ui->setupUi(this);
 
68
//   lay->addWidget(ui);
 
69
//   lay->addStretch();
 
70
 
 
71
  ui->click->setRange(0, 100, 10);
 
72
  ui->delay->setRange(100, 5000, 50, false);
 
73
  ui->rate->setRange(0.2, 50, 5, false);
 
74
 
 
75
  sliderMax = (int)floor (0.5 + 2*(log(5000)-log(100)) / (log(5000)-log(4999)));
 
76
  ui->delaySlider->setRange(0, sliderMax);
 
77
  ui->delaySlider->setSingleStep(sliderMax/100);
 
78
  ui->delaySlider->setPageStep(sliderMax/10);
 
79
  ui->delaySlider->setTickInterval(sliderMax/10);
 
80
 
 
81
  ui->rateSlider->setRange(20, 5000);
 
82
  ui->rateSlider->setSingleStep(30);
 
83
  ui->rateSlider->setPageStep(500);
 
84
  ui->rateSlider->setTickInterval(498);
 
85
 
 
86
  connect(ui->repeatBox, SIGNAL(clicked()), this, SLOT(changed()));
 
87
  connect(ui->delay, SIGNAL(valueChanged(int)), this, SLOT(delaySpinboxChanged(int)));
 
88
  connect(ui->delaySlider, SIGNAL(valueChanged(int)), this, SLOT(delaySliderChanged(int)));
 
89
  connect(ui->rate, SIGNAL(valueChanged(double)), this, SLOT(rateSpinboxChanged(double)));
 
90
  connect(ui->rateSlider, SIGNAL(valueChanged(int)), this, SLOT(rateSliderChanged(int)));
 
91
 
 
92
  connect(ui->click, SIGNAL(valueChanged(int)), this, SLOT(changed()));
 
93
  connect(ui->numlockGroup, SIGNAL(released(int)), this, SLOT(changed()));
 
94
 
 
95
#if !defined(HAVE_XTEST) && !defined(HAVE_XKB)
 
96
  ui->numlockGroup->setDisabled( true );
 
97
#endif
 
98
#if !defined(HAVE_XKB) && !defined(HAVE_XF86MISC)
 
99
//  delay->setDisabled( true );
 
100
//  rate->setDisabled( true );
 
101
#endif
 
102
//  lay->addStretch();
 
103
  load();
 
104
}
 
105
 
 
106
int  KeyboardConfig::getClick()
 
107
{
 
108
    return ui->click->value();
 
109
}
 
110
 
 
111
// set the slider and LCD values
 
112
void KeyboardConfig::setRepeat(int r, int delay_, double rate_)
 
113
{
 
114
    ui->repeatBox->setChecked(r == AutoRepeatModeOn);
 
115
    ui->delay->setValue(delay_);
 
116
    ui->rate->setValue(rate_);
 
117
}
 
118
 
 
119
void KeyboardConfig::setClick(int v)
 
120
{
 
121
    ui->click->setValue(v);
 
122
}
 
123
 
 
124
int KeyboardConfig::getNumLockState()
 
125
{
 
126
    int selected = ui->numlockGroup->selected();
 
127
    if( selected < 0 )
 
128
        return 2;
 
129
    return selected;
 
130
}
 
131
 
 
132
void KeyboardConfig::setNumLockState( int s )
 
133
{
 
134
    ui->numlockGroup->setSelected( s );
 
135
}
 
136
 
 
137
void KeyboardConfig::load()
 
138
{
 
139
  KConfigGroup config(KSharedConfig::openConfig("kcminputrc", KConfig::NoGlobals), "Keyboard");
 
140
 
 
141
  XKeyboardState kbd;
 
142
 
 
143
  XGetKeyboardControl(QX11Info::display(), &kbd);
 
144
 
 
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 );
 
151
 
 
152
  setClick(kbd.key_click_percent);
 
153
  setRepeat(kbd.global_auto_repeat, ui->delay->value(), ui->rate->value());
 
154
  setNumLockState( numlockState );
 
155
}
 
156
 
 
157
void KeyboardConfig::save()
 
158
{
 
159
  KConfigGroup config(KSharedConfig::openConfig("kcminputrc", KConfig::NoGlobals), "Keyboard");
 
160
 
 
161
  XKeyboardControl kbd;
 
162
 
 
163
  clickVolume = getClick();
 
164
  keyboardRepeat = ui->repeatBox->isChecked() ? AutoRepeatModeOn : AutoRepeatModeOff;
 
165
  numlockState = getNumLockState();
 
166
 
 
167
  kbd.key_click_percent = clickVolume;
 
168
  kbd.auto_repeat_mode = keyboardRepeat;
 
169
  XChangeKeyboardControl(QX11Info::display(),
 
170
                           KBKeyClickPercent | KBAutoRepeatMode,
 
171
                           &kbd);
 
172
  if( keyboardRepeat ) {
 
173
    set_repeatrate(ui->delay->value(), ui->rate->value());
 
174
  }
 
175
 
 
176
  config.writeEntry("ClickVolume",clickVolume);
 
177
  config.writeEntry("KeyboardRepeating", (keyboardRepeat == AutoRepeatModeOn));
 
178
  config.writeEntry("RepeatRate", ui->rate->value() );
 
179
  config.writeEntry("RepeatDelay", ui->delay->value() );
 
180
  config.writeEntry("NumLock", numlockState );
 
181
  config.sync();
 
182
}
 
183
 
 
184
void KeyboardConfig::defaults()
 
185
{
 
186
    setClick(50);
 
187
    setRepeat(true, 660, 25);
 
188
    setNumLockState( 2 );
 
189
}
 
190
 
 
191
QString KeyboardConfig::quickHelp() const
 
192
{
 
193
  return QString();
 
194
 
 
195
  /* "<h1>Keyboard</h1> This module allows you to choose options"
 
196
     " for the way in which your keyboard works. The actual effect of"
 
197
     " setting these options depends upon the features provided by your"
 
198
     " keyboard hardware and the X server on which KDE is running.<p>"
 
199
     " For example, you may find that changing the key click volume"
 
200
     " has no effect because this feature is not available on your system." */
 
201
}
 
202
 
 
203
void KeyboardConfig::delaySliderChanged (int value) {
 
204
        double alpha  = sliderMax / (log(5000) - log(100));
 
205
        double linearValue = exp (value/alpha + log(100));
 
206
 
 
207
        ui->delay->setValue((int)floor(0.5 + linearValue));
 
208
 
 
209
        emit KCModule::changed(true);
 
210
}
 
211
 
 
212
void KeyboardConfig::delaySpinboxChanged (int value) {
 
213
        double alpha  = sliderMax / (log(5000) - log(100));
 
214
        double logVal = alpha * (log(value)-log(100));
 
215
 
 
216
        ui->delaySlider->setValue ((int)floor (0.5 + logVal));
 
217
 
 
218
        emit KCModule::changed(true);
 
219
}
 
220
 
 
221
void KeyboardConfig::rateSliderChanged (int value) {
 
222
        ui->rate->setValue(value/100.0);
 
223
 
 
224
        emit KCModule::changed(true);
 
225
}
 
226
 
 
227
void KeyboardConfig::rateSpinboxChanged (double value) {
 
228
        ui->rateSlider->setValue ((int)(value*100));
 
229
 
 
230
        emit KCModule::changed(true);
 
231
}
 
232
 
 
233
void KeyboardConfig::changed()
 
234
{
 
235
  emit KCModule::changed(true);
 
236
}
 
237
 
 
238
/*
 
239
 Originally comes from NumLockX http://dforce.sh.cvut.cz/~seli/en/numlockx
 
240
 
 
241
 NumLockX
 
242
 
 
243
 Copyright (C) 2000-2001 Lubos Lunak        <l.lunak@kde.org>
 
244
 Copyright (C) 2001      Oswald Buddenhagen <ossi@kde.org>
 
245
 
 
246
Permission is hereby granted, free of charge, to any person obtaining a
 
247
copy of this software and associated documentation files (the "Software"),
 
248
to deal in the Software without restriction, including without limitation
 
249
the rights to use, copy, modify, merge, publish, distribute, sublicense,
 
250
and/or sell copies of the Software, and to permit persons to whom the
 
251
Software is furnished to do so, subject to the following conditions:
 
252
 
 
253
The above copyright notice and this permission notice shall be included in
 
254
all copies or substantial portions of the Software.
 
255
 
 
256
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 
257
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 
258
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
 
259
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 
260
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 
261
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
 
262
DEALINGS IN THE SOFTWARE.
 
263
 
 
264
****************************************************************************/
 
265
 
 
266
#include <X11/Xlib.h>
 
267
 
 
268
#ifdef HAVE_XTEST
 
269
#include <X11/extensions/XTest.h>
 
270
#endif
 
271
 
 
272
#ifdef HAVE_XKB
 
273
#define explicit myexplicit
 
274
#include <X11/XKBlib.h>
 
275
#undef explicit
 
276
#endif
 
277
 
 
278
#include <X11/keysym.h>
 
279
 
 
280
#if defined(HAVE_XTEST) || defined(HAVE_XKB)
 
281
 
 
282
/* the XKB stuff is based on code created by Oswald Buddenhagen <ossi@kde.org> */
 
283
#ifdef HAVE_XKB
 
284
int xkb_init()
 
285
    {
 
286
    int xkb_opcode, xkb_event, xkb_error;
 
287
    int xkb_lmaj = XkbMajorVersion;
 
288
    int xkb_lmin = XkbMinorVersion;
 
289
    return XkbLibraryVersion( &xkb_lmaj, &xkb_lmin )
 
290
                        && XkbQueryExtension( QX11Info::display(), &xkb_opcode, &xkb_event, &xkb_error,
 
291
                               &xkb_lmaj, &xkb_lmin );
 
292
    }
 
293
 
 
294
unsigned int xkb_mask_modifier( XkbDescPtr xkb, const char *name )
 
295
    {
 
296
    int i;
 
297
    if( !xkb || !xkb->names )
 
298
        return 0;
 
299
    for( i = 0;
 
300
         i < XkbNumVirtualMods;
 
301
         i++ )
 
302
        {
 
303
        char* modStr = XGetAtomName( xkb->dpy, xkb->names->vmods[i] );
 
304
        if( modStr != NULL && strcmp(name, modStr) == 0 )
 
305
            {
 
306
            unsigned int mask;
 
307
            XkbVirtualModsToReal( xkb, 1 << i, &mask );
 
308
            return mask;
 
309
            }
 
310
        }
 
311
    return 0;
 
312
    }
 
313
 
 
314
unsigned int xkb_numlock_mask()
 
315
    {
 
316
    XkbDescPtr xkb;
 
317
    if(( xkb = XkbGetKeyboard( QX11Info::display(), XkbAllComponentsMask, XkbUseCoreKbd )) != NULL )
 
318
        {
 
319
        unsigned int mask = xkb_mask_modifier( xkb, "NumLock" );
 
320
        XkbFreeKeyboard( xkb, 0, True );
 
321
        return mask;
 
322
        }
 
323
    return 0;
 
324
    }
 
325
 
 
326
int xkb_set_on()
 
327
    {
 
328
    unsigned int mask;
 
329
    if( !xkb_init())
 
330
        return 0;
 
331
    mask = xkb_numlock_mask();
 
332
    if( mask == 0 )
 
333
        return 0;
 
334
    XkbLockModifiers ( QX11Info::display(), XkbUseCoreKbd, mask, mask);
 
335
    return 1;
 
336
    }
 
337
 
 
338
int xkb_set_off()
 
339
    {
 
340
    unsigned int mask;
 
341
    if( !xkb_init())
 
342
        return 0;
 
343
    mask = xkb_numlock_mask();
 
344
    if( mask == 0 )
 
345
        return 0;
 
346
    XkbLockModifiers ( QX11Info::display(), XkbUseCoreKbd, mask, 0);
 
347
    return 1;
 
348
    }
 
349
#endif
 
350
 
 
351
#ifdef HAVE_XTEST
 
352
int xtest_get_numlock_state()
 
353
    {
 
354
    int i;
 
355
    int numlock_mask = 0;
 
356
    Window dummy1, dummy2;
 
357
    int dummy3, dummy4, dummy5, dummy6;
 
358
    unsigned int mask;
 
359
    KeyCode numlock_keycode = XKeysymToKeycode( QX11Info::display(), XK_Num_Lock );
 
360
    if( numlock_keycode == NoSymbol )
 
361
        return 0;
 
362
    XModifierKeymap* map = XGetModifierMapping( QX11Info::display() );
 
363
    for( i = 0;
 
364
         i < 8;
 
365
         ++i )
 
366
        {
 
367
        if( map->modifiermap[ map->max_keypermod * i ] == numlock_keycode )
 
368
                numlock_mask = 1 << i;
 
369
        }
 
370
    XQueryPointer( QX11Info::display(), DefaultRootWindow( QX11Info::display() ), &dummy1, &dummy2,
 
371
        &dummy3, &dummy4, &dummy5, &dummy6, &mask );
 
372
    XFreeModifiermap( map );
 
373
    return mask & numlock_mask;
 
374
    }
 
375
 
 
376
void xtest_change_numlock()
 
377
    {
 
378
    XTestFakeKeyEvent( QX11Info::display(), XKeysymToKeycode( QX11Info::display(), XK_Num_Lock ), True, CurrentTime );
 
379
    XTestFakeKeyEvent( QX11Info::display(), XKeysymToKeycode( QX11Info::display(), XK_Num_Lock ), False, CurrentTime );
 
380
    }
 
381
 
 
382
void xtest_set_on()
 
383
    {
 
384
    if( !xtest_get_numlock_state())
 
385
        xtest_change_numlock();
 
386
    }
 
387
 
 
388
void xtest_set_off()
 
389
    {
 
390
    if( xtest_get_numlock_state())
 
391
        xtest_change_numlock();
 
392
    }
 
393
#endif
 
394
 
 
395
void numlock_set_on()
 
396
    {
 
397
#ifdef HAVE_XKB
 
398
    if( xkb_set_on())
 
399
        return;
 
400
#endif
 
401
#ifdef HAVE_XTEST
 
402
    xtest_set_on();
 
403
#endif
 
404
    }
 
405
 
 
406
void numlock_set_off()
 
407
    {
 
408
#ifdef HAVE_XKB
 
409
    if( xkb_set_off())
 
410
        return;
 
411
#endif
 
412
#ifdef HAVE_XTEST
 
413
    xtest_set_off();
 
414
#endif
 
415
    }
 
416
 
 
417
void numlockx_change_numlock_state( bool set_P )
 
418
    {
 
419
    if( set_P )
 
420
        numlock_set_on();
 
421
    else
 
422
        numlock_set_off();
 
423
    }
 
424
#else
 
425
void numlockx_change_numlock_state( bool ) {} // dummy
 
426
#endif // defined(HAVE_XTEST) || defined(HAVE_XKB)
 
427
 
 
428
 
 
429
// This code is taken from xset utility from XFree 4.3 (http://www.xfree86.org/)
 
430
 
 
431
 
 
432
#if 0
 
433
//HAVE_XF86MISC
 
434
#include <X11/extensions/xf86misc.h>
 
435
void set_repeatrate(int delay, double rate)
 
436
{
 
437
  Display* dpy = QX11Info::display();
 
438
  XF86MiscKbdSettings values;
 
439
 
 
440
  XF86MiscGetKbdSettings(dpy, &values);
 
441
  values.delay = delay;
 
442
  values.rate = rate;
 
443
  XF86MiscSetKbdSettings(dpy, &values);
 
444
  return;
 
445
}
 
446
#else
 
447
void set_repeatrate(int delay, double rate)
 
448
{
 
449
#if HAVE_XKB
 
450
  Display* dpy = QX11Info::display();
 
451
  int xkbmajor = XkbMajorVersion, xkbminor = XkbMinorVersion;
 
452
  int xkbopcode, xkbevent, xkberror;
 
453
 
 
454
  if (XkbQueryExtension(dpy, &xkbopcode, &xkbevent, &xkberror, &xkbmajor,
 
455
                                &xkbminor)) {
 
456
     XkbDescPtr xkb = XkbAllocKeyboard();
 
457
     if (xkb) {
 
458
        int res = XkbGetControls(dpy, XkbRepeatKeysMask, xkb);
 
459
        xkb->ctrls->repeat_delay = delay;
 
460
        xkb->ctrls->repeat_interval = (int)floor(1000/rate + 0.5);
 
461
        res = XkbSetControls(dpy, XkbRepeatKeysMask, xkb);
 
462
        return;
 
463
     }
 
464
  }
 
465
#endif
 
466
  // Fallback: use the xset utility.
 
467
 
 
468
  // Unfortunately xset does only support int parameters, so
 
469
  // really slow repeat rates cannot be supported this way.
 
470
  // (the FSG Accessibility standard requires support for repeat rates
 
471
  // of several seconds per character)
 
472
  int r;
 
473
  if (rate < 1)
 
474
     r = 1;
 
475
  else
 
476
     r = (int)floor(rate + 0.5);
 
477
 
 
478
  QString exe = KGlobal::dirs()->findExe("xset");
 
479
  if (exe.isEmpty())
 
480
    return;
 
481
 
 
482
  KProcess p;
 
483
  p << exe << "r" << "rate" << QString::number(delay) << QString::number(r);
 
484
  p.execute();
 
485
}
 
486
#endif
 
487
 
 
488
void KeyboardConfig::init_keyboard()
 
489
{
 
490
        KConfigGroup config(KSharedConfig::openConfig( "kcminputrc" ), "Keyboard");
 
491
 
 
492
        XKeyboardState   kbd;
 
493
        XKeyboardControl kbdc;
 
494
 
 
495
        XGetKeyboardControl(QX11Info::display(), &kbd);
 
496
        bool key = config.readEntry("KeyboardRepeating", true);
 
497
        kbdc.key_click_percent = config.readEntry("ClickVolume", kbd.key_click_percent);
 
498
        kbdc.auto_repeat_mode = (key ? AutoRepeatModeOn : AutoRepeatModeOff);
 
499
 
 
500
        XChangeKeyboardControl(QX11Info::display(),
 
501
                                                   KBKeyClickPercent | KBAutoRepeatMode,
 
502
                                                   &kbdc);
 
503
 
 
504
        if( key ) {
 
505
                int delay_ = config.readEntry("RepeatDelay", 250);
 
506
                double rate_ = config.readEntry("RepeatRate", 30.);
 
507
                set_repeatrate(delay_, rate_);
 
508
        }
 
509
 
 
510
 
 
511
        int numlockState = config.readEntry( "NumLock", 2 );
 
512
        if( numlockState != 2 )
 
513
                numlockx_change_numlock_state( numlockState == 0 );
 
514
}
 
515
 
 
516
 
 
517
extern "C"
 
518
{
 
519
        KDE_EXPORT void kcminit_keyboard()
 
520
        {
 
521
                KeyboardConfig::init_keyboard();
 
522
        }
 
523
}
 
524
 
 
525
#include "kcmmisc.moc"
 
526