1 /*
2 kcmmisc.cpp
3
4 SPDX-FileCopyrightText: 1997 Patrick Dowler <dowler@morgul.fsh.uvic.ca>
5
6 Layout management, cleanups:
7 SPDX-FileCopyrightText: 1999 Dirk A. Mueller <dmuell@gmx.net>
8
9 SPDX-License-Identifier: GPL-2.0-or-later
10 */
11
12 #include "kcmmisc.h"
13 #include "ui_kcmmiscwidget.h"
14
15 #include <QButtonGroup>
16 #include <QCheckBox>
17 #include <QDoubleSpinBox>
18 #include <QSpinBox>
19 #include <QWhatsThis>
20 #include <QX11Info>
21
22 #include <KConfig>
23 #include <KConfigGroup>
24 #include <KLocalizedString>
25 #include <KSharedConfig>
26
27 #include <X11/Xlib.h>
28 #include <cmath>
29
30 namespace
31 {
hasAccentSupport()32 bool hasAccentSupport()
33 {
34 static bool isPlasmaIM = (qgetenv("QT_IM_MODULE") == "plasmaim");
35 return isPlasmaIM;
36 }
37 }
38
KCMiscKeyboardWidget(QWidget * parent)39 KCMiscKeyboardWidget::KCMiscKeyboardWidget(QWidget *parent)
40 : QWidget(parent)
41 , ui(*new Ui_KeyboardConfigWidget)
42 {
43 ui.setupUi(this);
44
45 ui.delay->setRange(100, 5000);
46 ui.delay->setSingleStep(50);
47 ui.rate->setRange(0.2, 100);
48 ui.rate->setSingleStep(5);
49
50 sliderMax = (int)floor(0.5 + 2 * (log(5000.0L) - log(100.0L)) / (log(5000.0L) - log(4999.0L)));
51 ui.delaySlider->setRange(0, sliderMax);
52 ui.delaySlider->setSingleStep(sliderMax / 100);
53 ui.delaySlider->setPageStep(sliderMax / 10);
54 ui.delaySlider->setTickInterval(sliderMax / 10);
55
56 ui.rateSlider->setRange(20, 10000);
57 ui.rateSlider->setSingleStep(30);
58 ui.rateSlider->setPageStep(500);
59 ui.rateSlider->setTickInterval(498);
60
61 connect(ui.delay, SIGNAL(valueChanged(int)), this, SLOT(delaySpinboxChanged(int)));
62 connect(ui.delaySlider, &QAbstractSlider::valueChanged, this, &KCMiscKeyboardWidget::delaySliderChanged);
63 connect(ui.rate, SIGNAL(valueChanged(double)), this, SLOT(rateSpinboxChanged(double)));
64 connect(ui.rateSlider, &QAbstractSlider::valueChanged, this, &KCMiscKeyboardWidget::rateSliderChanged);
65
66 _numlockButtonGroup = new QButtonGroup(ui.numlockButtonGroup);
67 _numlockButtonGroup->addButton(ui.radioButton1, 0);
68 _numlockButtonGroup->addButton(ui.radioButton2, 1);
69 _numlockButtonGroup->addButton(ui.radioButton3, 2);
70
71 connect(_numlockButtonGroup, SIGNAL(buttonClicked(int)), this, SLOT(changed()));
72
73 _keyboardRepeatButtonGroup = new QButtonGroup(ui.repeatFormLayout);
74 if (hasAccentSupport()) {
75 _keyboardRepeatButtonGroup->addButton(ui.accentMenuRadioButton, 0);
76 } else {
77 ui.accentMenuRadioButton->setVisible(false);
78 }
79 _keyboardRepeatButtonGroup->addButton(ui.repeatRadioButton, 1);
80 _keyboardRepeatButtonGroup->addButton(ui.nothingRadioButton, 2);
81
82 connect(_keyboardRepeatButtonGroup, SIGNAL(buttonClicked(int)), this, SLOT(changed()));
83 connect(_keyboardRepeatButtonGroup, SIGNAL(buttonClicked(int)), this, SLOT(keyboardRepeatStateChanged(int)));
84 }
85
~KCMiscKeyboardWidget()86 KCMiscKeyboardWidget::~KCMiscKeyboardWidget()
87 {
88 delete &ui;
89 }
90
91 // set the slider and LCD values
setRepeat(KeyBehaviour keyboardRepeat,int delay_,double rate_)92 void KCMiscKeyboardWidget::setRepeat(KeyBehaviour keyboardRepeat, int delay_, double rate_)
93 {
94 if (keyboardRepeat == KeyBehaviour::AccentMenu && !hasAccentSupport()) {
95 keyboardRepeat = KeyBehaviour::RepeatKey;
96 }
97 _keyboardRepeatButtonGroup->button(keyboardRepeat)->click();
98 ui.delay->setValue(delay_);
99 ui.rate->setValue(rate_);
100 delaySpinboxChanged(delay_);
101 rateSpinboxChanged(rate_);
102 }
103
getTriState(const QButtonGroup * group)104 TriState TriStateHelper::getTriState(const QButtonGroup *group)
105 {
106 int selected = group->checkedId();
107 return selected < 0 ? STATE_UNCHANGED : getTriState(selected);
108 }
109
setTriState(QButtonGroup * group,TriState state)110 void TriStateHelper::setTriState(QButtonGroup *group, TriState state)
111 {
112 group->button(getInt(state))->click();
113 }
114
load()115 void KCMiscKeyboardWidget::load()
116 {
117 KConfigGroup config(KSharedConfig::openConfig(QStringLiteral("kcminputrc"), KConfig::NoGlobals), "Keyboard");
118
119 ui.delay->blockSignals(true);
120 ui.rate->blockSignals(true);
121
122 // need to read as string to support old "true/false" parameter
123 QString key = config.readEntry("KeyRepeat", TriStateHelper::getString(STATE_ON));
124 if (key == QLatin1String("true") || key == TriStateHelper::getString(STATE_ON) || key == QLatin1String("accent")) {
125 keyboardRepeat = KeyBehaviour::AccentMenu;
126 } else if (key == QLatin1String("false") || key == TriStateHelper::getString(STATE_OFF) || key == QLatin1String("nothing")) {
127 keyboardRepeat = KeyBehaviour::DoNothing;
128 } else if (key == QLatin1String("repeat")) {
129 keyboardRepeat = KeyBehaviour::RepeatKey;
130 }
131
132 // keyboardRepeat = (key ? AutoRepeatModeOn : AutoRepeatModeOff);
133 int delay = config.readEntry("RepeatDelay", DEFAULT_REPEAT_DELAY);
134 double rate = config.readEntry("RepeatRate", DEFAULT_REPEAT_RATE);
135 setRepeat(keyboardRepeat, delay, rate);
136
137 // setRepeat(kbd.global_auto_repeat, ui.delay->value(), ui.rate->value());
138
139 numlockState = TriStateHelper::getTriState(config.readEntry("NumLock", TriStateHelper::getInt(STATE_UNCHANGED)));
140 TriStateHelper::setTriState(_numlockButtonGroup, numlockState);
141
142 ui.delay->blockSignals(false);
143 ui.rate->blockSignals(false);
144 }
145
save()146 void KCMiscKeyboardWidget::save()
147 {
148 KConfigGroup config(KSharedConfig::openConfig(QStringLiteral("kcminputrc"), KConfig::NoGlobals), "Keyboard");
149
150 keyboardRepeat = KeyBehaviour(_keyboardRepeatButtonGroup->checkedId());
151 numlockState = TriStateHelper::getTriState(_numlockButtonGroup);
152
153 config.writeEntry("KeyRepeat", keybehaviourNames[KeyBehaviour(_keyboardRepeatButtonGroup->checkedId())], KConfig::Notify);
154 config.writeEntry("RepeatRate", ui.rate->value(), KConfig::Notify);
155 config.writeEntry("RepeatDelay", ui.delay->value(), KConfig::Notify);
156 config.writeEntry("NumLock", TriStateHelper::getInt(numlockState));
157 config.sync();
158 }
159
defaults()160 void KCMiscKeyboardWidget::defaults()
161 {
162 setRepeat(KeyBehaviour::AccentMenu, DEFAULT_REPEAT_DELAY, DEFAULT_REPEAT_RATE);
163 TriStateHelper::setTriState(_numlockButtonGroup, STATE_UNCHANGED);
164 Q_EMIT changed(true);
165 }
166
quickHelp() const167 QString KCMiscKeyboardWidget::quickHelp() const
168 {
169 return QString();
170
171 /* "<h1>Keyboard</h1> This module allows you to choose options"
172 " for the way in which your keyboard works. The actual effect of"
173 " setting these options depends upon the features provided by your"
174 " keyboard hardware and the X server on which Plasma is running.<p>"
175 " For example, you may find that changing the key click volume"
176 " has no effect because this feature is not available on your system." */
177 }
178
delaySliderChanged(int value)179 void KCMiscKeyboardWidget::delaySliderChanged(int value)
180 {
181 double alpha = sliderMax / (log(5000.0L) - log(100.0L));
182 double linearValue = exp(value / alpha + log(100.0L));
183
184 ui.delay->setValue((int)floor(0.5 + linearValue));
185
186 Q_EMIT changed(true);
187 }
188
delaySpinboxChanged(int value)189 void KCMiscKeyboardWidget::delaySpinboxChanged(int value)
190 {
191 double alpha = sliderMax / (log(5000.0L) - log(100.0L));
192 double logVal = alpha * (log((double)value) - log(100.0L));
193
194 ui.delaySlider->setValue((int)floor(0.5 + logVal));
195
196 Q_EMIT changed(true);
197 }
198
rateSliderChanged(int value)199 void KCMiscKeyboardWidget::rateSliderChanged(int value)
200 {
201 ui.rate->setValue(value / 100.0);
202
203 Q_EMIT changed(true);
204 }
205
rateSpinboxChanged(double value)206 void KCMiscKeyboardWidget::rateSpinboxChanged(double value)
207 {
208 ui.rateSlider->setValue((int)(value * 100));
209
210 Q_EMIT changed(true);
211 }
212
changed()213 void KCMiscKeyboardWidget::changed()
214 {
215 Q_EMIT changed(true);
216 }
217
keyboardRepeatStateChanged(int selection)218 void KCMiscKeyboardWidget::keyboardRepeatStateChanged(int selection)
219 {
220 ui.keyboardRepeatParamsGroupBox->setVisible(selection == KeyBehaviour::RepeatKey);
221 changed();
222 }
223