Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(52)

Side by Side Diff: remoting/android/java/src/org/chromium/chromoting/InputInjectorWrapper.java

Issue 2066683003: [Chromoting] Add InputInjector and InputInjectorWrapper for easy unittesting (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Suppress FindBugs warning of FE_FLOATING_POINT_EQUALITY Created 4 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 // Copyright 2016 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 package org.chromium.chromoting;
6
7 import android.graphics.Point;
8 import android.view.KeyEvent;
9 import android.view.MotionEvent;
10
11 import org.chromium.chromoting.jni.TouchEventData;
12
13 import java.util.ArrayList;
14 import java.util.List;
15 import java.util.Set;
16 import java.util.TreeSet;
17
18 /**
19 * A set of functions to send users' activities, which are represented by Androi d classes, to
20 * remove host machine. This class uses a {@link InputInjector} to do the real i njections.
21 */
22 public final class InputInjectorWrapper {
Sergey Ulanov 2016/06/22 06:39:01 I don't think this is the best name for this class
Hzj_jie 2016/06/22 23:18:54 Done.
23 private static final int[] CTRL_ALT_DEL = {
24 KeyEvent.KEYCODE_CTRL_LEFT, KeyEvent.KEYCODE_ALT_LEFT, KeyEvent.KEYC ODE_FORWARD_DEL,
25 };
26
27 private final InputInjector mInjector;
28
29 /** Set of pressed keys for which we've sent TextEvent. */
30 private final Set<Integer> mPressedTextKeys;
31
32 public InputInjectorWrapper(InputInjector injector) {
33 Preconditions.notNull(injector);
34 mInjector = injector;
35 mPressedTextKeys = new TreeSet<>();
36 }
37
38 public void sendMouseEvent(Point pos, int button, boolean down) {
39 Preconditions.isTrue(button == TouchInputHandler.BUTTON_UNDEFINED
40 || button == TouchInputHandler.BUTTON_LEFT
41 || button == TouchInputHandler.BUTTON_MIDDLE
42 || button == TouchInputHandler.BUTTON_RIGHT);
43 mInjector.sendMouseEvent(pos.x, pos.y, button, down);
44 }
45
46 public void sendMouseDown(Point pos, int button) {
47 sendMouseEvent(pos, button, true);
48 }
49
50 public void sendMouseUp(Point pos, int button) {
51 sendMouseEvent(pos, button, false);
52 }
53
54 public void sendMouseClick(Point pos, int button) {
55 sendMouseDown(pos, button);
56 sendMouseUp(pos, button);
57 }
58
59 public void sendCursorMove(Point pos) {
60 sendMouseUp(pos, TouchInputHandler.BUTTON_UNDEFINED);
61 }
62
63 // TODO (zijiehe): This function will be eventually removed after {@link Inp utStrategyInterface}
Lambros 2016/06/22 01:43:14 No space between TODO and (.
Hzj_jie 2016/06/22 23:18:54 Done.
64 // has been deprecated.
65 public void sendCursorMove(int x, int y) {
66 sendCursorMove(new Point(x, y));
67 }
68
69 public void sendMouseWheelEvent(float distanceX, float distanceY) {
70 mInjector.sendMouseWheelEvent((int) distanceX, (int) distanceY);
71 }
72
73 public void sendReverseMouseWheelEvent(float distanceX, float distanceY) {
74 sendMouseWheelEvent(-distanceX, -distanceY);
75 }
76
77 /**
78 * Extracts the touch point data from a MotionEvent, converts each point int o a marshallable
79 * object and passes the set of points to the JNI layer to be transmitted to the remote host.
80 *
81 * @param event The event to send to the remote host for injection. NOTE: T his object must be
82 * updated to represent the remote machine's coordinate system before calling this
83 * function.
84 */
85 public void sendTouchEvent(MotionEvent event) {
86 int action = event.getActionMasked();
87 TouchEventData.EventType touchEventType = TouchEventData.EventType.fromM askedAction(action);
88 List<TouchEventData> touchEventList = new ArrayList<TouchEventData>();
89
90 if (action == MotionEvent.ACTION_MOVE) {
91 // In order to process all of the events associated with an ACTION_M OVE event, we need
92 // to walk the list of historical events in order and add each event to our list, then
93 // retrieve the current move event data.
94 int pointerCount = event.getPointerCount();
95 int historySize = event.getHistorySize();
96 for (int h = 0; h < historySize; ++h) {
97 for (int p = 0; p < pointerCount; ++p) {
98 touchEventList.add(new TouchEventData(event.getPointerId(p),
99 event.getHistoricalX(p, h), event.getHistoricalY(p, h),
100 event.getHistoricalSize(p, h), event.getHistoricalSi ze(p, h),
101 event.getHistoricalOrientation(p, h),
102 event.getHistoricalPressure(p, h)));
103 }
104 }
105
106 for (int p = 0; p < pointerCount; p++) {
107 touchEventList.add(new TouchEventData(event.getPointerId(p), eve nt.getX(p),
108 event.getY(p), event.getSize(p), event.getSize(p), event .getOrientation(p),
109 event.getPressure(p)));
110 }
111 } else {
112 // For all other events, we only want to grab the current/active poi nter. The event
113 // contains a list of every active pointer but passing all of of the se to the host can
114 // cause confusion on the remote OS side and result in broken touch gestures.
115 int activePointerIndex = event.getActionIndex();
116 touchEventList.add(new TouchEventData(event.getPointerId(activePoint erIndex),
117 event.getX(activePointerIndex), event.getY(activePointerInde x),
118 event.getSize(activePointerIndex), event.getSize(activePoint erIndex),
119 event.getOrientation(activePointerIndex),
120 event.getPressure(activePointerIndex)));
121 }
122
123 if (!touchEventList.isEmpty()) {
124 mInjector.sendTouchEvent(touchEventType, touchEventList.toArray(new TouchEventData[0]));
125 }
126 }
127
128 /**
129 * Converts the {@link KeyEvent} into low-level events and sends them to the host as either
130 * key-events or text-events. This contains some logic for handling some spe cial keys, and
131 * avoids sending a key-up event for a key that was previously injected as a text-event.
132 */
133 public boolean sendKeyEvent(KeyEvent event) {
134 int keyCode = event.getKeyCode();
135 boolean pressed = event.getAction() == KeyEvent.ACTION_DOWN;
136
137 // Events received from software keyboards generate TextEvent in two
138 // cases:
139 // 1. This is an ACTION_MULTIPLE event.
140 // 2. Ctrl, Alt and Meta are not pressed.
141 // This ensures that on-screen keyboard always injects input that
142 // correspond to what user sees on the screen, while physical keyboard
143 // acts as if it is connected to the remote host.
144 if (event.getAction() == KeyEvent.ACTION_MULTIPLE) {
145 mInjector.sendTextEvent(event.getCharacters());
146 return true;
147 }
148
149 // For Enter getUnicodeChar() returns 10 (line feed), but we still
150 // want to send it as KeyEvent.
151 int unicode = keyCode != KeyEvent.KEYCODE_ENTER ? event.getUnicodeChar() : 0;
152
153 boolean no_modifiers =
154 !event.isAltPressed() && !event.isCtrlPressed() && !event.isMeta Pressed();
155
156 if (pressed && unicode != 0 && no_modifiers) {
157 mPressedTextKeys.add(keyCode);
158 int[] codePoints = {unicode};
159 mInjector.sendTextEvent(new String(codePoints, 0, 1));
160 return true;
161 }
162
163 if (!pressed && mPressedTextKeys.contains(keyCode)) {
164 mPressedTextKeys.remove(keyCode);
165 return true;
166 }
167
168 switch (keyCode) {
169 // KEYCODE_AT, KEYCODE_POUND, KEYCODE_STAR and KEYCODE_PLUS are
170 // deprecated, but they still need to be here for older devices and
171 // third-party keyboards that may still generate these events. See
172 // https://source.android.com/devices/input/keyboard-devices.html#le gacy-unsupported-keys
173 case KeyEvent.KEYCODE_AT:
174 mInjector.sendKeyEvent(0, KeyEvent.KEYCODE_SHIFT_LEFT, pressed);
175 mInjector.sendKeyEvent(0, KeyEvent.KEYCODE_2, pressed);
176 return true;
177
178 case KeyEvent.KEYCODE_POUND:
179 mInjector.sendKeyEvent(0, KeyEvent.KEYCODE_SHIFT_LEFT, pressed);
180 mInjector.sendKeyEvent(0, KeyEvent.KEYCODE_3, pressed);
181 return true;
182
183 case KeyEvent.KEYCODE_STAR:
184 mInjector.sendKeyEvent(0, KeyEvent.KEYCODE_SHIFT_LEFT, pressed);
185 mInjector.sendKeyEvent(0, KeyEvent.KEYCODE_8, pressed);
186 return true;
187
188 case KeyEvent.KEYCODE_PLUS:
189 mInjector.sendKeyEvent(0, KeyEvent.KEYCODE_SHIFT_LEFT, pressed);
190 mInjector.sendKeyEvent(0, KeyEvent.KEYCODE_EQUALS, pressed);
191 return true;
192
193 default:
194 // We try to send all other key codes to the host directly.
195 return mInjector.sendKeyEvent(0, keyCode, pressed);
196 }
197 }
198
199 public void sendKeyDown(int keyCode) {
200 mInjector.sendKeyEvent(0, keyCode, true);
201 }
202
203 public void sendKeyUp(int keyCode) {
204 mInjector.sendKeyEvent(0, keyCode, false);
205 }
206
207 /**
208 * Sends key combinations such as Ctrl-Alt-Del. This injects a key-down even t for every key in
209 * the list, and then injects the corresponding key-up events.
210 */
211 public void sendKeysPress(int[] keyCodes) {
212 if (keyCodes != null && keyCodes.length > 0) {
Lambros 2016/06/22 01:43:14 I don't think you need a null check, and the lengt
Hzj_jie 2016/06/22 23:18:54 I believe Java allows an array to be null. And for
Lambros 2016/06/23 01:40:09 Arguably, it can be better to crash than to silent
Hzj_jie 2016/06/23 18:03:23 Done.
213 for (int keyCode : keyCodes) {
214 sendKeyDown(keyCode);
215 }
216 for (int keyCode : keyCodes) {
217 sendKeyUp(keyCode);
218 }
219 }
220 }
221
222 public void sendCtrlAltDel() {
223 sendKeysPress(CTRL_ALT_DEL);
224 }
225 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698