input_device_settings.cc revision ca12bfac764ba476d6cd062bf1dde12cc64c3f40
1// Copyright (c) 2012 The Chromium Authors. All rights reserved. 2// Use of this source code is governed by a BSD-style license that can be 3// found in the LICENSE file. 4 5#include "chrome/browser/chromeos/system/input_device_settings.h" 6 7#include <stdarg.h> 8#include <string> 9#include <vector> 10 11#include "base/bind.h" 12#include "base/chromeos/chromeos_version.h" 13#include "base/command_line.h" 14#include "base/file_util.h" 15#include "base/files/file_path.h" 16#include "base/memory/ref_counted.h" 17#include "base/message_loop/message_loop.h" 18#include "base/process.h" 19#include "base/process_util.h" 20#include "base/strings/stringprintf.h" 21#include "base/task_runner.h" 22#include "base/threading/sequenced_worker_pool.h" 23#include "content/public/browser/browser_thread.h" 24 25namespace chromeos { 26namespace system { 27 28namespace { 29 30const char kTpControl[] = "/opt/google/touchpad/tpcontrol"; 31const char kMouseControl[] = "/opt/google/mouse/mousecontrol"; 32 33typedef base::RefCountedData<bool> RefCountedBool; 34 35bool ScriptExists(const std::string& script) { 36 DCHECK(content::BrowserThread::GetBlockingPool()->RunsTasksOnCurrentThread()); 37 return base::PathExists(base::FilePath(script)); 38} 39 40// Executes the input control script asynchronously, if it exists. 41void ExecuteScriptOnFileThread(const std::vector<std::string>& argv) { 42 DCHECK(content::BrowserThread::GetBlockingPool()->RunsTasksOnCurrentThread()); 43 DCHECK(!argv.empty()); 44 const std::string& script(argv[0]); 45 46 // Script must exist on device. 47 DCHECK(!base::chromeos::IsRunningOnChromeOS() || ScriptExists(script)); 48 49 if (!ScriptExists(script)) 50 return; 51 52 base::ProcessHandle handle; 53 base::LaunchProcess(CommandLine(argv), base::LaunchOptions(), &handle); 54 base::EnsureProcessGetsReaped(handle); 55} 56 57void ExecuteScript(int argc, ...) { 58 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); 59 std::vector<std::string> argv; 60 va_list vl; 61 va_start(vl, argc); 62 for (int i = 0; i < argc; ++i) { 63 argv.push_back(va_arg(vl, const char*)); 64 } 65 va_end(vl); 66 67 // Control scripts can take long enough to cause SIGART during shutdown 68 // (http://crbug.com/261426). Run the blocking pool task with 69 // CONTINUE_ON_SHUTDOWN so it won't be joined when Chrome shuts down. 70 base::SequencedWorkerPool* pool = content::BrowserThread::GetBlockingPool(); 71 scoped_refptr<base::TaskRunner> runner = 72 pool->GetTaskRunnerWithShutdownBehavior( 73 base::SequencedWorkerPool::CONTINUE_ON_SHUTDOWN); 74 runner->PostTask(FROM_HERE, base::Bind(&ExecuteScriptOnFileThread, argv)); 75} 76 77void SetPointerSensitivity(const char* script, int value) { 78 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); 79 DCHECK(value >= kMinPointerSensitivity && value <= kMaxPointerSensitivity); 80 ExecuteScript( 81 3, script, "sensitivity", base::StringPrintf("%d", value).c_str()); 82} 83 84void SetTPControl(const char* control, bool enabled) { 85 ExecuteScript(3, kTpControl, control, enabled ? "on" : "off"); 86} 87 88void DeviceExistsBlockingPool(const char* script, 89 scoped_refptr<RefCountedBool> exists) { 90 DCHECK(content::BrowserThread::GetBlockingPool()->RunsTasksOnCurrentThread()); 91 exists->data = false; 92 if (!ScriptExists(script)) 93 return; 94 95 std::vector<std::string> argv; 96 argv.push_back(script); 97 argv.push_back("status"); 98 std::string output; 99 // Output is empty if the device is not found. 100 exists->data = base::GetAppOutput(CommandLine(argv), &output) && 101 !output.empty(); 102 DVLOG(1) << "DeviceExistsBlockingPool:" << script << "=" << exists->data; 103} 104 105void RunCallbackUIThread(scoped_refptr<RefCountedBool> exists, 106 const DeviceExistsCallback& callback) { 107 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); 108 DVLOG(1) << "RunCallbackUIThread " << exists->data; 109 callback.Run(exists->data); 110} 111 112void DeviceExists(const char* script, const DeviceExistsCallback& callback) { 113 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); 114 115 // One or both of the control scripts can apparently hang during shutdown 116 // (http://crbug.com/255546). Run the blocking pool task with 117 // CONTINUE_ON_SHUTDOWN so it won't be joined when Chrome shuts down. 118 scoped_refptr<RefCountedBool> exists(new RefCountedBool(false)); 119 base::SequencedWorkerPool* pool = content::BrowserThread::GetBlockingPool(); 120 scoped_refptr<base::TaskRunner> runner = 121 pool->GetTaskRunnerWithShutdownBehavior( 122 base::SequencedWorkerPool::CONTINUE_ON_SHUTDOWN); 123 runner->PostTaskAndReply(FROM_HERE, 124 base::Bind(&DeviceExistsBlockingPool, script, exists), 125 base::Bind(&RunCallbackUIThread, exists, callback)); 126} 127 128} // namespace 129 130namespace touchpad_settings { 131 132void TouchpadExists(const DeviceExistsCallback& callback) { 133 DeviceExists(kTpControl, callback); 134} 135 136// Sets the touchpad sensitivity in the range [1, 5]. 137void SetSensitivity(int value) { 138 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); 139 SetPointerSensitivity(kTpControl, value); 140} 141 142void SetTapToClick(bool enabled) { 143 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); 144 SetTPControl("taptoclick", enabled); 145} 146 147void SetThreeFingerClick(bool enabled) { 148 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); 149 150 SetTPControl("three_finger_click", enabled); 151 // For Alex/ZGB. 152 SetTPControl("t5r2_three_finger_click", enabled); 153} 154 155void SetTapDragging(bool enabled) { 156 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); 157 SetTPControl("tap_dragging", enabled); 158} 159 160} // namespace touchpad_settings 161 162namespace mouse_settings { 163 164void MouseExists(const DeviceExistsCallback& callback) { 165 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); 166 DeviceExists(kMouseControl, callback); 167} 168 169// Sets the touchpad sensitivity in the range [1, 5]. 170void SetSensitivity(int value) { 171 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); 172 SetPointerSensitivity(kMouseControl, value); 173} 174 175void SetPrimaryButtonRight(bool right) { 176 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); 177 ExecuteScript(3, kMouseControl, "swap_left_right", right ? "1" : "0"); 178} 179 180} // namespace mouse_settings 181 182} // namespace system 183} // namespace chromeos 184