OLD | NEW |
1 // Copyright 2013 The Chromium Authors. All rights reserved. | 1 // Copyright 2013 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 package org.chromium.chromoting; | 5 package org.chromium.chromoting; |
6 | 6 |
7 import android.annotation.SuppressLint; | 7 import android.annotation.SuppressLint; |
8 import android.app.Activity; | 8 import android.app.Activity; |
9 import android.content.res.Configuration; | 9 import android.content.res.Configuration; |
10 import android.os.Build; | 10 import android.os.Build; |
11 import android.os.Bundle; | 11 import android.os.Bundle; |
| 12 import android.view.KeyCharacterMap; |
12 import android.view.KeyEvent; | 13 import android.view.KeyEvent; |
13 import android.view.Menu; | 14 import android.view.Menu; |
14 import android.view.MenuItem; | 15 import android.view.MenuItem; |
15 import android.view.View; | 16 import android.view.View; |
16 import android.view.inputmethod.InputMethodManager; | 17 import android.view.inputmethod.InputMethodManager; |
17 import android.widget.ImageButton; | 18 import android.widget.ImageButton; |
18 | 19 |
19 import org.chromium.chromoting.jni.JniInterface; | 20 import org.chromium.chromoting.jni.JniInterface; |
20 | 21 |
| 22 import java.util.Set; |
| 23 import java.util.TreeSet; |
| 24 |
21 /** | 25 /** |
22 * A simple screen that does nothing except display a DesktopView and notify it
of rotations. | 26 * A simple screen that does nothing except display a DesktopView and notify it
of rotations. |
23 */ | 27 */ |
24 public class Desktop extends Activity implements View.OnSystemUiVisibilityChange
Listener { | 28 public class Desktop extends Activity implements View.OnSystemUiVisibilityChange
Listener { |
25 /** Web page to be displayed in the Help screen when launched from this acti
vity. */ | 29 /** Web page to be displayed in the Help screen when launched from this acti
vity. */ |
26 private static final String HELP_URL = | 30 private static final String HELP_URL = |
27 "http://support.google.com/chrome/?p=mobile_crd_connecthost"; | 31 "http://support.google.com/chrome/?p=mobile_crd_connecthost"; |
28 | 32 |
29 /** The surface that displays the remote host's desktop feed. */ | 33 /** The surface that displays the remote host's desktop feed. */ |
30 private DesktopView mRemoteHostDesktop; | 34 private DesktopView mRemoteHostDesktop; |
31 | 35 |
32 /** The button used to show the action bar. */ | 36 /** The button used to show the action bar. */ |
33 private ImageButton mOverlayButton; | 37 private ImageButton mOverlayButton; |
34 | 38 |
| 39 /** Set of pressed keys for which we've sent TextEvent. */ |
| 40 private Set<Integer> mPressedTextKeys = new TreeSet<Integer>(); |
| 41 |
35 /** Called when the activity is first created. */ | 42 /** Called when the activity is first created. */ |
36 @Override | 43 @Override |
37 public void onCreate(Bundle savedInstanceState) { | 44 public void onCreate(Bundle savedInstanceState) { |
38 super.onCreate(savedInstanceState); | 45 super.onCreate(savedInstanceState); |
39 setContentView(R.layout.desktop); | 46 setContentView(R.layout.desktop); |
40 mRemoteHostDesktop = (DesktopView)findViewById(R.id.desktop_view); | 47 mRemoteHostDesktop = (DesktopView)findViewById(R.id.desktop_view); |
41 mOverlayButton = (ImageButton)findViewById(R.id.desktop_overlay_button); | 48 mOverlayButton = (ImageButton)findViewById(R.id.desktop_overlay_button); |
42 mRemoteHostDesktop.setDesktop(this); | 49 mRemoteHostDesktop.setDesktop(this); |
43 | 50 |
44 // Ensure the button is initially hidden. | 51 // Ensure the button is initially hidden. |
(...skipping 124 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
169 return super.onOptionsItemSelected(item); | 176 return super.onOptionsItemSelected(item); |
170 } | 177 } |
171 | 178 |
172 /** | 179 /** |
173 * Called once when a keyboard key is pressed, then again when that same key
is released. This | 180 * Called once when a keyboard key is pressed, then again when that same key
is released. This |
174 * is not guaranteed to be notified of all soft keyboard events: certian key
boards might not | 181 * is not guaranteed to be notified of all soft keyboard events: certian key
boards might not |
175 * call it at all, while others might skip it in certain situations (e.g. sw
ipe input). | 182 * call it at all, while others might skip it in certain situations (e.g. sw
ipe input). |
176 */ | 183 */ |
177 @Override | 184 @Override |
178 public boolean dispatchKeyEvent(KeyEvent event) { | 185 public boolean dispatchKeyEvent(KeyEvent event) { |
179 // Send ACTION_MULTIPLE event as TextEvent. | 186 // Send TextEvent in two cases: |
180 // | 187 // 1. This is an ACTION_MULTIPLE event. |
181 // TODO(sergeyu): For all keys on English keyboard Android generates | 188 // 2. The event was generated by on-screen keyboard and Ctrl, Alt and |
182 // ACTION_DOWN/ACTION_UP events, so they are sent as KeyEvent instead of | 189 // Meta are not pressed. |
183 // TextEvent. As result the host may handle them as non-English chars | 190 // This ensures that on-screen keyboard always injects input that |
184 // when it has non-English layout selected, which might be confusing for | 191 // correspond to what user sees on the screen, while physical keyboard |
185 // the user. This code should be fixed to send all text input events as | 192 // acts as if it is connected to the remote host. |
186 // TextEvent, but it cannot be done now because not all hosts support | |
187 // TextEvent. Also, to handle keyboard shortcuts properly this code will | |
188 // need to track the state of modifier keys (such as Ctrl or Alt) and | |
189 // send KeyEvents in the case any of the modifier keys are pressed. | |
190 if (event.getAction() == KeyEvent.ACTION_MULTIPLE) { | 193 if (event.getAction() == KeyEvent.ACTION_MULTIPLE) { |
191 JniInterface.sendTextEvent(event.getCharacters()); | 194 JniInterface.sendTextEvent(event.getCharacters()); |
192 return super.dispatchKeyEvent(event); | 195 return super.dispatchKeyEvent(event); |
193 } | 196 } |
194 | 197 |
195 boolean depressed = event.getAction() == KeyEvent.ACTION_DOWN; | 198 int keyCode = event.getKeyCode(); |
| 199 boolean pressed = event.getAction() == KeyEvent.ACTION_DOWN; |
196 | 200 |
197 switch (event.getKeyCode()) { | 201 // For Enter getUnicodeChar() returns 10 (line feed), but we still |
| 202 // want to send it as KeyEvent. |
| 203 int unicode = keyCode != KeyEvent.KEYCODE_ENTER ? event.getUnicodeChar()
: 0; |
| 204 |
| 205 boolean no_modifiers = !event.isAltPressed() && |
| 206 !event.isCtrlPressed() && !event.isMetaPressed(); |
| 207 |
| 208 if (event.getDeviceId() == KeyCharacterMap.VIRTUAL_KEYBOARD && |
| 209 pressed && unicode != 0 && no_modifiers) { |
| 210 mPressedTextKeys.add(keyCode); |
| 211 int[] codePoints = { unicode }; |
| 212 JniInterface.sendTextEvent(new String(codePoints, 0, 1)); |
| 213 return super.dispatchKeyEvent(event); |
| 214 } |
| 215 |
| 216 if (!pressed && mPressedTextKeys.contains(keyCode)) { |
| 217 mPressedTextKeys.remove(keyCode); |
| 218 return super.dispatchKeyEvent(event); |
| 219 } |
| 220 |
| 221 switch (keyCode) { |
198 case KeyEvent.KEYCODE_AT: | 222 case KeyEvent.KEYCODE_AT: |
199 JniInterface.sendKeyEvent(KeyEvent.KEYCODE_SHIFT_LEFT, depressed
); | 223 JniInterface.sendKeyEvent(KeyEvent.KEYCODE_SHIFT_LEFT, pressed); |
200 JniInterface.sendKeyEvent(KeyEvent.KEYCODE_2, depressed); | 224 JniInterface.sendKeyEvent(KeyEvent.KEYCODE_2, pressed); |
201 break; | 225 break; |
202 | 226 |
203 case KeyEvent.KEYCODE_POUND: | 227 case KeyEvent.KEYCODE_POUND: |
204 JniInterface.sendKeyEvent(KeyEvent.KEYCODE_SHIFT_LEFT, depressed
); | 228 JniInterface.sendKeyEvent(KeyEvent.KEYCODE_SHIFT_LEFT, pressed); |
205 JniInterface.sendKeyEvent(KeyEvent.KEYCODE_3, depressed); | 229 JniInterface.sendKeyEvent(KeyEvent.KEYCODE_3, pressed); |
206 break; | 230 break; |
207 | 231 |
208 case KeyEvent.KEYCODE_STAR: | 232 case KeyEvent.KEYCODE_STAR: |
209 JniInterface.sendKeyEvent(KeyEvent.KEYCODE_SHIFT_LEFT, depressed
); | 233 JniInterface.sendKeyEvent(KeyEvent.KEYCODE_SHIFT_LEFT, pressed); |
210 JniInterface.sendKeyEvent(KeyEvent.KEYCODE_8, depressed); | 234 JniInterface.sendKeyEvent(KeyEvent.KEYCODE_8, pressed); |
211 break; | 235 break; |
212 | 236 |
213 case KeyEvent.KEYCODE_PLUS: | 237 case KeyEvent.KEYCODE_PLUS: |
214 JniInterface.sendKeyEvent(KeyEvent.KEYCODE_SHIFT_LEFT, depressed
); | 238 JniInterface.sendKeyEvent(KeyEvent.KEYCODE_SHIFT_LEFT, pressed); |
215 JniInterface.sendKeyEvent(KeyEvent.KEYCODE_EQUALS, depressed); | 239 JniInterface.sendKeyEvent(KeyEvent.KEYCODE_EQUALS, pressed); |
216 break; | 240 break; |
217 | 241 |
218 default: | 242 default: |
219 // We try to send all other key codes to the host directly. | 243 // We try to send all other key codes to the host directly. |
220 JniInterface.sendKeyEvent(event.getKeyCode(), depressed); | 244 JniInterface.sendKeyEvent(keyCode, pressed); |
221 } | 245 } |
222 | 246 |
223 return super.dispatchKeyEvent(event); | 247 return super.dispatchKeyEvent(event); |
224 } | 248 } |
225 } | 249 } |
OLD | NEW |