Changeset View
Changeset View
Standalone View
Standalone View
kcms/input/mouse.cpp
Show First 20 Lines • Show All 59 Lines • ▼ Show 20 Line(s) | |||||
60 | #include <kstandarddirs.h> | 60 | #include <kstandarddirs.h> | ||
61 | #include <kaboutdata.h> | 61 | #include <kaboutdata.h> | ||
62 | #include <KPluginFactory> | 62 | #include <KPluginFactory> | ||
63 | #include <KPluginLoader> | 63 | #include <KPluginLoader> | ||
64 | 64 | | |||
65 | #include <config-workspace.h> | 65 | #include <config-workspace.h> | ||
66 | 66 | | |||
67 | #include "mouse.h" | 67 | #include "mouse.h" | ||
68 | #include "mousebackend.h" | ||||
69 | #include "mousesettings.h" | ||||
68 | 70 | | |||
69 | #include <X11/X.h> | | |||
70 | #include <X11/Xlib.h> | | |||
71 | #include <X11/Xatom.h> | | |||
72 | #include <X11/extensions/XInput2.h> | | |||
73 | #include <X11/Xutil.h> | | |||
74 | #include <kglobalsettings.h> | 71 | #include <kglobalsettings.h> | ||
75 | #include <QX11Info> | | |||
76 | #include <evdev-properties.h> | | |||
77 | 72 | | |||
78 | #undef Below | 73 | #undef Below | ||
79 | 74 | | |||
80 | #include "../migrationlib/kdelibs4config.h" | 75 | #include "../migrationlib/kdelibs4config.h" | ||
81 | 76 | | |||
82 | K_PLUGIN_FACTORY(MouseConfigFactory, | 77 | K_PLUGIN_FACTORY(MouseConfigFactory, | ||
83 | registerPlugin<MouseConfig>(); // mouse | 78 | registerPlugin<MouseConfig>(); // mouse | ||
84 | ) | 79 | ) | ||
85 | K_EXPORT_PLUGIN(MouseConfigFactory("kcminput")) | | |||
86 | 80 | | |||
87 | MouseConfig::MouseConfig(QWidget *parent, const QVariantList &args) | 81 | MouseConfig::MouseConfig(QWidget *parent, const QVariantList &args) | ||
88 | : KCModule(parent, args) | 82 | : KCModule(parent, args), backend(MouseBackend::implementation()) | ||
89 | { | 83 | { | ||
90 | setQuickHelp(i18n("<h1>Mouse</h1> This module allows you to choose various" | 84 | setupUi(this); | ||
91 | " options for the way in which your pointing device works. Your" | | |||
92 | " pointing device may be a mouse, trackball, or some other hardware" | | |||
93 | " that performs a similar function.")); | | |||
94 | | ||||
95 | QBoxLayout *topLayout = new QVBoxLayout(this); | | |||
96 | topLayout->setMargin(0); | | |||
97 | | ||||
98 | tabwidget = new QTabWidget(this); | | |||
99 | topLayout->addWidget(tabwidget); | | |||
100 | | ||||
101 | generalTab = new KMouseDlg(this); | | |||
102 | QButtonGroup *group = new QButtonGroup(generalTab); | | |||
103 | group->setExclusive(true); | | |||
104 | group->addButton(generalTab->singleClick); | | |||
105 | group->addButton(generalTab->doubleClick); | | |||
106 | | ||||
107 | tabwidget->addTab(generalTab, i18n("&General")); | | |||
108 | | ||||
109 | group = new QButtonGroup(generalTab); | | |||
110 | group->setExclusive(true); | | |||
111 | group->addButton(generalTab->rightHanded,RIGHT_HANDED); | | |||
112 | group->addButton(generalTab->leftHanded,LEFT_HANDED); | | |||
113 | | ||||
114 | connect(group, SIGNAL(buttonClicked(int)), this, SLOT(changed())); | | |||
115 | connect(group, SIGNAL(buttonClicked(int)), this, SLOT(slotHandedChanged(int))); | | |||
116 | | ||||
117 | QString wtstr = i18n("If you are left-handed, you may prefer to swap the" | | |||
118 | " functions of the left and right buttons on your pointing device" | | |||
119 | " by choosing the 'left-handed' option. If your pointing device" | | |||
120 | " has more than two buttons, only those that function as the" | | |||
121 | " left and right buttons are affected. For example, if you have" | | |||
122 | " a three-button mouse, the middle button is unaffected."); | | |||
123 | generalTab->handedBox->setWhatsThis(wtstr); | | |||
124 | 85 | | |||
125 | connect(generalTab->doubleClick, SIGNAL(clicked()), SLOT(changed())); | 86 | generalTab->handedGroup->setId(generalTab->rightHanded, static_cast<int>(MouseHanded::Right)); | ||
126 | 87 | generalTab->handedGroup->setId(generalTab->leftHanded, static_cast<int>(MouseHanded::Left)); | |||
127 | wtstr = i18n("The default behavior in KDE is to select and activate" | | |||
128 | " icons with a single click of the left button on your pointing" | | |||
129 | " device. This behavior is consistent with what you would expect" | | |||
130 | " when you click links in most web browsers. If you would prefer" | | |||
131 | " to select with a single click, and activate with a double click," | | |||
132 | " check this option."); | | |||
133 | generalTab->doubleClick->setWhatsThis(wtstr); | | |||
134 | 88 | | |||
135 | wtstr = i18n("Activates and opens a file or folder with a single click."); | 89 | connect(generalTab->handedGroup, SIGNAL(buttonClicked(int)), this, SLOT(changed())); | ||
136 | generalTab->singleClick->setWhatsThis(wtstr); | 90 | connect(generalTab->handedGroup, SIGNAL(buttonClicked(int)), this, SLOT(slotHandedChanged(int))); | ||
91 | connect(generalTab->doubleClick, SIGNAL(clicked()), SLOT(changed())); | ||||
137 | 92 | | |||
138 | connect(generalTab->singleClick, SIGNAL(clicked()), this, SLOT(changed())); | 93 | connect(generalTab->singleClick, SIGNAL(clicked()), this, SLOT(changed())); | ||
139 | | ||||
140 | // Only allow setting reversing scroll polarity if we have scroll buttons | | |||
141 | unsigned char map[20]; | | |||
142 | if (QX11Info::isPlatformX11() && XGetPointerMapping(QX11Info::display(), map, 20) >= 5) | | |||
143 | { | | |||
144 | generalTab->cbScrollPolarity->setEnabled(true); | | |||
145 | generalTab->cbScrollPolarity->show(); | | |||
146 | } | | |||
147 | else | | |||
148 | { | | |||
149 | generalTab->cbScrollPolarity->setEnabled(false); | | |||
150 | generalTab->cbScrollPolarity->hide(); | | |||
151 | } | | |||
152 | connect(generalTab->cbScrollPolarity, SIGNAL(clicked()), this, SLOT(changed())); | 94 | connect(generalTab->cbScrollPolarity, SIGNAL(clicked()), this, SLOT(changed())); | ||
153 | connect(generalTab->cbScrollPolarity, SIGNAL(clicked()), this, SLOT(slotScrollPolarityChanged())); | 95 | connect(generalTab->cbScrollPolarity, SIGNAL(clicked()), this, SLOT(slotScrollPolarityChanged())); | ||
154 | 96 | | |||
155 | // Advanced tab | | |||
156 | advancedTab = new QWidget(0); | | |||
157 | advancedTab->setObjectName("Advanced Tab"); | | |||
158 | tabwidget->addTab(advancedTab, i18n("Advanced")); | | |||
159 | | ||||
160 | QFormLayout *formLayout = new QFormLayout; | | |||
161 | formLayout->setFieldGrowthPolicy(QFormLayout::ExpandingFieldsGrow); | | |||
162 | | ||||
163 | accel = new QDoubleSpinBox(advancedTab); | | |||
164 | accel->setDecimals(1); | | |||
165 | accel->setRange(0.1, 20); | | |||
166 | accel->setSingleStep(0.1); | | |||
167 | accel->setValue(2); | | |||
168 | accel->setSuffix(i18n(" x")); | | |||
169 | accel->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Fixed); | | |||
170 | | ||||
171 | formLayout->addRow(i18n("Pointer acceleration:"), accel); | | |||
172 | connect(accel, SIGNAL(valueChanged(double)), this, SLOT(changed())); | 97 | connect(accel, SIGNAL(valueChanged(double)), this, SLOT(changed())); | ||
173 | | ||||
174 | wtstr = i18n("<p>This option allows you to change the relationship" | | |||
175 | " between the distance that the mouse pointer moves on the" | | |||
176 | " screen and the relative movement of the physical device" | | |||
177 | " itself (which may be a mouse, trackball, or some other" | | |||
178 | " pointing device.)</p><p>" | | |||
179 | " A high value for the acceleration will lead to large" | | |||
180 | " movements of the mouse pointer on the screen even when" | | |||
181 | " you only make a small movement with the physical device." | | |||
182 | " Selecting very high values may result in the mouse pointer" | | |||
183 | " flying across the screen, making it hard to control.</p>"); | | |||
184 | accel->setWhatsThis(wtstr); | | |||
185 | | ||||
186 | thresh = new QSpinBox(advancedTab); | | |||
187 | thresh->setRange(0, 20); | | |||
188 | thresh->setSingleStep(1); | | |||
189 | thresh->setValue(2); | | |||
190 | thresh->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Fixed); | | |||
191 | formLayout->addRow(i18n("Pointer threshold:"), thresh); | | |||
192 | connect(thresh, SIGNAL(valueChanged(int)), this, SLOT(changed())); | 98 | connect(thresh, SIGNAL(valueChanged(int)), this, SLOT(changed())); | ||
193 | connect(thresh, SIGNAL(valueChanged(int)), this, SLOT(slotThreshChanged(int))); | 99 | connect(thresh, SIGNAL(valueChanged(int)), this, SLOT(slotThreshChanged(int))); | ||
100 | connect(accelProfileComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(changed())); | ||||
194 | slotThreshChanged(thresh->value()); | 101 | slotThreshChanged(thresh->value()); | ||
195 | 102 | | |||
196 | wtstr = i18n("<p>The threshold is the smallest distance that the" | | |||
197 | " mouse pointer must move on the screen before acceleration" | | |||
198 | " has any effect. If the movement is smaller than the threshold," | | |||
199 | " the mouse pointer moves as if the acceleration was set to 1X;</p><p>" | | |||
200 | " thus, when you make small movements with the physical device," | | |||
201 | " there is no acceleration at all, giving you a greater degree" | | |||
202 | " of control over the mouse pointer. With larger movements of" | | |||
203 | " the physical device, you can move the mouse pointer" | | |||
204 | " rapidly to different areas on the screen.</p>"); | | |||
205 | thresh->setWhatsThis(wtstr); | | |||
206 | | ||||
207 | // It would be nice if the user had a test field. | 103 | // It would be nice if the user had a test field. | ||
208 | // Selecting such values in milliseconds is not intuitive | 104 | // Selecting such values in milliseconds is not intuitive | ||
209 | doubleClickInterval = new QSpinBox(advancedTab); | | |||
210 | doubleClickInterval->setRange(100, 2000); | | |||
211 | doubleClickInterval->setSuffix(i18n(" msec")); | | |||
212 | doubleClickInterval->setSingleStep(100); | | |||
213 | doubleClickInterval->setValue(2000); | | |||
214 | doubleClickInterval->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Fixed); | | |||
215 | formLayout->addRow(i18n("Double click interval:"), doubleClickInterval); | | |||
216 | connect(doubleClickInterval, SIGNAL(valueChanged(int)), this, SLOT(changed())); | 105 | connect(doubleClickInterval, SIGNAL(valueChanged(int)), this, SLOT(changed())); | ||
217 | 106 | | |||
218 | wtstr = i18n("The double click interval is the maximal time" | | |||
219 | " (in milliseconds) between two mouse clicks which" | | |||
220 | " turns them into a double click. If the second" | | |||
221 | " click happens later than this time interval after" | | |||
222 | " the first click, they are recognized as two" | | |||
223 | " separate clicks."); | | |||
224 | doubleClickInterval->setWhatsThis(wtstr); | | |||
225 | | ||||
226 | dragStartTime = new QSpinBox(advancedTab); | | |||
227 | dragStartTime->setRange(100, 2000); | | |||
228 | dragStartTime->setSuffix(i18n(" msec")); | | |||
229 | dragStartTime->setSingleStep(100); | | |||
230 | dragStartTime->setValue(2000); | | |||
231 | dragStartTime->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Fixed); | | |||
232 | formLayout->addRow(i18n("Drag start time:"), dragStartTime); | | |||
233 | connect(dragStartTime, SIGNAL(valueChanged(int)), this, SLOT(changed())); | 107 | connect(dragStartTime, SIGNAL(valueChanged(int)), this, SLOT(changed())); | ||
234 | 108 | | |||
235 | wtstr = i18n("If you click with the mouse (e.g. in a multi-line" | | |||
236 | " editor) and begin to move the mouse within the" | | |||
237 | " drag start time, a drag operation will be initiated."); | | |||
238 | dragStartTime->setWhatsThis(wtstr); | | |||
239 | | ||||
240 | dragStartDist = new QSpinBox(advancedTab); | | |||
241 | dragStartDist->setRange(1, 20); | | |||
242 | dragStartDist->setSingleStep(1); | | |||
243 | dragStartDist->setValue(20); | | |||
244 | dragStartDist->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Fixed); | | |||
245 | formLayout->addRow(i18n("Drag start distance:"), dragStartDist); | | |||
246 | connect(dragStartDist, SIGNAL(valueChanged(int)), this, SLOT(changed())); | 109 | connect(dragStartDist, SIGNAL(valueChanged(int)), this, SLOT(changed())); | ||
247 | connect(dragStartDist, SIGNAL(valueChanged(int)), this, SLOT(slotDragStartDistChanged(int))); | 110 | connect(dragStartDist, SIGNAL(valueChanged(int)), this, SLOT(slotDragStartDistChanged(int))); | ||
248 | slotDragStartDistChanged(dragStartDist->value()); | 111 | slotDragStartDistChanged(dragStartDist->value()); | ||
249 | 112 | | |||
250 | wtstr = i18n("If you click with the mouse and begin to move the" | | |||
251 | " mouse at least the drag start distance, a drag" | | |||
252 | " operation will be initiated."); | | |||
253 | dragStartDist->setWhatsThis(wtstr); | | |||
254 | | ||||
255 | wheelScrollLines = new QSpinBox(advancedTab); | | |||
256 | wheelScrollLines->setRange(1, 12); | | |||
257 | wheelScrollLines->setSingleStep(1); | | |||
258 | wheelScrollLines->setValue(3); | | |||
259 | wheelScrollLines->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Fixed); | | |||
260 | formLayout->addRow(i18n("Mouse wheel scrolls by:"), wheelScrollLines); | | |||
261 | connect(wheelScrollLines, SIGNAL(valueChanged(int)), this, SLOT(changed())); | 113 | connect(wheelScrollLines, SIGNAL(valueChanged(int)), this, SLOT(changed())); | ||
262 | connect(wheelScrollLines, SIGNAL(valueChanged(int)), SLOT(slotWheelScrollLinesChanged(int))); | 114 | connect(wheelScrollLines, SIGNAL(valueChanged(int)), SLOT(slotWheelScrollLinesChanged(int))); | ||
263 | slotWheelScrollLinesChanged(wheelScrollLines->value()); | 115 | slotWheelScrollLinesChanged(wheelScrollLines->value()); | ||
264 | 116 | | |||
265 | wtstr = i18n("If you use the wheel of a mouse, this value determines the number" | | |||
266 | " of lines to scroll for each wheel movement. Note that if this" | | |||
267 | " number exceeds the number of visible lines, it will be ignored" | | |||
268 | " and the wheel movement will be handled as a page up/down movement."); | | |||
269 | wheelScrollLines->setWhatsThis(wtstr); | | |||
270 | | ||||
271 | QHBoxLayout *outerLayout = new QHBoxLayout(advancedTab); | | |||
272 | outerLayout->addLayout(formLayout, 0); | | |||
273 | outerLayout->addStretch(1); | | |||
274 | | ||||
275 | QWidget *keysTab = new QWidget(this); | | |||
276 | keysTab->setObjectName("Mouse Navigation"); | | |||
277 | tabwidget->addTab(keysTab, i18n("Keyboard Navigation")); | | |||
278 | | ||||
279 | formLayout = new QFormLayout; | | |||
280 | formLayout->setFieldGrowthPolicy(QFormLayout::ExpandingFieldsGrow); | | |||
281 | | ||||
282 | mouseKeys = new QCheckBox(i18n("&Move pointer with keyboard (using the num pad)"), keysTab); | | |||
283 | formLayout->addRow(mouseKeys); | | |||
284 | | ||||
285 | mk_delay = new QSpinBox(keysTab); | | |||
286 | mk_delay->setRange(1, 1000); | | |||
287 | mk_delay->setSingleStep(50); | | |||
288 | mk_delay->setSuffix(i18n(" msec")); | | |||
289 | mk_delay->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Fixed); | | |||
290 | formLayout->addRow(i18n("&Acceleration delay:"), mk_delay); | | |||
291 | | ||||
292 | mk_interval = new QSpinBox(keysTab); | | |||
293 | mk_interval->setRange(1, 1000); | | |||
294 | mk_interval->setSingleStep(10); | | |||
295 | mk_interval->setSuffix(i18n(" msec")); | | |||
296 | mk_interval->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Fixed); | | |||
297 | formLayout->addRow(i18n("R&epeat interval:"), mk_interval); | | |||
298 | | ||||
299 | mk_time_to_max = new QSpinBox(keysTab); | | |||
300 | mk_time_to_max->setRange(100, 10000); | | |||
301 | mk_time_to_max->setSingleStep(200); | | |||
302 | mk_time_to_max->setSuffix(i18n(" msec")); | | |||
303 | mk_time_to_max->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Fixed); | | |||
304 | formLayout->addRow(i18n("Acceleration &time:"), mk_time_to_max); | | |||
305 | | ||||
306 | mk_max_speed = new QSpinBox(keysTab); | | |||
307 | mk_max_speed->setRange(1, 2000); | | |||
308 | mk_max_speed->setSingleStep(20); | | |||
309 | mk_max_speed->setSuffix(i18n(" pixel/sec")); | | |||
310 | mk_max_speed->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Fixed); | | |||
311 | formLayout->addRow(i18n("Ma&ximum speed:"), mk_max_speed); | | |||
312 | | ||||
313 | mk_curve = new QSpinBox(keysTab); | | |||
314 | mk_curve->setRange(-1000, 1000); | | |||
315 | mk_curve->setSingleStep(100); | | |||
316 | mk_curve->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Fixed); | | |||
317 | formLayout->addRow(i18n("Acceleration &profile:"), mk_curve); | | |||
318 | | ||||
319 | outerLayout = new QHBoxLayout(keysTab); | | |||
320 | outerLayout->addLayout(formLayout, 0); | | |||
321 | outerLayout->addStretch(1); | | |||
322 | | ||||
323 | connect(mouseKeys, SIGNAL(clicked()), this, SLOT(checkAccess())); | 117 | connect(mouseKeys, SIGNAL(clicked()), this, SLOT(checkAccess())); | ||
324 | connect(mouseKeys, SIGNAL(clicked()), this, SLOT(changed())); | 118 | connect(mouseKeys, SIGNAL(clicked()), this, SLOT(changed())); | ||
325 | connect(mk_delay, SIGNAL(valueChanged(int)), this, SLOT(changed())); | 119 | connect(mk_delay, SIGNAL(valueChanged(int)), this, SLOT(changed())); | ||
326 | connect(mk_interval, SIGNAL(valueChanged(int)), this, SLOT(changed())); | 120 | connect(mk_interval, SIGNAL(valueChanged(int)), this, SLOT(changed())); | ||
327 | connect(mk_time_to_max, SIGNAL(valueChanged(int)), this, SLOT(changed())); | 121 | connect(mk_time_to_max, SIGNAL(valueChanged(int)), this, SLOT(changed())); | ||
328 | connect(mk_max_speed, SIGNAL(valueChanged(int)), this, SLOT(changed())); | 122 | connect(mk_max_speed, SIGNAL(valueChanged(int)), this, SLOT(changed())); | ||
329 | connect(mk_curve, SIGNAL(valueChanged(int)), this, SLOT(changed())); | 123 | connect(mk_curve, SIGNAL(valueChanged(int)), this, SLOT(changed())); | ||
330 | 124 | | |||
▲ Show 20 Lines • Show All 45 Lines • ▼ Show 20 Line(s) | |||||
376 | } | 170 | } | ||
377 | 171 | | |||
378 | void MouseConfig::setThreshold(int val) | 172 | void MouseConfig::setThreshold(int val) | ||
379 | { | 173 | { | ||
380 | thresh->setValue(val); | 174 | thresh->setValue(val); | ||
381 | } | 175 | } | ||
382 | 176 | | |||
383 | 177 | | |||
384 | int MouseConfig::getHandedness() | 178 | MouseHanded MouseConfig::getHandedness() | ||
385 | { | 179 | { | ||
386 | if (generalTab->rightHanded->isChecked()) | 180 | if (generalTab->rightHanded->isChecked()) | ||
387 | return RIGHT_HANDED; | 181 | return MouseHanded::Right; | ||
388 | else | 182 | else | ||
389 | return LEFT_HANDED; | 183 | return MouseHanded::Left; | ||
390 | } | 184 | } | ||
391 | 185 | | |||
392 | void MouseConfig::setHandedness(int val) | 186 | void MouseConfig::setHandedness(MouseHanded val) | ||
393 | { | 187 | { | ||
394 | generalTab->rightHanded->setChecked(false); | 188 | generalTab->rightHanded->setChecked(false); | ||
395 | generalTab->leftHanded->setChecked(false); | 189 | generalTab->leftHanded->setChecked(false); | ||
396 | if (val == RIGHT_HANDED) { | 190 | if (val == MouseHanded::Right) { | ||
397 | generalTab->rightHanded->setChecked(true); | 191 | generalTab->rightHanded->setChecked(true); | ||
398 | generalTab->mousePix->setPixmap(KStandardDirs::locate("data", "kcminput/pics/mouse_rh.png")); | 192 | generalTab->mousePix->setPixmap(KStandardDirs::locate("data", "kcminput/pics/mouse_rh.png")); | ||
399 | } | 193 | } | ||
400 | else { | 194 | else { | ||
401 | generalTab->leftHanded->setChecked(true); | 195 | generalTab->leftHanded->setChecked(true); | ||
402 | generalTab->mousePix->setPixmap(KStandardDirs::locate("data", "kcminput/pics/mouse_lh.png")); | 196 | generalTab->mousePix->setPixmap(KStandardDirs::locate("data", "kcminput/pics/mouse_lh.png")); | ||
403 | } | 197 | } | ||
404 | settings->m_handedNeedsApply = true; | 198 | settings->m_handedNeedsApply = true; | ||
405 | } | 199 | } | ||
406 | 200 | | |||
407 | void MouseConfig::load() | 201 | void MouseConfig::load() | ||
408 | { | 202 | { | ||
409 | KConfig config("kcminputrc"); | 203 | KConfig config("kcminputrc"); | ||
410 | settings->load(&config); | 204 | settings->load(&config, backend); | ||
205 | | ||||
206 | // settings->load will trigger backend->load so information will be avaialbe | ||||
207 | // here. | ||||
208 | // Only allow setting reversing scroll polarity if we have scroll buttons | ||||
209 | if (backend) { | ||||
210 | if (backend->supportScrollPolarity()) | ||||
211 | { | ||||
212 | generalTab->cbScrollPolarity->setEnabled(true); | ||||
213 | generalTab->cbScrollPolarity->show(); | ||||
214 | } | ||||
215 | else | ||||
216 | { | ||||
217 | generalTab->cbScrollPolarity->setEnabled(false); | ||||
218 | generalTab->cbScrollPolarity->hide(); | ||||
219 | } | ||||
220 | | ||||
221 | auto accelProfile = backend->supportedAccelerationProfiles(); | ||||
222 | accelProfileComboBox->setEnabled(!accelProfile.isEmpty()); | ||||
223 | accelProfileComboBox->setVisible(!accelProfile.isEmpty()); | ||||
224 | accelerationProfileLabel->setEnabled(!accelProfile.isEmpty()); | ||||
225 | accelerationProfileLabel->setVisible(!accelProfile.isEmpty()); | ||||
226 | accelProfileComboBox->clear(); | ||||
227 | int idx = 0; | ||||
228 | for (const auto &profile : accelProfile) { | ||||
229 | accelProfileComboBox->addItem(i18n(profile.toUtf8().constData()), profile); | ||||
230 | if (profile == settings->m_currentAccelProfile) { | ||||
231 | accelProfileComboBox->setCurrentIndex(idx); | ||||
232 | } | ||||
233 | idx++; | ||||
234 | } | ||||
235 | } | ||||
411 | 236 | | |||
412 | generalTab->rightHanded->setEnabled(settings->handedEnabled); | 237 | generalTab->rightHanded->setEnabled(settings->handedEnabled); | ||
413 | generalTab->leftHanded->setEnabled(settings->handedEnabled); | 238 | generalTab->leftHanded->setEnabled(settings->handedEnabled); | ||
414 | if (generalTab->cbScrollPolarity->isEnabled()) | 239 | if (generalTab->cbScrollPolarity->isEnabled()) | ||
415 | generalTab->cbScrollPolarity->setEnabled(settings->handedEnabled); | 240 | generalTab->cbScrollPolarity->setEnabled(settings->handedEnabled); | ||
416 | generalTab->cbScrollPolarity->setChecked(settings->reverseScrollPolarity); | 241 | generalTab->cbScrollPolarity->setChecked(settings->reverseScrollPolarity); | ||
417 | 242 | | |||
418 | setAccel(settings->accelRate); | 243 | setAccel(settings->accelRate); | ||
▲ Show 20 Lines • Show All 45 Lines • ▼ Show 20 Line(s) | 286 | { | |||
464 | settings->handed = getHandedness(); | 289 | settings->handed = getHandedness(); | ||
465 | 290 | | |||
466 | settings->doubleClickInterval = doubleClickInterval->value(); | 291 | settings->doubleClickInterval = doubleClickInterval->value(); | ||
467 | settings->dragStartTime = dragStartTime->value(); | 292 | settings->dragStartTime = dragStartTime->value(); | ||
468 | settings->dragStartDist = dragStartDist->value(); | 293 | settings->dragStartDist = dragStartDist->value(); | ||
469 | settings->wheelScrollLines = wheelScrollLines->value(); | 294 | settings->wheelScrollLines = wheelScrollLines->value(); | ||
470 | settings->singleClick = !generalTab->doubleClick->isChecked(); | 295 | settings->singleClick = !generalTab->doubleClick->isChecked(); | ||
471 | settings->reverseScrollPolarity = generalTab->cbScrollPolarity->isChecked(); | 296 | settings->reverseScrollPolarity = generalTab->cbScrollPolarity->isChecked(); | ||
297 | settings->m_currentAccelProfile = accelProfileComboBox->itemData(accelProfileComboBox->currentIndex()).toString(); | ||||
472 | 298 | | |||
473 | settings->apply(); | 299 | settings->apply(backend); | ||
474 | KConfig config("kcminputrc"); | 300 | KConfig config("kcminputrc"); | ||
475 | settings->save(&config); | 301 | settings->save(&config); | ||
476 | 302 | | |||
477 | KConfig ac("kaccessrc"); | 303 | KConfig ac("kaccessrc"); | ||
478 | 304 | | |||
479 | KConfigGroup group = ac.group("Mouse"); | 305 | KConfigGroup group = ac.group("Mouse"); | ||
480 | 306 | | |||
481 | int interval = mk_interval->value(); | 307 | int interval = mk_interval->value(); | ||
Show All 12 Lines | |||||
494 | 320 | | |||
495 | emit changed(false); | 321 | emit changed(false); | ||
496 | } | 322 | } | ||
497 | 323 | | |||
498 | void MouseConfig::defaults() | 324 | void MouseConfig::defaults() | ||
499 | { | 325 | { | ||
500 | setThreshold(2); | 326 | setThreshold(2); | ||
501 | setAccel(2); | 327 | setAccel(2); | ||
502 | setHandedness(RIGHT_HANDED); | 328 | setHandedness(MouseHanded::Right); | ||
503 | generalTab->cbScrollPolarity->setChecked(false); | 329 | generalTab->cbScrollPolarity->setChecked(false); | ||
504 | doubleClickInterval->setValue(400); | 330 | doubleClickInterval->setValue(400); | ||
505 | dragStartTime->setValue(500); | 331 | dragStartTime->setValue(500); | ||
506 | dragStartDist->setValue(4); | 332 | dragStartDist->setValue(4); | ||
507 | wheelScrollLines->setValue(3); | 333 | wheelScrollLines->setValue(3); | ||
508 | generalTab->doubleClick->setChecked(!KDE_DEFAULT_SINGLECLICK); | 334 | generalTab->doubleClick->setChecked(!KDE_DEFAULT_SINGLECLICK); | ||
509 | generalTab->singleClick->setChecked(KDE_DEFAULT_SINGLECLICK); | 335 | generalTab->singleClick->setChecked(KDE_DEFAULT_SINGLECLICK); | ||
510 | 336 | | |||
511 | mouseKeys->setChecked(false); | 337 | mouseKeys->setChecked(false); | ||
512 | mk_delay->setValue(160); | 338 | mk_delay->setValue(160); | ||
513 | mk_interval->setValue(5); | 339 | mk_interval->setValue(5); | ||
514 | mk_time_to_max->setValue(5000); | 340 | mk_time_to_max->setValue(5000); | ||
515 | mk_max_speed->setValue(1000); | 341 | mk_max_speed->setValue(1000); | ||
516 | mk_curve->setValue(0); | 342 | mk_curve->setValue(0); | ||
517 | 343 | | |||
518 | checkAccess(); | 344 | checkAccess(); | ||
519 | changed(); | 345 | changed(); | ||
520 | } | 346 | } | ||
521 | 347 | | |||
522 | /** No descriptions */ | 348 | /** No descriptions */ | ||
523 | void MouseConfig::slotHandedChanged(int val) | 349 | void MouseConfig::slotHandedChanged(int val) | ||
524 | { | 350 | { | ||
525 | if (val==RIGHT_HANDED) | 351 | if (val == static_cast<int>(MouseHanded::Right)) | ||
526 | generalTab->mousePix->setPixmap(KStandardDirs::locate("data", "kcminput/pics/mouse_rh.png")); | 352 | generalTab->mousePix->setPixmap(KStandardDirs::locate("data", "kcminput/pics/mouse_rh.png")); | ||
527 | else | 353 | else | ||
528 | generalTab->mousePix->setPixmap(KStandardDirs::locate("data", "kcminput/pics/mouse_lh.png")); | 354 | generalTab->mousePix->setPixmap(KStandardDirs::locate("data", "kcminput/pics/mouse_lh.png")); | ||
529 | settings->m_handedNeedsApply = true; | 355 | settings->m_handedNeedsApply = true; | ||
530 | } | 356 | } | ||
531 | 357 | | |||
532 | void MouseSettings::load(KConfig *config, Display *dpy) | | |||
533 | { | | |||
534 | // TODO: what's a good threshold default value | | |||
535 | int threshold = 0; | | |||
536 | int h = RIGHT_HANDED; | | |||
537 | double accel = 1.0; | | |||
538 | if (QX11Info::isPlatformX11()) { | | |||
539 | int accel_num, accel_den; | | |||
540 | | ||||
541 | XGetPointerControl(dpy, &accel_num, &accel_den, &threshold); | | |||
542 | accel = float(accel_num) / float(accel_den); | | |||
543 | | ||||
544 | // get settings from X server | | |||
545 | unsigned char map[20]; | | |||
546 | num_buttons = XGetPointerMapping(dpy, map, 20); | | |||
547 | | ||||
548 | handedEnabled = true; | | |||
549 | | ||||
550 | // ## keep this in sync with KGlobalSettings::mouseSettings | | |||
551 | if (num_buttons == 1) | | |||
552 | { | | |||
553 | /* disable button remapping */ | | |||
554 | handedEnabled = false; | | |||
555 | } | | |||
556 | else if (num_buttons == 2) | | |||
557 | { | | |||
558 | if ((int)map[0] == 1 && (int)map[1] == 2) | | |||
559 | h = RIGHT_HANDED; | | |||
560 | else if ((int)map[0] == 2 && (int)map[1] == 1) | | |||
561 | h = LEFT_HANDED; | | |||
562 | else | | |||
563 | /* custom button setup: disable button remapping */ | | |||
564 | handedEnabled = false; | | |||
565 | } | | |||
566 | else | | |||
567 | { | | |||
568 | middle_button = (int)map[1]; | | |||
569 | if ((int)map[0] == 1 && (int)map[2] == 3) | | |||
570 | h = RIGHT_HANDED; | | |||
571 | else if ((int)map[0] == 3 && (int)map[2] == 1) | | |||
572 | h = LEFT_HANDED; | | |||
573 | else | | |||
574 | { | | |||
575 | /* custom button setup: disable button remapping */ | | |||
576 | handedEnabled = false; | | |||
577 | } | | |||
578 | } | | |||
579 | } else { | | |||
580 | // other platforms | | |||
581 | handedEnabled = true; | | |||
582 | } | | |||
583 | | ||||
584 | KConfigGroup group = config->group("Mouse"); | | |||
585 | double a = group.readEntry("Acceleration", -1.0); | | |||
586 | if (a == -1) | | |||
587 | accelRate = accel; | | |||
588 | else | | |||
589 | accelRate = a; | | |||
590 | | ||||
591 | int t = group.readEntry("Threshold", -1); | | |||
592 | if (t == -1) | | |||
593 | thresholdMove = threshold; | | |||
594 | else | | |||
595 | thresholdMove = t; | | |||
596 | | ||||
597 | QString key = group.readEntry("MouseButtonMapping"); | | |||
598 | if (key == "RightHanded") | | |||
599 | handed = RIGHT_HANDED; | | |||
600 | else if (key == "LeftHanded") | | |||
601 | handed = LEFT_HANDED; | | |||
602 | #ifdef __GNUC__ | | |||
603 | #warning was key == NULL how was this working? is key.isNull() what the coder meant? | | |||
604 | #endif | | |||
605 | else if (key.isNull()) | | |||
606 | handed = h; | | |||
607 | reverseScrollPolarity = group.readEntry("ReverseScrollPolarity", false); | | |||
608 | m_handedNeedsApply = false; | | |||
609 | | ||||
610 | // SC/DC/AutoSelect/ChangeCursor | | |||
611 | group = config->group("KDE"); | | |||
612 | doubleClickInterval = group.readEntry("DoubleClickInterval", 400); | | |||
613 | dragStartTime = group.readEntry("StartDragTime", 500); | | |||
614 | dragStartDist = group.readEntry("StartDragDist", 4); | | |||
615 | wheelScrollLines = group.readEntry("WheelScrollLines", 3); | | |||
616 | | ||||
617 | singleClick = group.readEntry("SingleClick", KDE_DEFAULT_SINGLECLICK); | | |||
618 | } | | |||
619 | | ||||
620 | void MouseConfig::slotThreshChanged(int value) | 358 | void MouseConfig::slotThreshChanged(int value) | ||
621 | { | 359 | { | ||
622 | thresh->setSuffix(i18np(" pixel", " pixels", value)); | 360 | thresh->setSuffix(i18np(" pixel", " pixels", value)); | ||
623 | } | 361 | } | ||
624 | 362 | | |||
625 | void MouseConfig::slotDragStartDistChanged(int value) | 363 | void MouseConfig::slotDragStartDistChanged(int value) | ||
626 | { | 364 | { | ||
627 | dragStartDist->setSuffix(i18np(" pixel", " pixels", value)); | 365 | dragStartDist->setSuffix(i18np(" pixel", " pixels", value)); | ||
628 | } | 366 | } | ||
629 | 367 | | |||
630 | void MouseConfig::slotWheelScrollLinesChanged(int value) | 368 | void MouseConfig::slotWheelScrollLinesChanged(int value) | ||
631 | { | 369 | { | ||
632 | wheelScrollLines->setSuffix(i18np(" line", " lines", value)); | 370 | wheelScrollLines->setSuffix(i18np(" line", " lines", value)); | ||
633 | } | 371 | } | ||
634 | 372 | | |||
635 | void MouseSettings::apply(bool force) | | |||
636 | { | | |||
637 | if (!QX11Info::isPlatformX11()) { | | |||
638 | return; | | |||
639 | } | | |||
640 | XChangePointerControl(QX11Info::display(), | | |||
641 | true, true, int(qRound(accelRate*10)), 10, thresholdMove); | | |||
642 | | ||||
643 | // 256 might seems extreme, but X has already been known to return 32, | | |||
644 | // and we don't want to truncate things. Xlib limits the table to 256 bytes, | | |||
645 | // so it's a good upper bound.. | | |||
646 | unsigned char map[256]; | | |||
647 | num_buttons = XGetPointerMapping(QX11Info::display(), map, 256); | | |||
648 | | ||||
649 | int remap=(num_buttons>=1); | | |||
650 | if (handedEnabled && (m_handedNeedsApply || force)) { | | |||
651 | if (num_buttons == 1) | | |||
652 | { | | |||
653 | map[0] = (unsigned char) 1; | | |||
654 | } | | |||
655 | else if (num_buttons == 2) | | |||
656 | { | | |||
657 | if (handed == RIGHT_HANDED) | | |||
658 | { | | |||
659 | map[0] = (unsigned char) 1; | | |||
660 | map[1] = (unsigned char) 3; | | |||
661 | } | | |||
662 | else | | |||
663 | { | | |||
664 | map[0] = (unsigned char) 3; | | |||
665 | map[1] = (unsigned char) 1; | | |||
666 | } | | |||
667 | } | | |||
668 | else // 3 buttons and more | | |||
669 | { | | |||
670 | if (handed == RIGHT_HANDED) | | |||
671 | { | | |||
672 | map[0] = (unsigned char) 1; | | |||
673 | map[1] = (unsigned char) middle_button; | | |||
674 | map[2] = (unsigned char) 3; | | |||
675 | } | | |||
676 | else | | |||
677 | { | | |||
678 | map[0] = (unsigned char) 3; | | |||
679 | map[1] = (unsigned char) middle_button; | | |||
680 | map[2] = (unsigned char) 1; | | |||
681 | } | | |||
682 | } | | |||
683 | | ||||
684 | int retval; | | |||
685 | if (remap) { | | |||
686 | while ((retval=XSetPointerMapping(QX11Info::display(), map, | | |||
687 | num_buttons)) == MappingBusy) | | |||
688 | /* keep trying until the pointer is free */ | | |||
689 | { }; | | |||
690 | } | | |||
691 | | ||||
692 | // apply reverseScrollPolarity | | |||
693 | Display *dpy = QX11Info::display(); | | |||
694 | Atom prop_wheel_emulation = XInternAtom(dpy, EVDEV_PROP_WHEEL, True); | | |||
695 | Atom prop_scroll_distance = XInternAtom(dpy, EVDEV_PROP_SCROLL_DISTANCE, True); | | |||
696 | Atom prop_wheel_emulation_axes = XInternAtom(dpy, EVDEV_PROP_WHEEL_AXES, True); | | |||
697 | int ndevices_return; | | |||
698 | XIDeviceInfo *info = XIQueryDevice(dpy, XIAllDevices, &ndevices_return); | | |||
699 | if (!info) { | | |||
700 | return; | | |||
701 | } | | |||
702 | for (int i = 0; i < ndevices_return; ++i) { | | |||
703 | if ((info + i)->use == XISlavePointer) { | | |||
704 | int deviceid = (info + i)->deviceid; | | |||
705 | Status status; | | |||
706 | Atom type_return; | | |||
707 | int format_return; | | |||
708 | unsigned long num_items_return; | | |||
709 | unsigned long bytes_after_return; | | |||
710 | | ||||
711 | unsigned char *data = nullptr; | | |||
712 | unsigned char *data2 = nullptr; | | |||
713 | //data returned is an 1 byte boolean | | |||
714 | status = XIGetProperty(dpy, deviceid, prop_wheel_emulation, 0, 1, | | |||
715 | False, XA_INTEGER, &type_return, &format_return, | | |||
716 | &num_items_return, &bytes_after_return, &data); | | |||
717 | if (status != Success) { | | |||
718 | continue; | | |||
719 | } | | |||
720 | | ||||
721 | // pointer device without wheel emulation | | |||
722 | if (type_return != XA_INTEGER || data == NULL || *data == False) { | | |||
723 | status = XIGetProperty(dpy, deviceid, prop_scroll_distance, 0, 3, | | |||
724 | False, XA_INTEGER, &type_return, &format_return, | | |||
725 | &num_items_return, &bytes_after_return, &data2); | | |||
726 | // negate scroll distance | | |||
727 | if (status == Success && type_return == XA_INTEGER && | | |||
728 | format_return == 32 && num_items_return == 3) { | | |||
729 | int32_t *vals = (int32_t*)data2; | | |||
730 | for (unsigned long i=0; i<num_items_return; ++i) { | | |||
731 | int32_t val = *(vals+i); | | |||
732 | *(vals+i) = (int32_t) (reverseScrollPolarity ? -abs(val) : abs(val)); | | |||
733 | } | | |||
734 | XIChangeProperty(dpy, deviceid, prop_scroll_distance, XA_INTEGER, | | |||
735 | 32, XIPropModeReplace, data2, 3); | | |||
736 | } | | |||
737 | } else { // wheel emulation used, reverse wheel axes | | |||
738 | status = XIGetProperty(dpy, deviceid, prop_wheel_emulation_axes, 0, 4, | | |||
739 | False, XA_INTEGER, &type_return, &format_return, | | |||
740 | &num_items_return, &bytes_after_return, &data2); | | |||
741 | if (status == Success && type_return == XA_INTEGER && | | |||
742 | format_return == 8 && num_items_return == 4) { | | |||
743 | // when scroll direction is not reversed, | | |||
744 | // up button id should be smaller than down button id, | | |||
745 | // up/left are odd elements, down/right are even elements | | |||
746 | for (int i=0; i<2; ++i) { | | |||
747 | unsigned char odd = *(data2 + i*2); | | |||
748 | unsigned char even = *(data2 + i*2+1); | | |||
749 | unsigned char max_elem = std::max(odd, even); | | |||
750 | unsigned char min_elem = std::min(odd, even); | | |||
751 | *(data2 + i * 2) = reverseScrollPolarity ? max_elem : min_elem; | | |||
752 | *(data2 + i * 2 + 1) = reverseScrollPolarity ? min_elem : max_elem; | | |||
753 | } | | |||
754 | XIChangeProperty(dpy, deviceid, prop_wheel_emulation_axes, XA_INTEGER, | | |||
755 | 8, XIPropModeReplace, data2, 4); | | |||
756 | } | | |||
757 | } | | |||
758 | | ||||
759 | if (data != NULL) { XFree(data); } | | |||
760 | if (data2 != NULL) { XFree(data2); } | | |||
761 | } | | |||
762 | } | | |||
763 | XIFreeDeviceInfo(info); | | |||
764 | m_handedNeedsApply = false; | | |||
765 | } | | |||
766 | } | | |||
767 | | ||||
768 | void MouseSettings::save(KConfig *config) | | |||
769 | { | | |||
770 | KSharedConfig::Ptr kcminputProfile = KSharedConfig::openConfig("kcminputrc"); | | |||
771 | KConfigGroup kcminputGroup(kcminputProfile, "Mouse"); | | |||
772 | kcminputGroup.writeEntry("Acceleration",accelRate); | | |||
773 | kcminputGroup.writeEntry("Threshold",thresholdMove); | | |||
774 | if (handed == RIGHT_HANDED) | | |||
775 | kcminputGroup.writeEntry("MouseButtonMapping",QString("RightHanded")); | | |||
776 | else | | |||
777 | kcminputGroup.writeEntry("MouseButtonMapping",QString("LeftHanded")); | | |||
778 | kcminputGroup.writeEntry("ReverseScrollPolarity", reverseScrollPolarity); | | |||
779 | kcminputGroup.sync(); | | |||
780 | | ||||
781 | KSharedConfig::Ptr profile = KSharedConfig::openConfig("kdeglobals"); | | |||
782 | KConfigGroup group(profile, "KDE"); | | |||
783 | group.writeEntry("DoubleClickInterval", doubleClickInterval, KConfig::Persistent); | | |||
784 | group.writeEntry("StartDragTime", dragStartTime, KConfig::Persistent); | | |||
785 | group.writeEntry("StartDragDist", dragStartDist, KConfig::Persistent); | | |||
786 | group.writeEntry("WheelScrollLines", wheelScrollLines, KConfig::Persistent); | | |||
787 | group.writeEntry("SingleClick", singleClick, KConfig::Persistent); | | |||
788 | | ||||
789 | group.sync(); | | |||
790 | config->sync(); | | |||
791 | | ||||
792 | Kdelibs4SharedConfig::syncConfigGroup(QLatin1String("Mouse"), "kcminputrc"); | | |||
793 | Kdelibs4SharedConfig::syncConfigGroup(QLatin1String("KDE"), "kdeglobals"); | | |||
794 | | ||||
795 | KGlobalSettings::self()->emitChange(KGlobalSettings::SettingsChanged, KGlobalSettings::SETTINGS_MOUSE); | | |||
796 | } | | |||
797 | | ||||
798 | void MouseConfig::slotScrollPolarityChanged() | 373 | void MouseConfig::slotScrollPolarityChanged() | ||
799 | { | 374 | { | ||
800 | settings->m_handedNeedsApply = true; | 375 | settings->m_handedNeedsApply = true; | ||
801 | } | 376 | } | ||
802 | 377 | | |||
803 | #include "mouse.moc" | 378 | #include "mouse.moc" |