Commit 1da4a34e authored by sergeyu's avatar sergeyu Committed by Commit bot

Use scan codes when sending keyboard events froms physical keyboard.

Previously android app was using key code when sending keyboard events.
That approach doesn't work well with physical keyboard when using
layout other than QWERTY. Fixed the client to use scan codes, so that
the events are always send correctly and layout mapping is applied
only on the client.

BUG=475713

Review URL: https://codereview.chromium.org/1321223003

Cr-Commit-Position: refs/heads/master@{#347874}
parent 582fd8ff
...@@ -228,10 +228,10 @@ public class Desktop extends AppCompatActivity implements View.OnSystemUiVisibil ...@@ -228,10 +228,10 @@ public class Desktop extends AppCompatActivity implements View.OnSystemUiVisibil
KeyEvent.KEYCODE_FORWARD_DEL, KeyEvent.KEYCODE_FORWARD_DEL,
}; };
for (int key : keys) { for (int key : keys) {
JniInterface.sendKeyEvent(key, true); JniInterface.sendKeyEvent(0, key, true);
} }
for (int key : keys) { for (int key : keys) {
JniInterface.sendKeyEvent(key, false); JniInterface.sendKeyEvent(0, key, false);
} }
return true; return true;
} }
...@@ -256,10 +256,21 @@ public class Desktop extends AppCompatActivity implements View.OnSystemUiVisibil ...@@ -256,10 +256,21 @@ public class Desktop extends AppCompatActivity implements View.OnSystemUiVisibil
return super.dispatchKeyEvent(event); return super.dispatchKeyEvent(event);
} }
// Send TextEvent in two cases: boolean pressed = event.getAction() == KeyEvent.ACTION_DOWN;
// Physical keyboard must work as if it is connected to the remote host
// and so events coming from physical keyboard never generate text
// events. Also scan codes must be used instead of key code, so that
// the keyboard layout selected on the client doesn't affect the key
// codes sent to the host.
if (event.getDeviceId() != KeyCharacterMap.VIRTUAL_KEYBOARD) {
return JniInterface.sendKeyEvent(event.getScanCode(), 0, pressed);
}
// Events received from software keyboards generate TextEvent in two
// cases:
// 1. This is an ACTION_MULTIPLE event. // 1. This is an ACTION_MULTIPLE event.
// 2. The event was generated by on-screen keyboard and Ctrl, Alt and // 2. Ctrl, Alt and Meta are not pressed.
// Meta are not pressed.
// This ensures that on-screen keyboard always injects input that // This ensures that on-screen keyboard always injects input that
// correspond to what user sees on the screen, while physical keyboard // correspond to what user sees on the screen, while physical keyboard
// acts as if it is connected to the remote host. // acts as if it is connected to the remote host.
...@@ -268,8 +279,6 @@ public class Desktop extends AppCompatActivity implements View.OnSystemUiVisibil ...@@ -268,8 +279,6 @@ public class Desktop extends AppCompatActivity implements View.OnSystemUiVisibil
return true; return true;
} }
boolean pressed = event.getAction() == KeyEvent.ACTION_DOWN;
// For Enter getUnicodeChar() returns 10 (line feed), but we still // For Enter getUnicodeChar() returns 10 (line feed), but we still
// want to send it as KeyEvent. // want to send it as KeyEvent.
int unicode = keyCode != KeyEvent.KEYCODE_ENTER ? event.getUnicodeChar() : 0; int unicode = keyCode != KeyEvent.KEYCODE_ENTER ? event.getUnicodeChar() : 0;
...@@ -277,8 +286,7 @@ public class Desktop extends AppCompatActivity implements View.OnSystemUiVisibil ...@@ -277,8 +286,7 @@ public class Desktop extends AppCompatActivity implements View.OnSystemUiVisibil
boolean no_modifiers = !event.isAltPressed() boolean no_modifiers = !event.isAltPressed()
&& !event.isCtrlPressed() && !event.isMetaPressed(); && !event.isCtrlPressed() && !event.isMetaPressed();
if (event.getDeviceId() == KeyCharacterMap.VIRTUAL_KEYBOARD if (pressed && unicode != 0 && no_modifiers) {
&& pressed && unicode != 0 && no_modifiers) {
mPressedTextKeys.add(keyCode); mPressedTextKeys.add(keyCode);
int[] codePoints = { unicode }; int[] codePoints = { unicode };
JniInterface.sendTextEvent(new String(codePoints, 0, 1)); JniInterface.sendTextEvent(new String(codePoints, 0, 1));
...@@ -291,29 +299,33 @@ public class Desktop extends AppCompatActivity implements View.OnSystemUiVisibil ...@@ -291,29 +299,33 @@ public class Desktop extends AppCompatActivity implements View.OnSystemUiVisibil
} }
switch (keyCode) { switch (keyCode) {
// KEYCODE_AT, KEYCODE_POUND, KEYCODE_STAR and KEYCODE_PLUS are
// deprecated, but they still need to be here for older devices and
// third-party keyboards that may still generate these events. See
// https://source.android.com/devices/input/keyboard-devices.html#legacy-unsupported-keys
case KeyEvent.KEYCODE_AT: case KeyEvent.KEYCODE_AT:
JniInterface.sendKeyEvent(KeyEvent.KEYCODE_SHIFT_LEFT, pressed); JniInterface.sendKeyEvent(0, KeyEvent.KEYCODE_SHIFT_LEFT, pressed);
JniInterface.sendKeyEvent(KeyEvent.KEYCODE_2, pressed); JniInterface.sendKeyEvent(0, KeyEvent.KEYCODE_2, pressed);
return true; return true;
case KeyEvent.KEYCODE_POUND: case KeyEvent.KEYCODE_POUND:
JniInterface.sendKeyEvent(KeyEvent.KEYCODE_SHIFT_LEFT, pressed); JniInterface.sendKeyEvent(0, KeyEvent.KEYCODE_SHIFT_LEFT, pressed);
JniInterface.sendKeyEvent(KeyEvent.KEYCODE_3, pressed); JniInterface.sendKeyEvent(0, KeyEvent.KEYCODE_3, pressed);
return true; return true;
case KeyEvent.KEYCODE_STAR: case KeyEvent.KEYCODE_STAR:
JniInterface.sendKeyEvent(KeyEvent.KEYCODE_SHIFT_LEFT, pressed); JniInterface.sendKeyEvent(0, KeyEvent.KEYCODE_SHIFT_LEFT, pressed);
JniInterface.sendKeyEvent(KeyEvent.KEYCODE_8, pressed); JniInterface.sendKeyEvent(0, KeyEvent.KEYCODE_8, pressed);
return true; return true;
case KeyEvent.KEYCODE_PLUS: case KeyEvent.KEYCODE_PLUS:
JniInterface.sendKeyEvent(KeyEvent.KEYCODE_SHIFT_LEFT, pressed); JniInterface.sendKeyEvent(0, KeyEvent.KEYCODE_SHIFT_LEFT, pressed);
JniInterface.sendKeyEvent(KeyEvent.KEYCODE_EQUALS, pressed); JniInterface.sendKeyEvent(0, KeyEvent.KEYCODE_EQUALS, pressed);
return true; return true;
default: default:
// We try to send all other key codes to the host directly. // We try to send all other key codes to the host directly.
return JniInterface.sendKeyEvent(keyCode, pressed); return JniInterface.sendKeyEvent(0, keyCode, pressed);
} }
} }
} }
...@@ -286,17 +286,22 @@ public class JniInterface { ...@@ -286,17 +286,22 @@ public class JniInterface {
/** Passes mouse-wheel information to the native handling code. */ /** Passes mouse-wheel information to the native handling code. */
private static native void nativeSendMouseWheelEvent(int deltaX, int deltaY); private static native void nativeSendMouseWheelEvent(int deltaX, int deltaY);
/** Presses or releases the specified (nonnegative) key. Called on the UI thread. */ /**
public static boolean sendKeyEvent(int keyCode, boolean keyDown) { * Presses or releases the specified (nonnegative) key. Called on the UI thread. If scanCode
* is not zero then keyCode is ignored.
*/
public static boolean sendKeyEvent(int scanCode, int keyCode, boolean keyDown) {
if (!sConnected) { if (!sConnected) {
return false; return false;
} }
return nativeSendKeyEvent(keyCode, keyDown); return nativeSendKeyEvent(scanCode, keyCode, keyDown);
} }
/** Passes key press information to the native handling code. */ /**
private static native boolean nativeSendKeyEvent(int keyCode, boolean keyDown); * Passes key press information to the native handling code.
*/
private static native boolean nativeSendKeyEvent(int scanCode, int keyCode, boolean keyDown);
/** Sends TextEvent to the host. Called on the UI thread. */ /** Sends TextEvent to the host. Called on the UI thread. */
public static void sendTextEvent(String text) { public static void sendTextEvent(String text) {
......
...@@ -25,6 +25,7 @@ ...@@ -25,6 +25,7 @@
#include "remoting/protocol/negotiating_client_authenticator.h" #include "remoting/protocol/negotiating_client_authenticator.h"
#include "remoting/protocol/network_settings.h" #include "remoting/protocol/network_settings.h"
#include "remoting/signaling/server_log_entry.h" #include "remoting/signaling/server_log_entry.h"
#include "ui/events/keycodes/dom/keycode_converter.h"
namespace remoting { namespace remoting {
...@@ -229,10 +230,17 @@ void ChromotingJniInstance::SendMouseWheelEvent(int delta_x, int delta_y) { ...@@ -229,10 +230,17 @@ void ChromotingJniInstance::SendMouseWheelEvent(int delta_x, int delta_y) {
client_->input_stub()->InjectMouseEvent(event); client_->input_stub()->InjectMouseEvent(event);
} }
bool ChromotingJniInstance::SendKeyEvent(int key_code, bool key_down) { bool ChromotingJniInstance::SendKeyEvent(int scan_code,
uint32 usb_key_code = AndroidKeycodeToUsbKeycode(key_code); int key_code,
bool key_down) {
// For software keyboards |scan_code| is set to 0, in which case the
// |key_code| is used instead.
uint32_t usb_key_code =
scan_code ? ui::KeycodeConverter::NativeKeycodeToUsbKeycode(scan_code)
: AndroidKeycodeToUsbKeycode(key_code);
if (!usb_key_code) { if (!usb_key_code) {
LOG(WARNING) << "Ignoring unknown keycode: " << key_code; LOG(WARNING) << "Ignoring unknown key code: " << key_code
<< " scan code: " << scan_code;
return false; return false;
} }
......
...@@ -83,7 +83,7 @@ class ChromotingJniInstance ...@@ -83,7 +83,7 @@ class ChromotingJniInstance
void SendMouseWheelEvent(int delta_x, int delta_y); void SendMouseWheelEvent(int delta_x, int delta_y);
// Sends the provided keyboard scan code to the host. // Sends the provided keyboard scan code to the host.
bool SendKeyEvent(int key_code, bool key_down); bool SendKeyEvent(int scan_code, int key_code, bool key_down);
void SendTextEvent(const std::string& text); void SendTextEvent(const std::string& text);
......
...@@ -139,10 +139,11 @@ static void SendMouseWheelEvent(JNIEnv* env, ...@@ -139,10 +139,11 @@ static void SendMouseWheelEvent(JNIEnv* env,
static jboolean SendKeyEvent(JNIEnv* env, static jboolean SendKeyEvent(JNIEnv* env,
const JavaParamRef<jclass>& clazz, const JavaParamRef<jclass>& clazz,
jint scanCode,
jint keyCode, jint keyCode,
jboolean keyDown) { jboolean keyDown) {
return remoting::ChromotingJniRuntime::GetInstance()->session()->SendKeyEvent( return remoting::ChromotingJniRuntime::GetInstance()->session()->SendKeyEvent(
keyCode, keyDown); scanCode, keyCode, keyDown);
} }
static void SendTextEvent(JNIEnv* env, static void SendTextEvent(JNIEnv* env,
......
...@@ -27,6 +27,7 @@ ...@@ -27,6 +27,7 @@
'remoting_jni_headers', 'remoting_jni_headers',
'remoting_protocol', 'remoting_protocol',
'../google_apis/google_apis.gyp:google_apis', '../google_apis/google_apis.gyp:google_apis',
'../ui/events/events.gyp:dom_keycode_converter',
'../ui/gfx/gfx.gyp:gfx', '../ui/gfx/gfx.gyp:gfx',
], ],
'sources': [ 'sources': [
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment