xref: /haiku/src/preferences/input/MouseSettings.cpp (revision a127b88ecbfab58f64944c98aa47722a18e363b2)
1 /*
2  * Copyright 2019, Haiku, Inc.
3  * Distributed under the terms of the MIT License.
4  *
5  * Author:
6  *		Preetpal Kaur <preetpalok123@gmail.com>
7  */
8 
9 
10 #include "MouseSettings.h"
11 
12 #include <File.h>
13 #include <FindDirectory.h>
14 #include <Path.h>
15 #include <String.h>
16 #include <View.h>
17 
18 #include <stdio.h>
19 
20 
21 // The R5 settings file differs from that of Haiku;
22 // the latter maps 16 different mouse buttons
23 #define R5_COMPATIBLE 0
24 
25 static const bigtime_t kDefaultClickSpeed = 500000;
26 static const int32 kDefaultMouseSpeed = 65536;
27 static const int32 kDefaultMouseType = 3; // 3 button mouse
28 static const int32 kDefaultAccelerationFactor = 65536;
29 static const bool kDefaultAcceptFirstClick = true;
30 
31 
32 MouseSettings::MouseSettings(BString name)
33 	:
34 	fName(name)
35 {
36 	if (_RetrieveSettings() != B_OK)
37 		Defaults();
38 
39 	fOriginalSettings = fSettings;
40 	fOriginalMode = fMode;
41 	fOriginalFocusFollowsMouseMode = fFocusFollowsMouseMode;
42 	fOriginalAcceptFirstClick = fAcceptFirstClick;
43 }
44 
45 
46 MouseSettings::MouseSettings(mouse_settings settings, BString name)
47 	:
48 	fSettings(settings)
49 {
50 	fName = name;
51 
52 #ifdef DEBUG
53 	Dump();
54 #endif
55 
56 	// These are not stored in mouse_settings, get the current values from
57 	// app_server
58 	// FIXME these should be moved out of the MouseSettings class, since they
59 	// are not specific to each mouse, but are global settings.
60 	fMode = mouse_mode();
61 	fFocusFollowsMouseMode = focus_follows_mouse_mode();
62 	fAcceptFirstClick = accept_first_click();
63 
64 	fOriginalSettings = fSettings;
65 	fOriginalMode = fMode;
66 	fOriginalFocusFollowsMouseMode = fFocusFollowsMouseMode;
67 	fOriginalAcceptFirstClick = fAcceptFirstClick;
68 }
69 
70 
71 MouseSettings::~MouseSettings()
72 {
73 }
74 
75 
76 status_t
77 MouseSettings::_GetSettingsPath(BPath& path)
78 {
79 	status_t status = find_directory(B_USER_SETTINGS_DIRECTORY, &path);
80 	if (status < B_OK)
81 		return status;
82 
83 	path.Append(mouse_settings_file);
84 	return B_OK;
85 }
86 
87 
88 status_t
89 MouseSettings::_RetrieveSettings()
90 {
91 	// retrieve current values
92 	if (get_mouse_map(&fSettings.map) != B_OK)
93 		return B_ERROR;
94 	if (get_click_speed(&fSettings.click_speed) != B_OK)
95 		return B_ERROR;
96 	if (get_mouse_speed(fName, &fSettings.accel.speed) != B_OK)
97 		return B_ERROR;
98 	if (get_mouse_acceleration(fName, &fSettings.accel.accel_factor) != B_OK)
99 		return B_ERROR;
100 	if (get_mouse_type(fName, &fSettings.type) != B_OK)
101 		return B_ERROR;
102 
103 	fMode = mouse_mode();
104 	fFocusFollowsMouseMode = focus_follows_mouse_mode();
105 	fAcceptFirstClick = accept_first_click();
106 
107 	return B_OK;
108 }
109 
110 
111 status_t
112 MouseSettings::_LoadLegacySettings()
113 {
114 	BPath path;
115 	if (_GetSettingsPath(path) < B_OK)
116 		return B_ERROR;
117 
118 	BFile file(path.Path(), B_READ_ONLY);
119 	if (file.InitCheck() < B_OK)
120 		return B_ERROR;
121 
122 	// Read the settings from the file
123 	file.Read((void*)&fSettings, sizeof(mouse_settings));
124 
125 #ifdef DEBUG
126 	Dump();
127 #endif
128 
129 	return B_OK;
130 }
131 
132 
133 #ifdef DEBUG
134 void
135 MouseSettings::Dump()
136 {
137 	printf("type:\t\t%" B_PRId32 " button mouse\n", fSettings.type);
138 	for (int i = 0; i < 5; i++)
139 		printf("button[%d]: %" B_PRId32 "\n", i, fSettings.map.button[i]);
140 	printf("click speed:\t%" B_PRId64 "\n", fSettings.click_speed);
141 	printf("accel:\t\t%s\n", fSettings.accel.enabled ? "enabled" : "disabled");
142 	printf("accel factor:\t%" B_PRId32 "\n", fSettings.accel.accel_factor);
143 	printf("speed:\t\t%" B_PRId32 "\n", fSettings.accel.speed);
144 
145 	const char* mode = "unknown";
146 	switch (fMode) {
147 		case B_NORMAL_MOUSE:
148 			mode = "click to focus and raise";
149 			break;
150 		case B_CLICK_TO_FOCUS_MOUSE:
151 			mode = "click to focus";
152 			break;
153 		case B_FOCUS_FOLLOWS_MOUSE:
154 			mode = "focus follows mouse";
155 			break;
156 	}
157 	printf("mouse mode:\t%s\n", mode);
158 
159 	const char* focus_follows_mouse_mode = "unknown";
160 	switch (fFocusFollowsMouseMode) {
161 		case B_NORMAL_FOCUS_FOLLOWS_MOUSE:
162 			focus_follows_mouse_mode = "normal";
163 			break;
164 		case B_WARP_FOCUS_FOLLOWS_MOUSE:
165 			focus_follows_mouse_mode = "warp";
166 			break;
167 		case B_INSTANT_WARP_FOCUS_FOLLOWS_MOUSE:
168 			focus_follows_mouse_mode = "instant warp";
169 			break;
170 	}
171 	printf("focus follows mouse mode:\t%s\n", focus_follows_mouse_mode);
172 	printf("accept first click:\t%s\n",
173 		fAcceptFirstClick ? "enabled" : "disabled");
174 }
175 #endif
176 
177 
178 // Resets the settings to the system defaults
179 void
180 MouseSettings::Defaults()
181 {
182 	SetClickSpeed(kDefaultClickSpeed);
183 	SetMouseSpeed(kDefaultMouseSpeed);
184 	SetMouseType(kDefaultMouseType);
185 	SetAccelerationFactor(kDefaultAccelerationFactor);
186 	SetMouseMode(B_NORMAL_MOUSE);
187 	SetFocusFollowsMouseMode(B_NORMAL_FOCUS_FOLLOWS_MOUSE);
188 	SetAcceptFirstClick(kDefaultAcceptFirstClick);
189 
190 	mouse_map map;
191 	if (get_mouse_map(&map) != B_OK) {
192 		// Set some default values
193 		map.button[0] = B_PRIMARY_MOUSE_BUTTON;
194 		map.button[1] = B_SECONDARY_MOUSE_BUTTON;
195 		map.button[2] = B_TERTIARY_MOUSE_BUTTON;
196 		map.button[3] = B_MOUSE_BUTTON(4);
197 		map.button[4] = B_MOUSE_BUTTON(5);
198 		map.button[5] = B_MOUSE_BUTTON(6);
199 	}
200 	SetMapping(map);
201 }
202 
203 
204 // Checks if the settings are different then the system defaults
205 bool
206 MouseSettings::IsDefaultable()
207 {
208 	return fSettings.click_speed != kDefaultClickSpeed
209 		|| fSettings.accel.speed != kDefaultMouseSpeed
210 		|| fSettings.type != kDefaultMouseType
211 		|| fSettings.accel.accel_factor != kDefaultAccelerationFactor
212 		|| fMode != B_NORMAL_MOUSE
213 		|| fFocusFollowsMouseMode != B_NORMAL_FOCUS_FOLLOWS_MOUSE
214 		|| fAcceptFirstClick != kDefaultAcceptFirstClick
215 		|| fSettings.map.button[0] != B_PRIMARY_MOUSE_BUTTON
216 		|| fSettings.map.button[1] != B_SECONDARY_MOUSE_BUTTON
217 		|| fSettings.map.button[2] != B_TERTIARY_MOUSE_BUTTON
218 		|| fSettings.map.button[3] != B_MOUSE_BUTTON(4)
219 		|| fSettings.map.button[4] != B_MOUSE_BUTTON(5)
220 		|| fSettings.map.button[5] != B_MOUSE_BUTTON(6);
221 }
222 
223 
224 //	Reverts to the active settings at program startup
225 void
226 MouseSettings::Revert()
227 {
228 	SetClickSpeed(fOriginalSettings.click_speed);
229 	SetMouseSpeed(fOriginalSettings.accel.speed);
230 	SetMouseType(fOriginalSettings.type);
231 	SetAccelerationFactor(fOriginalSettings.accel.accel_factor);
232 	SetMouseMode(fOriginalMode);
233 	SetFocusFollowsMouseMode(fOriginalFocusFollowsMouseMode);
234 	SetAcceptFirstClick(fOriginalAcceptFirstClick);
235 
236 	SetMapping(fOriginalSettings.map);
237 }
238 
239 
240 // Checks if the settings are different then the original settings
241 bool
242 MouseSettings::IsRevertable()
243 {
244 	return fSettings.click_speed != fOriginalSettings.click_speed
245 		|| fSettings.accel.speed != fOriginalSettings.accel.speed
246 		|| fSettings.type != fOriginalSettings.type
247 		|| fSettings.accel.accel_factor != fOriginalSettings.accel.accel_factor
248 		|| fMode != fOriginalMode
249 		|| fFocusFollowsMouseMode != fOriginalFocusFollowsMouseMode
250 		|| fAcceptFirstClick != fOriginalAcceptFirstClick
251 		|| fSettings.map.button[0] != fOriginalSettings.map.button[0]
252 		|| fSettings.map.button[1] != fOriginalSettings.map.button[1]
253 		|| fSettings.map.button[2] != fOriginalSettings.map.button[2]
254 		|| fSettings.map.button[3] != fOriginalSettings.map.button[3]
255 		|| fSettings.map.button[4] != fOriginalSettings.map.button[4]
256 		|| fSettings.map.button[5] != fOriginalSettings.map.button[5];
257 }
258 
259 
260 void
261 MouseSettings::SetMouseType(int32 type)
262 {
263 	if (set_mouse_type(fName, type) == B_OK)
264 		fSettings.type = type;
265 }
266 
267 
268 bigtime_t
269 MouseSettings::ClickSpeed() const
270 {
271 	return 1000000LL - fSettings.click_speed;
272 		// to correct the Sliders 0-100000 scale
273 }
274 
275 
276 void
277 MouseSettings::SetClickSpeed(bigtime_t clickSpeed)
278 {
279 	clickSpeed = 1000000LL - clickSpeed;
280 
281 	if (set_click_speed(clickSpeed) == B_OK)
282 		fSettings.click_speed = clickSpeed;
283 }
284 
285 
286 void
287 MouseSettings::SetMouseSpeed(int32 speed)
288 {
289 	if (set_mouse_speed(fName, speed) == B_OK)
290 		fSettings.accel.speed = speed;
291 }
292 
293 
294 void
295 MouseSettings::SetAccelerationFactor(int32 factor)
296 {
297 	if (set_mouse_acceleration(fName, factor) == B_OK)
298 		fSettings.accel.accel_factor = factor;
299 }
300 
301 
302 uint32
303 MouseSettings::Mapping(int32 index) const
304 {
305 	return fSettings.map.button[index];
306 }
307 
308 
309 void
310 MouseSettings::Mapping(mouse_map& map) const
311 {
312 	map = fSettings.map;
313 }
314 
315 
316 void
317 MouseSettings::SetMapping(int32 index, uint32 button)
318 {
319 	fSettings.map.button[index] = button;
320 	set_mouse_map(&fSettings.map);
321 }
322 
323 
324 void
325 MouseSettings::SetMapping(mouse_map& map)
326 {
327 	if (set_mouse_map(&map) == B_OK)
328 		fSettings.map = map;
329 }
330 
331 
332 void
333 MouseSettings::SetMouseMode(mode_mouse mode)
334 {
335 	set_mouse_mode(mode);
336 	fMode = mode;
337 }
338 
339 
340 void
341 MouseSettings::SetFocusFollowsMouseMode(mode_focus_follows_mouse mode)
342 {
343 	set_focus_follows_mouse_mode(mode);
344 	fFocusFollowsMouseMode = mode;
345 }
346 
347 
348 void
349 MouseSettings::SetAcceptFirstClick(bool accept_first_click)
350 {
351 	set_accept_first_click(accept_first_click);
352 	fAcceptFirstClick = accept_first_click;
353 }
354 
355 
356 mouse_settings*
357 MouseSettings::GetSettings()
358 {
359 	return &fSettings;
360 }
361 
362 
363 MultipleMouseSettings::MultipleMouseSettings()
364 {
365 	fDeprecatedMouseSettings = NULL;
366 	RetrieveSettings();
367 
368 #ifdef DEBUG
369 	Dump();
370 #endif
371 }
372 
373 
374 MultipleMouseSettings::~MultipleMouseSettings()
375 {
376 	SaveSettings();
377 
378 #ifdef DEBUG
379 	Dump();
380 #endif
381 
382 	std::map<BString, MouseSettings*>::iterator itr;
383 	for (itr = fMouseSettingsObject.begin(); itr != fMouseSettingsObject.end();
384 		++itr)
385 		delete itr->second;
386 
387 	delete fDeprecatedMouseSettings;
388 }
389 
390 
391 status_t
392 MultipleMouseSettings::GetSettingsPath(BPath& path)
393 {
394 	status_t status = find_directory(B_USER_SETTINGS_DIRECTORY, &path);
395 	if (status < B_OK)
396 		return status;
397 
398 	path.Append(mouse_settings_file);
399 	return B_OK;
400 }
401 
402 
403 void
404 MultipleMouseSettings::RetrieveSettings()
405 {
406 	// retrieve current values
407 	// also try to load the window position from disk
408 
409 	BPath path;
410 	if (GetSettingsPath(path) < B_OK)
411 		return;
412 
413 	BFile file(path.Path(), B_READ_ONLY);
414 	if (file.InitCheck() < B_OK)
415 		return;
416 
417 	BMessage message;
418 
419 	if (message.Unflatten(&file) == B_OK) {
420 		int i = 0;
421 		BString deviceName;
422 		mouse_settings* settings;
423 		ssize_t size = 0;
424 
425 		while (message.FindString("mouseDevice", i, &deviceName) == B_OK) {
426 			message.FindData(
427 				"mouseSettings", B_ANY_TYPE, i, (const void**)&settings, &size);
428 			MouseSettings* mouseSettings
429 				= new MouseSettings(*settings, deviceName);
430 			fMouseSettingsObject.insert(
431 				std::pair<BString, MouseSettings*>(deviceName, mouseSettings));
432 			i++;
433 		}
434 	} else {
435 		// Does not look like a BMessage, try loading using the old format
436 		fDeprecatedMouseSettings = new MouseSettings("");
437 		if (fDeprecatedMouseSettings->_LoadLegacySettings() != B_OK) {
438 			delete fDeprecatedMouseSettings;
439 			fDeprecatedMouseSettings = NULL;
440 		}
441 	}
442 }
443 
444 
445 status_t
446 MultipleMouseSettings::Archive(BMessage* into, bool deep) const
447 {
448 	std::map<BString, MouseSettings*>::const_iterator itr;
449 	for (itr = fMouseSettingsObject.begin(); itr != fMouseSettingsObject.end();
450 		++itr) {
451 		into->AddString("mouseDevice", itr->first);
452 		into->AddData("mouseSettings", B_ANY_TYPE, itr->second->GetSettings(),
453 			sizeof(*(itr->second->GetSettings())));
454 	}
455 
456 	return B_OK;
457 }
458 
459 
460 status_t
461 MultipleMouseSettings::SaveSettings()
462 {
463 	BPath path;
464 	status_t status = GetSettingsPath(path);
465 	if (status < B_OK)
466 		return status;
467 
468 	BFile file(path.Path(), B_WRITE_ONLY | B_CREATE_FILE | B_ERASE_FILE);
469 	status = file.InitCheck();
470 	if (status != B_OK)
471 		return status;
472 
473 	BMessage message;
474 	Archive(&message, true);
475 	message.Flatten(&file);
476 
477 	return B_OK;
478 }
479 
480 
481 void
482 MultipleMouseSettings::Defaults()
483 {
484 	std::map<BString, MouseSettings*>::iterator itr;
485 	for (itr = fMouseSettingsObject.begin(); itr != fMouseSettingsObject.end();
486 		++itr) {
487 		itr->second->Defaults();
488 	}
489 
490 }
491 
492 
493 #ifdef DEBUG
494 void
495 MultipleMouseSettings::Dump()
496 {
497 	std::map<BString, MouseSettings*>::iterator itr;
498 	for (itr = fMouseSettingsObject.begin(); itr != fMouseSettingsObject.end();
499 		++itr) {
500 		printf("mouse_name:\t%s\n", itr->first.String());
501 		itr->second->Dump();
502 		printf("\n");
503 	}
504 }
505 #endif
506 
507 
508 MouseSettings*
509 MultipleMouseSettings::AddMouseSettings(BString mouse_name)
510 {
511 	if (fDeprecatedMouseSettings != NULL) {
512 		MouseSettings* RetrievedSettings = new(std::nothrow) MouseSettings(
513 			*(fDeprecatedMouseSettings->GetSettings()), mouse_name);
514 
515 		if (RetrievedSettings != NULL) {
516 			fMouseSettingsObject.insert(std::pair<BString, MouseSettings*>(
517 				mouse_name, RetrievedSettings));
518 
519 			return RetrievedSettings;
520 		}
521 	}
522 
523 	MouseSettings* settings = GetMouseSettings(mouse_name);
524 	if (settings)
525 		return settings;
526 
527 	settings = new(std::nothrow) MouseSettings(mouse_name);
528 	if (settings == NULL)
529 		return NULL;
530 
531 	fMouseSettingsObject.insert(
532 		std::pair<BString, MouseSettings*>(mouse_name, settings));
533 	return settings;
534 }
535 
536 
537 MouseSettings*
538 MultipleMouseSettings::GetMouseSettings(BString mouse_name)
539 {
540 	std::map<BString, MouseSettings*>::iterator itr;
541 	itr = fMouseSettingsObject.find(mouse_name);
542 
543 	if (itr != fMouseSettingsObject.end())
544 		return itr->second;
545 	return NULL;
546 }
547