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