input_device_settings.cc revision eb525c5499e34cc9c4b825d6d9e75bb07cc06ace
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/message_loop.h"
17#include "base/process.h"
18#include "base/process_util.h"
19#include "base/strings/stringprintf.h"
20#include "base/threading/sequenced_worker_pool.h"
21#include "content/public/browser/browser_thread.h"
22
23namespace chromeos {
24namespace system {
25
26namespace {
27
28const char kTpControl[] = "/opt/google/touchpad/tpcontrol";
29const char kMouseControl[] = "/opt/google/mouse/mousecontrol";
30
31bool ScriptExists(const std::string& script) {
32  DCHECK(content::BrowserThread::GetBlockingPool()->RunsTasksOnCurrentThread());
33  return file_util::PathExists(base::FilePath(script));
34}
35
36// Executes the input control script asynchronously, if it exists.
37void ExecuteScriptOnFileThread(const std::vector<std::string>& argv) {
38  DCHECK(content::BrowserThread::GetBlockingPool()->RunsTasksOnCurrentThread());
39  DCHECK(!argv.empty());
40  const std::string& script(argv[0]);
41
42  // Script must exist on device.
43  DCHECK(!base::chromeos::IsRunningOnChromeOS() || ScriptExists(script));
44
45  if (!ScriptExists(script))
46    return;
47
48  base::ProcessHandle handle;
49  base::LaunchProcess(CommandLine(argv), base::LaunchOptions(), &handle);
50  base::EnsureProcessGetsReaped(handle);
51}
52
53void ExecuteScript(int argc, ...) {
54  DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
55  std::vector<std::string> argv;
56  va_list vl;
57  va_start(vl, argc);
58  for (int i = 0; i < argc; ++i) {
59    argv.push_back(va_arg(vl, const char*));
60  }
61  va_end(vl);
62
63  content::BrowserThread::GetBlockingPool()->PostTask(FROM_HERE,
64      base::Bind(&ExecuteScriptOnFileThread, argv));
65}
66
67void SetPointerSensitivity(const char* script, int value) {
68  DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
69  DCHECK(value >= kMinPointerSensitivity && value <= kMaxPointerSensitivity);
70  ExecuteScript(
71      3, script, "sensitivity", base::StringPrintf("%d", value).c_str());
72}
73
74void SetTPControl(const char* control, bool enabled) {
75  ExecuteScript(3, kTpControl, control, enabled ? "on" : "off");
76}
77
78void DeviceExistsBlockingPool(const char* script, bool* exists) {
79  DCHECK(content::BrowserThread::GetBlockingPool()->RunsTasksOnCurrentThread());
80  *exists = false;
81  if (!ScriptExists(script))
82    return;
83
84  std::vector<std::string> argv;
85  argv.push_back(script);
86  argv.push_back("status");
87  std::string output;
88  // Output is empty if the device is not found.
89  *exists = base::GetAppOutput(CommandLine(argv), &output) && !output.empty();
90  DVLOG(1) << "DeviceExistsBlockingPool:" << script << "=" << *exists;
91}
92
93void RunCallbackUIThread(bool* exists, const DeviceExistsCallback& callback) {
94  DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
95  DVLOG(1) << "RunCallbackUIThread " << *exists;
96  callback.Run(*exists);
97}
98
99void DeviceExists(const char* script, const DeviceExistsCallback& callback) {
100  DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
101
102  bool* exists = new bool(false);
103  content::BrowserThread::GetBlockingPool()->PostTaskAndReply(FROM_HERE,
104      base::Bind(&DeviceExistsBlockingPool, script, exists),
105      base::Bind(&RunCallbackUIThread, base::Owned(exists), callback));
106}
107
108}  // namespace
109
110namespace touchpad_settings {
111
112void TouchpadExists(const DeviceExistsCallback& callback) {
113  DeviceExists(kTpControl, callback);
114}
115
116// Sets the touchpad sensitivity in the range [1, 5].
117void SetSensitivity(int value) {
118  DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
119  SetPointerSensitivity(kTpControl, value);
120}
121
122void SetTapToClick(bool enabled) {
123  DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
124  SetTPControl("taptoclick", enabled);
125}
126
127void SetThreeFingerClick(bool enabled) {
128  DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
129
130  SetTPControl("three_finger_click", enabled);
131  // For Alex/ZGB.
132  SetTPControl("t5r2_three_finger_click", enabled);
133}
134
135void SetThreeFingerSwipe(bool enabled) {
136  DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
137  SetTPControl("three_finger_swipe", enabled);
138}
139
140void SetTapDragging(bool enabled) {
141  DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
142  SetTPControl("tap_dragging", enabled);
143}
144
145}  // namespace touchpad_settings
146
147namespace mouse_settings {
148
149void MouseExists(const DeviceExistsCallback& callback) {
150  DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
151  DeviceExists(kMouseControl, callback);
152}
153
154// Sets the touchpad sensitivity in the range [1, 5].
155void SetSensitivity(int value) {
156  DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
157  SetPointerSensitivity(kMouseControl, value);
158}
159
160void SetPrimaryButtonRight(bool right) {
161  DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
162  ExecuteScript(3, kMouseControl, "swap_left_right", right ? "1" : "0");
163}
164
165}  // namespace mouse_settings
166
167}  // namespace system
168}  // namespace chromeos
169