diff options
author | sergeyu@chromium.org <sergeyu@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2014-05-21 22:49:20 +0000 |
---|---|---|
committer | sergeyu@chromium.org <sergeyu@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2014-05-21 22:49:20 +0000 |
commit | a0c458629a0620ee65948645aa81c9a1dab43c55 (patch) | |
tree | 25ae27f475deca585251897072c3638eca126ca4 /remoting/client | |
parent | 703c6a8cbbfcc1d5d5b16e1c12e4a18497b4eb0f (diff) | |
download | chromium_src-a0c458629a0620ee65948645aa81c9a1dab43c55.zip chromium_src-a0c458629a0620ee65948645aa81c9a1dab43c55.tar.gz chromium_src-a0c458629a0620ee65948645aa81c9a1dab43c55.tar.bz2 |
Enable keyboard filters in PNaCl client
Previously keyboard filters were selected using the per-platform
filename exclusion rules, and that doesn't work for PNaCl plugin. Now
both Mac and ChromeOS filters are compiled into the PNaCl plugin and
selected in runtime.
BUG=276739
Review URL: https://codereview.chromium.org/292103004
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@271997 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'remoting/client')
12 files changed, 277 insertions, 262 deletions
diff --git a/remoting/client/plugin/chromoting_instance.cc b/remoting/client/plugin/chromoting_instance.cc index 8a07ecb..d7f9195 100644 --- a/remoting/client/plugin/chromoting_instance.cc +++ b/remoting/client/plugin/chromoting_instance.cc @@ -42,6 +42,8 @@ #include "remoting/client/frame_consumer_proxy.h" #include "remoting/client/plugin/delegating_signal_strategy.h" #include "remoting/client/plugin/media_source_video_renderer.h" +#include "remoting/client/plugin/normalizing_input_filter_cros.h" +#include "remoting/client/plugin/normalizing_input_filter_mac.h" #include "remoting/client/plugin/pepper_audio_player.h" #include "remoting/client/plugin/pepper_input_handler.h" #include "remoting/client/plugin/pepper_port_allocator.h" @@ -210,8 +212,7 @@ ChromotingInstance::ChromotingInstance(PP_Instance pp_instance) context_(plugin_task_runner_.get()), input_tracker_(&mouse_input_filter_), key_mapper_(&input_tracker_), - normalizing_input_filter_(CreateNormalizingInputFilter(&key_mapper_)), - input_handler_(this, normalizing_input_filter_.get()), + input_handler_(this), use_async_pin_dialog_(false), use_media_source_rendering_(false), weak_factory_(this) { @@ -643,6 +644,30 @@ void ChromotingInstance::HandleConnect(const base::DictionaryValue& data) { } } +#if defined(OS_NACL) + std::string key_filter; + if (!data.GetString("keyFilter", &key_filter)) { + NOTREACHED(); + normalizing_input_filter_.reset(new protocol::InputFilter(&key_mapper_)); + } else if (key_filter == "mac") { + normalizing_input_filter_.reset( + new NormalizingInputFilterMac(&key_mapper_)); + } else if (key_filter == "cros") { + normalizing_input_filter_.reset( + new NormalizingInputFilterCros(&key_mapper_)); + } else { + DCHECK(key_filter.empty()); + normalizing_input_filter_.reset(new protocol::InputFilter(&key_mapper_)); + } +#elif defined(OS_MACOSX) + normalizing_input_filter_.reset(new NormalizingInputFilterMac(&key_mapper_)); +#elif defined(OS_CHROMEOS) + normalizing_input_filter_.reset(new NormalizingInputFilterCros(&key_mapper_)); +#else + normalizing_input_filter_.reset(new protocol::InputFilter(&key_mapper_)); +#endif + input_handler_.set_input_stub(normalizing_input_filter_.get()); + ConnectWithConfig(config, local_jid); } diff --git a/remoting/client/plugin/chromoting_instance.h b/remoting/client/plugin/chromoting_instance.h index f56074d..2843c97 100644 --- a/remoting/client/plugin/chromoting_instance.h +++ b/remoting/client/plugin/chromoting_instance.h @@ -2,9 +2,6 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -// TODO(ajwong): We need to come up with a better description of the -// responsibilities for each thread. - #ifndef REMOTING_CLIENT_PLUGIN_CHROMOTING_INSTANCE_H_ #define REMOTING_CLIENT_PLUGIN_CHROMOTING_INSTANCE_H_ @@ -23,7 +20,6 @@ #include "remoting/client/client_user_interface.h" #include "remoting/client/key_event_mapper.h" #include "remoting/client/plugin/media_source_video_renderer.h" -#include "remoting/client/plugin/normalizing_input_filter.h" #include "remoting/client/plugin/pepper_input_handler.h" #include "remoting/client/plugin/pepper_plugin_thread_delegate.h" #include "remoting/proto/event.pb.h" diff --git a/remoting/client/plugin/normalizing_input_filter.cc b/remoting/client/plugin/normalizing_input_filter.cc deleted file mode 100644 index 7206305..0000000 --- a/remoting/client/plugin/normalizing_input_filter.cc +++ /dev/null @@ -1,20 +0,0 @@ -// Copyright 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "remoting/client/plugin/normalizing_input_filter.h" - -#include "remoting/protocol/input_filter.h" - -namespace remoting { - -using protocol::InputFilter; -using protocol::InputStub; - -#if !defined(OS_MACOSX) && !defined(OS_CHROMEOS) -scoped_ptr<InputFilter> CreateNormalizingInputFilter(InputStub* input_stub) { - return scoped_ptr<InputFilter>(new InputFilter(input_stub)); -} -#endif // !defined(OS_MACOSX) && !defined(OS_CHROMEOS) - -} diff --git a/remoting/client/plugin/normalizing_input_filter.h b/remoting/client/plugin/normalizing_input_filter.h deleted file mode 100644 index ebe49fe..0000000 --- a/remoting/client/plugin/normalizing_input_filter.h +++ /dev/null @@ -1,21 +0,0 @@ -// Copyright 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef REMOTING_CLIENT_PLUGIN_NORMALIZING_INPUT_FILTER_H_ -#define REMOTING_CLIENT_PLUGIN_NORMALIZING_INPUT_FILTER_H_ - -#include "base/memory/scoped_ptr.h" -#include "remoting/protocol/input_filter.h" - -namespace remoting { - -// Returns an InputFilter which re-writes input events to work around -// platform-specific behaviours. If no re-writing is required then a -// pass-through InputFilter is returned. -scoped_ptr<protocol::InputFilter> CreateNormalizingInputFilter( - protocol::InputStub* input_stub); - -} // namespace remoting - -#endif // REMOTING_CLIENT_PLUGIN_NORMALIZING_INPUT_FILTER_H_ diff --git a/remoting/client/plugin/normalizing_input_filter_cros.cc b/remoting/client/plugin/normalizing_input_filter_cros.cc index 81cec8d..5ad77ee 100644 --- a/remoting/client/plugin/normalizing_input_filter_cros.cc +++ b/remoting/client/plugin/normalizing_input_filter_cros.cc @@ -2,26 +2,9 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -// NormalizingInputFilterCros addresses the problems generated by key rewritings -// such as Down->PageDown, 1->F1, etc, when keys are pressed in combination with -// the OSKey (aka Search). Rewriting OSKey+Down, for example, causes us to -// receive the following: -// -// keydown OSKey -// keydown PageDown -// keyup PageDown -// keyup OSKey -// -// The host system will therefore behave as if OSKey+PageDown were pressed, -// rather than PageDown alone. -// -// This file must be kept up-to-date with changes to -// chrome/browser/ui/ash/event_rewriter.cc - -#include "remoting/client/plugin/normalizing_input_filter.h" +#include "remoting/client/plugin/normalizing_input_filter_cros.h" #include "base/logging.h" -#include "remoting/proto/event.pb.h" namespace remoting { @@ -53,6 +36,8 @@ static bool IsRewrittenKey(unsigned int code) { return IsRewrittenExtendedKey(code) || IsRewrittenFunctionKey(code); } +} // namespace + // The input filter tries to avoid sending keydown/keyup events for OSKey // (aka Search, WinKey, Cmd, Super) when it is used to rewrite other key events. // Rewriting via other combinations is not currently handled. @@ -86,121 +71,102 @@ static bool IsRewrittenKey(unsigned int code) { // 4. An OSKey is pressed, and is Modifying. // - If the OSKey keyup is received then we send it and we move to State #1. // - All other key event pass through the filter unchanged. +// +// This file must be kept up-to-date with changes to +// chrome/browser/ui/ash/event_rewriter.cc -class NormalizingInputFilterCros : public protocol::InputFilter { - public: - explicit NormalizingInputFilterCros(protocol::InputStub* input_stub) - : protocol::InputFilter(input_stub), - deferred_key_is_rewriting_(false), - modifying_key_(0) { - } - virtual ~NormalizingInputFilterCros() {} +NormalizingInputFilterCros::NormalizingInputFilterCros( + protocol::InputStub* input_stub) + : protocol::InputFilter(input_stub), + deferred_key_is_rewriting_(false), + modifying_key_(0) { +} - // InputFilter overrides. - virtual void InjectKeyEvent(const protocol::KeyEvent& event) OVERRIDE { - DCHECK(event.has_usb_keycode()); - DCHECK(event.has_pressed()); +NormalizingInputFilterCros::~NormalizingInputFilterCros() {} - if (event.pressed()) - ProcessKeyDown(event); - else - ProcessKeyUp(event); - } +void NormalizingInputFilterCros::InjectKeyEvent( + const protocol::KeyEvent& event) { + DCHECK(event.has_usb_keycode()); + DCHECK(event.has_pressed()); - virtual void InjectMouseEvent(const protocol::MouseEvent& event) OVERRIDE { - if (deferred_keydown_event_.has_usb_keycode()) - SwitchRewritingKeyToModifying(); - InputFilter::InjectMouseEvent(event); + if (event.pressed()) { + ProcessKeyDown(event); + } else { + ProcessKeyUp(event); } +} - private: - void ProcessKeyDown(const protocol::KeyEvent& event) { - // If |event| is |deferred_keydown_event_| auto-repeat then assume - // that the user is holding the key down rather than using it to Rewrite. - if (deferred_keydown_event_.has_usb_keycode() && - deferred_keydown_event_.usb_keycode() == event.usb_keycode()) { - SwitchRewritingKeyToModifying(); - } - - // If |event| is a |modifying_key_| repeat then let it pass through. - if (modifying_key_ == event.usb_keycode()) { - InputFilter::InjectKeyEvent(event); - return; - } - - // If |event| is for an OSKey and we don't know whether it's a Normal, - // Rewriting or Modifying use, then hold the keydown event. - if (IsOsKey(event.usb_keycode())) { - deferred_keydown_event_ = event; - deferred_key_is_rewriting_ = false; - return; - } +void NormalizingInputFilterCros::InjectMouseEvent( + const protocol::MouseEvent& event) { + if (deferred_keydown_event_.has_usb_keycode()) + SwitchRewritingKeyToModifying(); + InputFilter::InjectMouseEvent(event); +} - // If |event| is for a Rewritten key then set a flag to prevent any deferred - // OSKey keydown from being sent when keyup is received for it. Otherwise, - // inject the deferred OSKey keydown, if any, and switch that key into - // Modifying mode. - if (IsRewrittenKey(event.usb_keycode())) { - // Note that there may not be a deferred OSKey event if there is a full - // PC keyboard connected, which can generate e.g. PageDown without - // rewriting. - deferred_key_is_rewriting_ = true; - } else { - if (deferred_keydown_event_.has_usb_keycode()) - SwitchRewritingKeyToModifying(); - } +void NormalizingInputFilterCros::ProcessKeyDown( + const protocol::KeyEvent& event) { + // If |event| is |deferred_keydown_event_| repeat then assume that the user is + // holding the key down rather than using it to Rewrite. + if (deferred_keydown_event_.has_usb_keycode() && + deferred_keydown_event_.usb_keycode() == event.usb_keycode()) { + SwitchRewritingKeyToModifying(); + } + // If |event| is a |modifying_key_| repeat then let it pass through. + if (modifying_key_ == event.usb_keycode()) { InputFilter::InjectKeyEvent(event); + return; } - void ProcessKeyUp(const protocol::KeyEvent& event) { - if (deferred_keydown_event_.has_usb_keycode() && - deferred_keydown_event_.usb_keycode() == event.usb_keycode()) { - if (deferred_key_is_rewriting_) { - // If we never sent the keydown then don't send a keyup. - deferred_keydown_event_ = protocol::KeyEvent(); - return; - } - - // If the OSKey hasn't Rewritten anything then treat as Modifying. - SwitchRewritingKeyToModifying(); - } - - if (modifying_key_ == event.usb_keycode()) - modifying_key_ = 0; - - InputFilter::InjectKeyEvent(event); + // If |event| is for an OSKey and we don't know whether it's a Normal, + // Rewriting or Modifying use, then hold the keydown event. + if (IsOsKey(event.usb_keycode())) { + deferred_keydown_event_ = event; + deferred_key_is_rewriting_ = false; + return; } - void SwitchRewritingKeyToModifying() { - DCHECK(deferred_keydown_event_.has_usb_keycode()); - modifying_key_ = deferred_keydown_event_.usb_keycode(); - InputFilter::InjectKeyEvent(deferred_keydown_event_); - deferred_keydown_event_ = protocol::KeyEvent(); + // If |event| is for a Rewritten key then set a flag to prevent any deferred + // OSKey keydown from being sent when keyup is received for it. Otherwise, + // inject the deferred OSKey keydown, if any, and switch that key into + // Modifying mode. + if (IsRewrittenKey(event.usb_keycode())) { + // Note that there may not be a deferred OSKey event if there is a full + // PC keyboard connected, which can generate e.g. PageDown without + // rewriting. + deferred_key_is_rewriting_ = true; + } else { + if (deferred_keydown_event_.has_usb_keycode()) + SwitchRewritingKeyToModifying(); } - // Holds the keydown event for the most recent OSKey to have been pressed, - // while it is Rewriting, or we are not yet sure whether it is Normal, - // Rewriting or Modifying. The event is sent on if we switch to Modifying, or - // discarded if the OSKey is released while in Rewriting mode. - protocol::KeyEvent deferred_keydown_event_; + InputFilter::InjectKeyEvent(event); +} - // True while the |rewrite_keydown_event_| key is Rewriting, i.e. was followed - // by one or more Rewritten key events, and not by any Modified events. - bool deferred_key_is_rewriting_; +void NormalizingInputFilterCros::ProcessKeyUp(const protocol::KeyEvent& event) { + if (deferred_keydown_event_.has_usb_keycode() && + deferred_keydown_event_.usb_keycode() == event.usb_keycode()) { + if (deferred_key_is_rewriting_) { + // If we never sent the keydown then don't send a keyup. + deferred_keydown_event_ = protocol::KeyEvent(); + return; + } - // Stores the code of the OSKey while it is pressed for use as a Modifier. - uint32 modifying_key_; + // If the OSKey hasn't Rewritten anything then treat as Modifying. + SwitchRewritingKeyToModifying(); + } - DISALLOW_COPY_AND_ASSIGN(NormalizingInputFilterCros); -}; + if (modifying_key_ == event.usb_keycode()) + modifying_key_ = 0; -} // namespace + InputFilter::InjectKeyEvent(event); +} -scoped_ptr<protocol::InputFilter> CreateNormalizingInputFilter( - protocol::InputStub* input_stub) { - return scoped_ptr<protocol::InputFilter>( - new NormalizingInputFilterCros(input_stub)); +void NormalizingInputFilterCros::SwitchRewritingKeyToModifying() { + DCHECK(deferred_keydown_event_.has_usb_keycode()); + modifying_key_ = deferred_keydown_event_.usb_keycode(); + InputFilter::InjectKeyEvent(deferred_keydown_event_); + deferred_keydown_event_ = protocol::KeyEvent(); } } // namespace remoting diff --git a/remoting/client/plugin/normalizing_input_filter_cros.h b/remoting/client/plugin/normalizing_input_filter_cros.h new file mode 100644 index 0000000..977c90c --- /dev/null +++ b/remoting/client/plugin/normalizing_input_filter_cros.h @@ -0,0 +1,54 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "remoting/protocol/input_filter.h" + +#include "remoting/proto/event.pb.h" + +namespace remoting { + +// NormalizingInputFilterCros addresses the problems generated by key rewritings +// such as Down->PageDown, 1->F1, etc, when keys are pressed in combination with +// the OSKey (aka Search). Rewriting OSKey+Down, for example, causes us to +// receive the following: +// +// keydown OSKey +// keydown PageDown +// keyup PageDown +// keyup OSKey +// +// The host system will therefore behave as if OSKey+PageDown were pressed, +// rather than PageDown alone. +class NormalizingInputFilterCros : public protocol::InputFilter { + public: + explicit NormalizingInputFilterCros(protocol::InputStub* input_stub); + virtual ~NormalizingInputFilterCros(); + + // InputFilter overrides. + virtual void InjectKeyEvent(const protocol::KeyEvent& event) OVERRIDE; + virtual void InjectMouseEvent(const protocol::MouseEvent& event) OVERRIDE; + + private: + void ProcessKeyDown(const protocol::KeyEvent& event); + void ProcessKeyUp(const protocol::KeyEvent& event); + + void SwitchRewritingKeyToModifying(); + + // Holds the keydown event for the most recent OSKey to have been pressed, + // while it is Rewriting, or we are not yet sure whether it is Normal, + // Rewriting or Modifying. The event is sent on if we switch to Modifying, or + // discarded if the OSKey is released while in Rewriting mode. + protocol::KeyEvent deferred_keydown_event_; + + // True while the |rewrite_keydown_event_| key is Rewriting, i.e. was followed + // by one or more Rewritten key events, and not by any Modified events. + bool deferred_key_is_rewriting_; + + // Stores the code of the OSKey while it is pressed for use as a Modifier. + uint32 modifying_key_; + + DISALLOW_COPY_AND_ASSIGN(NormalizingInputFilterCros); +}; + +} // namespace remoting diff --git a/remoting/client/plugin/normalizing_input_filter_cros_unittest.cc b/remoting/client/plugin/normalizing_input_filter_cros_unittest.cc index cf46d16..9001471 100644 --- a/remoting/client/plugin/normalizing_input_filter_cros_unittest.cc +++ b/remoting/client/plugin/normalizing_input_filter_cros_unittest.cc @@ -2,7 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "remoting/client/plugin/normalizing_input_filter.h" +#include "remoting/client/plugin/normalizing_input_filter_cros.h" + #include "remoting/proto/event.pb.h" #include "remoting/protocol/protocol_mock_objects.h" #include "testing/gmock/include/gmock/gmock.h" @@ -21,9 +22,9 @@ namespace { const unsigned int kUsbLeftOsKey = 0x0700e3; const unsigned int kUsbRightOsKey = 0x0700e7; -const unsigned int kUsbFunctionKey = 0x07003a; // F1 -const unsigned int kUsbExtendedKey = 0x070049; // Insert -const unsigned int kUsbOtherKey = 0x07002b; // Tab +const unsigned int kUsbFunctionKey = 0x07003a; // F1 +const unsigned int kUsbExtendedKey = 0x070049; // Insert +const unsigned int kUsbOtherKey = 0x07002b; // Tab // A hardcoded value used to verify |lock_states| is preserved. static const uint32 kTestLockStates = protocol::KeyEvent::LOCK_STATES_NUMLOCK; @@ -63,8 +64,8 @@ static MouseEvent MakeMouseMoveEvent(int x, int y) { // Test OSKey press/release. TEST(NormalizingInputFilterCrosTest, PressReleaseOsKey) { MockInputStub stub; - scoped_ptr<protocol::InputFilter> processor = - CreateNormalizingInputFilter(&stub); + scoped_ptr<protocol::InputFilter> processor( + new NormalizingInputFilterCros(&stub)); { InSequence s; @@ -84,8 +85,8 @@ TEST(NormalizingInputFilterCrosTest, PressReleaseOsKey) { // Test OSKey key repeat switches it to "modifying" mode. TEST(NormalizingInputFilterCrosTest, OSKeyRepeats) { MockInputStub stub; - scoped_ptr<protocol::InputFilter> processor = - CreateNormalizingInputFilter(&stub); + scoped_ptr<protocol::InputFilter> processor( + new NormalizingInputFilterCros(&stub)); { InSequence s; @@ -106,8 +107,8 @@ TEST(NormalizingInputFilterCrosTest, OSKeyRepeats) { // just the function key events. TEST(NormalizingInputFilterCrosTest, FunctionKey) { MockInputStub stub; - scoped_ptr<protocol::InputFilter> processor = - CreateNormalizingInputFilter(&stub); + scoped_ptr<protocol::InputFilter> processor( + new NormalizingInputFilterCros(&stub)); { InSequence s; @@ -126,8 +127,8 @@ TEST(NormalizingInputFilterCrosTest, FunctionKey) { // just the function key events. TEST(NormalizingInputFilterCrosTest, ExtendedKey) { MockInputStub stub; - scoped_ptr<protocol::InputFilter> processor = - CreateNormalizingInputFilter(&stub); + scoped_ptr<protocol::InputFilter> processor( + new NormalizingInputFilterCros(&stub)); { InSequence s; @@ -146,8 +147,8 @@ TEST(NormalizingInputFilterCrosTest, ExtendedKey) { // results in normal-looking sequence. TEST(NormalizingInputFilterCrosTest, OtherKey) { MockInputStub stub; - scoped_ptr<protocol::InputFilter> processor = - CreateNormalizingInputFilter(&stub); + scoped_ptr<protocol::InputFilter> processor( + new NormalizingInputFilterCros(&stub)); { InSequence s; @@ -168,8 +169,8 @@ TEST(NormalizingInputFilterCrosTest, OtherKey) { // results in OSKey switching to modifying mode for the normal key. TEST(NormalizingInputFilterCrosTest, ExtendedThenOtherKey) { MockInputStub stub; - scoped_ptr<protocol::InputFilter> processor = - CreateNormalizingInputFilter(&stub); + scoped_ptr<protocol::InputFilter> processor( + new NormalizingInputFilterCros(&stub)); { InSequence s; @@ -192,8 +193,8 @@ TEST(NormalizingInputFilterCrosTest, ExtendedThenOtherKey) { // Test OSKey press followed by mouse event puts the OSKey into modifying mode. TEST(NormalizingInputFilterCrosTest, MouseEvent) { MockInputStub stub; - scoped_ptr<protocol::InputFilter> processor = - CreateNormalizingInputFilter(&stub); + scoped_ptr<protocol::InputFilter> processor( + new NormalizingInputFilterCros(&stub)); { InSequence s; diff --git a/remoting/client/plugin/normalizing_input_filter_mac.cc b/remoting/client/plugin/normalizing_input_filter_mac.cc index 56b327e..36708e9 100644 --- a/remoting/client/plugin/normalizing_input_filter_mac.cc +++ b/remoting/client/plugin/normalizing_input_filter_mac.cc @@ -2,42 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -// NormalizingInputFilterMac is designed to solve the problem of missing keyup -// events on Mac. -// -// PROBLEM -// -// On Mac if user presses CMD and then C key there is no keyup event generated -// for C when user releases the C key before the CMD key. -// The cause is that CMD + C triggers a system action and Chrome injects only a -// keydown event for the C key. Safari shares the same behavior. -// -// SOLUTION -// -// When a keyup event for CMD key happens we will check all prior keydown -// events received and inject corresponding keyup events artificially, with -// the exception of: -// -// SHIFT, CONTROL, OPTION, LEFT CMD, RIGHT CMD and CAPS LOCK -// -// because they are reported by Chrome correctly. -// -// There are a couple cases that this solution doesn't work perfectly, one -// of them leads to duplicated keyup events. -// -// User performs this sequence of actions: -// -// CMD DOWN, C DOWN, CMD UP, C UP -// -// In this case the algorithm will generate: -// -// CMD DOWN, C DOWN, C UP, CMD UP, C UP -// -// Because we artificially generate keyup events the C UP event is duplicated -// as user releases the key after CMD key. This would not be a problem as the -// receiver end will drop this duplicated keyup event. - -#include "remoting/client/plugin/normalizing_input_filter.h" +#include "remoting/client/plugin/normalizing_input_filter_mac.h" #include <map> #include <vector> @@ -62,30 +27,13 @@ const unsigned int kUsbTab = 0x07002b; } // namespace -class NormalizingInputFilterMac : public protocol::InputFilter { - public: - explicit NormalizingInputFilterMac(protocol::InputStub* input_stub); - virtual ~NormalizingInputFilterMac() {} - - // InputFilter overrides. - virtual void InjectKeyEvent(const protocol::KeyEvent& event) OVERRIDE; - - private: - // Generate keyup events for any keys pressed with CMD. - void GenerateKeyupEvents(); - - // A map that stores pressed keycodes and the corresponding key event. - typedef std::map<int, protocol::KeyEvent> KeyPressedMap; - KeyPressedMap key_pressed_map_; - - DISALLOW_COPY_AND_ASSIGN(NormalizingInputFilterMac); -}; - NormalizingInputFilterMac::NormalizingInputFilterMac( protocol::InputStub* input_stub) : protocol::InputFilter(input_stub) { } +NormalizingInputFilterMac::~NormalizingInputFilterMac() {} + void NormalizingInputFilterMac::InjectKeyEvent(const protocol::KeyEvent& event) { DCHECK(event.has_usb_keycode()); @@ -145,10 +93,4 @@ void NormalizingInputFilterMac::GenerateKeyupEvents() { key_pressed_map_.clear(); } -scoped_ptr<protocol::InputFilter> CreateNormalizingInputFilter( - protocol::InputStub* input_stub) { - return scoped_ptr<protocol::InputFilter>( - new NormalizingInputFilterMac(input_stub)); -} - } // namespace remoting diff --git a/remoting/client/plugin/normalizing_input_filter_mac.h b/remoting/client/plugin/normalizing_input_filter_mac.h new file mode 100644 index 0000000..ed1d0d3 --- /dev/null +++ b/remoting/client/plugin/normalizing_input_filter_mac.h @@ -0,0 +1,65 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include <map> + +#include "remoting/protocol/input_filter.h" + +namespace remoting { + +// NormalizingInputFilterMac is designed to solve the problem of missing keyup +// events on Mac. +// +// PROBLEM +// +// On Mac if user presses CMD and then C key there is no keyup event generated +// for C when user releases the C key before the CMD key. +// The cause is that CMD + C triggers a system action and Chrome injects only a +// keydown event for the C key. Safari shares the same behavior. +// +// SOLUTION +// +// When a keyup event for CMD key happens we will check all prior keydown +// events received and inject corresponding keyup events artificially, with +// the exception of: +// +// SHIFT, CONTROL, OPTION, LEFT CMD, RIGHT CMD and CAPS LOCK +// +// because they are reported by Chrome correctly. +// +// There are a couple cases that this solution doesn't work perfectly, one +// of them leads to duplicated keyup events. +// +// User performs this sequence of actions: +// +// CMD DOWN, C DOWN, CMD UP, C UP +// +// In this case the algorithm will generate: +// +// CMD DOWN, C DOWN, C UP, CMD UP, C UP +// +// Because we artificially generate keyup events the C UP event is duplicated +// as user releases the key after CMD key. This would not be a problem as the +// receiver end will drop this duplicated keyup event. +class NormalizingInputFilterMac : public protocol::InputFilter { + public: + explicit NormalizingInputFilterMac(protocol::InputStub* input_stub); + virtual ~NormalizingInputFilterMac(); + + // InputFilter overrides. + virtual void InjectKeyEvent(const protocol::KeyEvent& event) OVERRIDE; + + private: + typedef std::map<int, protocol::KeyEvent> KeyPressedMap; + + // Generate keyup events for any keys pressed with CMD. + void GenerateKeyupEvents(); + + // A map that stores pressed keycodes and the corresponding key event. + KeyPressedMap key_pressed_map_; + + DISALLOW_COPY_AND_ASSIGN(NormalizingInputFilterMac); +}; + +} // namespace remoting diff --git a/remoting/client/plugin/normalizing_input_filter_mac_unittest.cc b/remoting/client/plugin/normalizing_input_filter_mac_unittest.cc index 8221223..2e645e5 100644 --- a/remoting/client/plugin/normalizing_input_filter_mac_unittest.cc +++ b/remoting/client/plugin/normalizing_input_filter_mac_unittest.cc @@ -2,7 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "remoting/client/plugin/normalizing_input_filter.h" +#include "remoting/client/plugin/normalizing_input_filter_mac.h" + #include "remoting/proto/event.pb.h" #include "remoting/protocol/protocol_mock_objects.h" #include "testing/gmock/include/gmock/gmock.h" @@ -46,8 +47,8 @@ KeyEvent MakeKeyEvent(uint32 keycode, bool pressed) { // Test CapsLock press/release. TEST(NormalizingInputFilterMacTest, CapsLock) { MockInputStub stub; - scoped_ptr<protocol::InputFilter> processor = - CreateNormalizingInputFilter(&stub); + scoped_ptr<protocol::InputFilter> processor( + new NormalizingInputFilterMac(&stub)); { InSequence s; @@ -64,8 +65,8 @@ TEST(NormalizingInputFilterMacTest, CapsLock) { // Test without pressing command key. TEST(NormalizingInputFilterMacTest, NoInjection) { MockInputStub stub; - scoped_ptr<protocol::InputFilter> processor = - CreateNormalizingInputFilter(&stub); + scoped_ptr<protocol::InputFilter> processor( + new NormalizingInputFilterMac(&stub)); { InSequence s; @@ -84,8 +85,8 @@ TEST(NormalizingInputFilterMacTest, NoInjection) { // Test pressing command key and other normal keys. TEST(NormalizingInputFilterMacTest, CmdKey) { MockInputStub stub; - scoped_ptr<protocol::InputFilter> processor = - CreateNormalizingInputFilter(&stub); + scoped_ptr<protocol::InputFilter> processor( + new NormalizingInputFilterMac(&stub)); { InSequence s; @@ -145,8 +146,8 @@ TEST(NormalizingInputFilterMacTest, CmdKey) { // Test pressing command and special keys. TEST(NormalizingInputFilterMacTest, SpecialKeys) { MockInputStub stub; - scoped_ptr<protocol::InputFilter> processor = - CreateNormalizingInputFilter(&stub); + scoped_ptr<protocol::InputFilter> processor( + new NormalizingInputFilterMac(&stub)); { InSequence s; @@ -188,8 +189,8 @@ TEST(NormalizingInputFilterMacTest, SpecialKeys) { // Test pressing multiple command keys. TEST(NormalizingInputFilterMacTest, MultipleCmdKeys) { MockInputStub stub; - scoped_ptr<protocol::InputFilter> processor = - CreateNormalizingInputFilter(&stub); + scoped_ptr<protocol::InputFilter> processor( + new NormalizingInputFilterMac(&stub)); { InSequence s; @@ -217,8 +218,8 @@ TEST(NormalizingInputFilterMacTest, MultipleCmdKeys) { // Test press C key before command key. TEST(NormalizingInputFilterMacTest, BeforeCmdKey) { MockInputStub stub; - scoped_ptr<protocol::InputFilter> processor = - CreateNormalizingInputFilter(&stub); + scoped_ptr<protocol::InputFilter> processor( + new NormalizingInputFilterMac(&stub)); { InSequence s; diff --git a/remoting/client/plugin/pepper_input_handler.cc b/remoting/client/plugin/pepper_input_handler.cc index 60a2746..b9ec4e8 100644 --- a/remoting/client/plugin/pepper_input_handler.cc +++ b/remoting/client/plugin/pepper_input_handler.cc @@ -17,11 +17,10 @@ namespace remoting { PepperInputHandler::PepperInputHandler( - pp::Instance* instance, - protocol::InputStub* input_stub) + pp::Instance* instance) : pp::MouseLock(instance), instance_(instance), - input_stub_(input_stub), + input_stub_(NULL), callback_factory_(this), has_focus_(false), mouse_lock_state_(MouseLockDisallowed), @@ -31,8 +30,7 @@ PepperInputHandler::PepperInputHandler( wheel_ticks_y_(0) { } -PepperInputHandler::~PepperInputHandler() { -} +PepperInputHandler::~PepperInputHandler() {} // Helper function to get the USB key code using the Dev InputEvent interface. uint32_t GetUsbKeyCode(pp::KeyboardInputEvent pp_key_event) { @@ -69,7 +67,8 @@ bool PepperInputHandler::HandleInputEvent(const pp::InputEvent& event) { key_event.set_pressed(event.GetType() == PP_INPUTEVENT_TYPE_KEYDOWN); key_event.set_lock_states(lock_states); - input_stub_->InjectKeyEvent(key_event); + if (input_stub_) + input_stub_->InjectKeyEvent(key_event); return true; } @@ -106,7 +105,8 @@ bool PepperInputHandler::HandleInputEvent(const pp::InputEvent& event) { mouse_event.set_delta_y(delta.y()); } - input_stub_->InjectMouseEvent(mouse_event); + if (input_stub_) + input_stub_->InjectMouseEvent(mouse_event); } return true; } @@ -129,7 +129,8 @@ bool PepperInputHandler::HandleInputEvent(const pp::InputEvent& event) { mouse_event.set_delta_y(delta.y()); } - input_stub_->InjectMouseEvent(mouse_event); + if (input_stub_) + input_stub_->InjectMouseEvent(mouse_event); return true; } @@ -175,7 +176,8 @@ bool PepperInputHandler::HandleInputEvent(const pp::InputEvent& event) { mouse_event.set_wheel_ticks_x(ticks_x); mouse_event.set_wheel_ticks_y(ticks_y); - input_stub_->InjectMouseEvent(mouse_event); + if (input_stub_) + input_stub_->InjectMouseEvent(mouse_event); } return true; } diff --git a/remoting/client/plugin/pepper_input_handler.h b/remoting/client/plugin/pepper_input_handler.h index c72243e..d975670 100644 --- a/remoting/client/plugin/pepper_input_handler.h +++ b/remoting/client/plugin/pepper_input_handler.h @@ -27,9 +27,13 @@ class InputStub; class PepperInputHandler : public pp::MouseLock { public: // |instance| must outlive |this|. - PepperInputHandler(pp::Instance* instance, protocol::InputStub* input_stub); + explicit PepperInputHandler(pp::Instance* instance); virtual ~PepperInputHandler(); + void set_input_stub(protocol::InputStub* input_stub) { + input_stub_ = input_stub; + } + bool HandleInputEvent(const pp::InputEvent& event); // Enables locking the mouse when the host sets a completely transparent mouse |