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 inject input that |
Lambros
2014/05/28 22:32:28
s/inject/injects
Sergey Ulanov
2014/06/06 18:43:45
Done.
| |
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. | |
Lambros
2014/05/28 22:32:28
What about Backspace - will that work as expected?
Sergey Ulanov
2014/06/06 18:43:45
Yes. getCharacter() is not set for Backspace.
| |
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 = new int[1]; | |
Lambros
2014/05/28 22:32:28
This could be: int[] codePoints = { unicode }
but
Sergey Ulanov
2014/06/06 18:43:45
Done.
| |
212 codePoints[0] = unicode; | |
213 JniInterface.sendTextEvent(new String(codePoints, 0, 1)); | |
Lambros
2014/05/28 22:32:28
You can convert to string like this:
String.valueO
Sergey Ulanov
2014/06/06 18:43:45
In Java char is 16 bits and can encode only plane
| |
214 return super.dispatchKeyEvent(event); | |
215 } | |
216 | |
217 if (!pressed && mPressedTextKeys.contains(keyCode)) { | |
218 mPressedTextKeys.remove(keyCode); | |
219 return super.dispatchKeyEvent(event); | |
220 } | |
221 | |
222 switch (keyCode) { | |
198 case KeyEvent.KEYCODE_AT: | 223 case KeyEvent.KEYCODE_AT: |
199 JniInterface.sendKeyEvent(KeyEvent.KEYCODE_SHIFT_LEFT, depressed ); | 224 JniInterface.sendKeyEvent(KeyEvent.KEYCODE_SHIFT_LEFT, pressed); |
200 JniInterface.sendKeyEvent(KeyEvent.KEYCODE_2, depressed); | 225 JniInterface.sendKeyEvent(KeyEvent.KEYCODE_2, pressed); |
201 break; | 226 break; |
202 | 227 |
203 case KeyEvent.KEYCODE_POUND: | 228 case KeyEvent.KEYCODE_POUND: |
204 JniInterface.sendKeyEvent(KeyEvent.KEYCODE_SHIFT_LEFT, depressed ); | 229 JniInterface.sendKeyEvent(KeyEvent.KEYCODE_SHIFT_LEFT, pressed); |
205 JniInterface.sendKeyEvent(KeyEvent.KEYCODE_3, depressed); | 230 JniInterface.sendKeyEvent(KeyEvent.KEYCODE_3, pressed); |
206 break; | 231 break; |
207 | 232 |
208 case KeyEvent.KEYCODE_STAR: | 233 case KeyEvent.KEYCODE_STAR: |
209 JniInterface.sendKeyEvent(KeyEvent.KEYCODE_SHIFT_LEFT, depressed ); | 234 JniInterface.sendKeyEvent(KeyEvent.KEYCODE_SHIFT_LEFT, pressed); |
210 JniInterface.sendKeyEvent(KeyEvent.KEYCODE_8, depressed); | 235 JniInterface.sendKeyEvent(KeyEvent.KEYCODE_8, pressed); |
211 break; | 236 break; |
212 | 237 |
213 case KeyEvent.KEYCODE_PLUS: | 238 case KeyEvent.KEYCODE_PLUS: |
214 JniInterface.sendKeyEvent(KeyEvent.KEYCODE_SHIFT_LEFT, depressed ); | 239 JniInterface.sendKeyEvent(KeyEvent.KEYCODE_SHIFT_LEFT, pressed); |
215 JniInterface.sendKeyEvent(KeyEvent.KEYCODE_EQUALS, depressed); | 240 JniInterface.sendKeyEvent(KeyEvent.KEYCODE_EQUALS, pressed); |
216 break; | 241 break; |
217 | 242 |
218 default: | 243 default: |
219 // We try to send all other key codes to the host directly. | 244 // We try to send all other key codes to the host directly. |
220 JniInterface.sendKeyEvent(event.getKeyCode(), depressed); | 245 JniInterface.sendKeyEvent(keyCode, pressed); |
221 } | 246 } |
222 | 247 |
223 return super.dispatchKeyEvent(event); | 248 return super.dispatchKeyEvent(event); |
224 } | 249 } |
225 } | 250 } |
OLD | NEW |