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 25static const bigtime_t kDefaultClickSpeed = 500000; 26static const int32 kDefaultMouseSpeed = 65536; 27static const int32 kDefaultMouseType = 3; // 3 button mouse 28static const int32 kDefaultAccelerationFactor = 65536; 29static const bool kDefaultAcceptFirstClick = true; 30 31 32MouseSettings::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 46MouseSettings::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 71MouseSettings::~MouseSettings() 72{ 73} 74 75 76status_t 77MouseSettings::_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 88status_t 89MouseSettings::_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 111status_t 112MouseSettings::_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 134void 135MouseSettings::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 179void 180MouseSettings::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 205bool 206MouseSettings::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 225void 226MouseSettings::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 241bool 242MouseSettings::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 260void 261MouseSettings::SetMouseType(int32 type) 262{ 263 if (set_mouse_type(fName, type) == B_OK) 264 fSettings.type = type; 265} 266 267 268bigtime_t 269MouseSettings::ClickSpeed() const 270{ 271 return 1000000LL - fSettings.click_speed; 272 // to correct the Sliders 0-100000 scale 273} 274 275 276void 277MouseSettings::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 286void 287MouseSettings::SetMouseSpeed(int32 speed) 288{ 289 if (set_mouse_speed(fName, speed) == B_OK) 290 fSettings.accel.speed = speed; 291} 292 293 294void 295MouseSettings::SetAccelerationFactor(int32 factor) 296{ 297 if (set_mouse_acceleration(fName, factor) == B_OK) 298 fSettings.accel.accel_factor = factor; 299} 300 301 302uint32 303MouseSettings::Mapping(int32 index) const 304{ 305 return fSettings.map.button[index]; 306} 307 308 309void 310MouseSettings::Mapping(mouse_map& map) const 311{ 312 map = fSettings.map; 313} 314 315 316void 317MouseSettings::SetMapping(int32 index, uint32 button) 318{ 319 fSettings.map.button[index] = button; 320 set_mouse_map(&fSettings.map); 321} 322 323 324void 325MouseSettings::SetMapping(mouse_map& map) 326{ 327 if (set_mouse_map(&map) == B_OK) 328 fSettings.map = map; 329} 330 331 332void 333MouseSettings::SetMouseMode(mode_mouse mode) 334{ 335 set_mouse_mode(mode); 336 fMode = mode; 337} 338 339 340void 341MouseSettings::SetFocusFollowsMouseMode(mode_focus_follows_mouse mode) 342{ 343 set_focus_follows_mouse_mode(mode); 344 fFocusFollowsMouseMode = mode; 345} 346 347 348void 349MouseSettings::SetAcceptFirstClick(bool accept_first_click) 350{ 351 set_accept_first_click(accept_first_click); 352 fAcceptFirstClick = accept_first_click; 353} 354 355 356mouse_settings* 357MouseSettings::GetSettings() 358{ 359 return &fSettings; 360} 361 362 363MultipleMouseSettings::MultipleMouseSettings() 364{ 365 fDeprecatedMouseSettings = NULL; 366 RetrieveSettings(); 367 368#ifdef DEBUG 369 Dump(); 370#endif 371} 372 373 374MultipleMouseSettings::~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 391status_t 392MultipleMouseSettings::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 403void 404MultipleMouseSettings::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 445status_t 446MultipleMouseSettings::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 460status_t 461MultipleMouseSettings::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 481void 482MultipleMouseSettings::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 494void 495MultipleMouseSettings::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 508MouseSettings* 509MultipleMouseSettings::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 537MouseSettings* 538MultipleMouseSettings::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