diff options
Diffstat (limited to 'views/focus')
-rw-r--r-- | views/focus/accelerator_handler.h | 12 | ||||
-rw-r--r-- | views/focus/accelerator_handler_win.cc | 19 | ||||
-rw-r--r-- | views/focus/focus_manager_unittest.cc | 132 |
3 files changed, 158 insertions, 5 deletions
diff --git a/views/focus/accelerator_handler.h b/views/focus/accelerator_handler.h index 618f541..c440c6b 100644 --- a/views/focus/accelerator_handler.h +++ b/views/focus/accelerator_handler.h @@ -5,10 +5,16 @@ #ifndef VIEWS_FOCUS_ACCELERATOR_HANDLER_H_ #define VIEWS_FOCUS_ACCELERATOR_HANDLER_H_ +#include "build/build_config.h" + #if defined(OS_LINUX) #include <gdk/gdk.h> #endif +#if defined(OS_WIN) +#include <set> +#endif + #include "base/message_loop.h" namespace views { @@ -27,8 +33,10 @@ class AcceleratorHandler : public MessageLoopForUI::Dispatcher { #endif private: -#if defined(OS_LINUX) - // Last key pressed and consumed as an accelerator. +#if defined(OS_WIN) + // The keys currently pressed and consumed by the FocusManager. + std::set<WPARAM> pressed_keys_; +#else // OS_LINUX guint last_key_pressed_; #endif diff --git a/views/focus/accelerator_handler_win.cc b/views/focus/accelerator_handler_win.cc index f617c6f..ee5c5b7 100644 --- a/views/focus/accelerator_handler_win.cc +++ b/views/focus/accelerator_handler_win.cc @@ -29,9 +29,22 @@ bool AcceleratorHandler::Dispatch(const MSG& msg) { msg.lParam & 0xFFFF, (msg.lParam & 0xFFFF0000) >> 16); process_message = focus_manager->OnKeyEvent(event); - // TODO(jcampan): http://crbug.com/23383 We should not translate and - // dispatch the associated WM_KEYUP if process_message - // is true. + if (!process_message) { + // Record that this key is pressed so we can remember not to + // translate and dispatch the associated WM_KEYUP. + pressed_keys_.insert(msg.wParam); + } + break; + } + case WM_KEYUP: + case WM_SYSKEYUP: { + std::set<WPARAM>::iterator iter = pressed_keys_.find(msg.wParam); + if (iter != pressed_keys_.end()) { + // Don't translate/dispatch the KEYUP since we have eaten the + // associated KEYDOWN. + pressed_keys_.erase(iter); + return true; + } break; } } diff --git a/views/focus/focus_manager_unittest.cc b/views/focus/focus_manager_unittest.cc index 63ba287..40abff6 100644 --- a/views/focus/focus_manager_unittest.cc +++ b/views/focus/focus_manager_unittest.cc @@ -208,6 +208,16 @@ class FocusManagerTest : public testing::Test, public WindowDelegate { GetFocusManager()->AddFocusChangeListener(listener); } +#if defined(OS_WIN) + void PostKeyDown(base::KeyboardCode key_code) { + ::PostMessage(window_->GetNativeWindow(), WM_KEYDOWN, key_code, 0); + } + + void PostKeyUp(base::KeyboardCode key_code) { + ::PostMessage(window_->GetNativeWindow(), WM_KEYUP, key_code, 0); + } +#endif + private: FocusChangeListener* focus_change_listener_; MessageLoopForUI message_loop_; @@ -1170,4 +1180,126 @@ TEST_F(FocusManagerTest, CallsSelfDeletingAcceleratorTarget) { EXPECT_EQ(target.accelerator_count(), 1); } +class MessageTrackingView : public View { + public: + MessageTrackingView() : accelerator_pressed_(false) { + } + + virtual bool OnKeyPressed(const KeyEvent& e) { + keys_pressed_.push_back(e.GetKeyCode()); + return true; + } + + virtual bool OnKeyReleased(const KeyEvent& e) { + keys_released_.push_back(e.GetKeyCode()); + return true; + } + + virtual bool AcceleratorPressed(const Accelerator& accelerator) { + accelerator_pressed_ = true; + return true; + } + + void Reset() { + accelerator_pressed_ = false; + keys_pressed_.clear(); + keys_released_.clear(); + } + + const std::vector<base::KeyboardCode>& keys_pressed() const { + return keys_pressed_; + } + + const std::vector<base::KeyboardCode>& keys_released() const { + return keys_released_; + } + + bool accelerator_pressed() const { + return accelerator_pressed_; + } + + private: + bool accelerator_pressed_; + std::vector<base::KeyboardCode> keys_pressed_; + std::vector<base::KeyboardCode> keys_released_; + + DISALLOW_COPY_AND_ASSIGN(MessageTrackingView); +}; + +#if defined(OS_WIN) +// Tests that the keyup messages are eaten for accelerators. +TEST_F(FocusManagerTest, IgnoreKeyupForAccelerators) { + FocusManager* focus_manager = GetFocusManager(); + MessageTrackingView* mtv = new MessageTrackingView(); + mtv->AddAccelerator(Accelerator(base::VKEY_0, false, false, false)); + mtv->AddAccelerator(Accelerator(base::VKEY_1, false, false, false)); + content_view_->AddChildView(mtv); + focus_manager->SetFocusedView(mtv); + + // First send a non-accelerator key sequence. + PostKeyDown(base::VKEY_9); + PostKeyUp(base::VKEY_9); + AcceleratorHandler accelerator_handler; + MessageLoopForUI::current()->PostTask(FROM_HERE, new MessageLoop::QuitTask()); + MessageLoopForUI::current()->Run(&accelerator_handler); + // Make sure we get a key-up and key-down. + ASSERT_EQ(1, mtv->keys_pressed().size()); + EXPECT_EQ(base::VKEY_9, mtv->keys_pressed().at(0)); + ASSERT_EQ(1, mtv->keys_released().size()); + EXPECT_EQ(base::VKEY_9, mtv->keys_released().at(0)); + EXPECT_FALSE(mtv->accelerator_pressed()); + mtv->Reset(); + + // Same thing with repeat and more than one key at once. + PostKeyDown(base::VKEY_9); + PostKeyDown(base::VKEY_9); + PostKeyDown(base::VKEY_8); + PostKeyDown(base::VKEY_9); + PostKeyDown(base::VKEY_7); + PostKeyUp(base::VKEY_9); + PostKeyUp(base::VKEY_7); + PostKeyUp(base::VKEY_8); + MessageLoopForUI::current()->PostTask(FROM_HERE, new MessageLoop::QuitTask()); + MessageLoopForUI::current()->Run(&accelerator_handler); + // Make sure we get a key-up and key-down. + ASSERT_EQ(5, mtv->keys_pressed().size()); + EXPECT_EQ(base::VKEY_9, mtv->keys_pressed().at(0)); + EXPECT_EQ(base::VKEY_9, mtv->keys_pressed().at(1)); + EXPECT_EQ(base::VKEY_8, mtv->keys_pressed().at(2)); + EXPECT_EQ(base::VKEY_9, mtv->keys_pressed().at(3)); + EXPECT_EQ(base::VKEY_7, mtv->keys_pressed().at(4)); + ASSERT_EQ(3, mtv->keys_released().size()); + EXPECT_EQ(base::VKEY_9, mtv->keys_released().at(0)); + EXPECT_EQ(base::VKEY_7, mtv->keys_released().at(1)); + EXPECT_EQ(base::VKEY_8, mtv->keys_released().at(2)); + EXPECT_FALSE(mtv->accelerator_pressed()); + mtv->Reset(); + + // Now send an accelerator key sequence. + PostKeyDown(base::VKEY_0); + PostKeyUp(base::VKEY_0); + MessageLoopForUI::current()->PostTask(FROM_HERE, new MessageLoop::QuitTask()); + MessageLoopForUI::current()->Run(&accelerator_handler); + EXPECT_TRUE(mtv->keys_pressed().empty()); + EXPECT_TRUE(mtv->keys_released().empty()); + EXPECT_TRUE(mtv->accelerator_pressed()); + mtv->Reset(); + + // Same thing with repeat and more than one key at once. + PostKeyDown(base::VKEY_0); + PostKeyDown(base::VKEY_1); + PostKeyDown(base::VKEY_1); + PostKeyDown(base::VKEY_0); + PostKeyDown(base::VKEY_0); + PostKeyUp(base::VKEY_1); + PostKeyUp(base::VKEY_0); + MessageLoopForUI::current()->PostTask(FROM_HERE, new MessageLoop::QuitTask()); + MessageLoopForUI::current()->Run(&accelerator_handler); + EXPECT_TRUE(mtv->keys_pressed().empty()); + EXPECT_TRUE(mtv->keys_released().empty()); + EXPECT_TRUE(mtv->accelerator_pressed()); + mtv->Reset(); +} +#endif + } // namespace views |