Commit 988070a5 authored by pkotwicz's avatar pkotwicz Committed by Commit bot

[Ozone] Fix disabling keyboard in maximized mode

This CL:
- Fixes EventConverterEvdev::SetAllowedKeys() to block disallowed keys
- Dispatches a synthetic key release event for any blocked pressed keys when
  EventConverterEvdev::SetAllowedKeys() is called instead of waiting till the
  user releases the key.

BUG=465611
TEST=EventConverterEvdevImplTest.*

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

Cr-Commit-Position: refs/heads/master@{#320170}
parent 46a8b676
......@@ -82,12 +82,29 @@ bool EventConverterEvdevImpl::HasCapsLockLed() const {
void EventConverterEvdevImpl::SetAllowedKeys(
scoped_ptr<std::set<DomCode>> allowed_keys) {
DCHECK(HasKeyboard());
allowed_keys_ = allowed_keys.Pass();
if (!allowed_keys) {
blocked_keys_.reset();
return;
}
blocked_keys_.set();
for (const DomCode& it : *allowed_keys) {
int evdev_code =
NativeCodeToEvdevCode(KeycodeConverter::DomCodeToNativeKeycode(it));
blocked_keys_.reset(evdev_code);
}
// Release any pressed blocked keys.
base::TimeDelta timestamp = ui::EventTimeForNow();
for (int key = 0; key < KEY_CNT; ++key) {
if (blocked_keys_.test(key))
OnKeyChange(key, false /* down */, timestamp);
}
}
void EventConverterEvdevImpl::AllowAllKeys() {
DCHECK(HasKeyboard());
allowed_keys_.reset();
blocked_keys_.reset();
}
void EventConverterEvdevImpl::OnStopped() {
......@@ -154,9 +171,7 @@ void EventConverterEvdevImpl::OnKeyChange(unsigned int key,
return;
// Apply key filter (releases for previously pressed keys are excepted).
DomCode key_code =
KeycodeConverter::NativeKeycodeToDomCode(EvdevCodeToNativeCode(key));
if (down && allowed_keys_ && allowed_keys_->count(key_code))
if (down && blocked_keys_.test(key))
return;
// State transition: !(down) -> (down)
......
......@@ -5,7 +5,7 @@
#ifndef UI_EVENTS_OZONE_EVDEV_EVENT_CONVERTER_EVDEV_IMPL_H_
#define UI_EVENTS_OZONE_EVDEV_EVENT_CONVERTER_EVDEV_IMPL_H_
#include <set>
#include <bitset>
#include "base/files/file_path.h"
#include "base/message_loop/message_pump_libevent.h"
......@@ -78,9 +78,8 @@ class EVENTS_OZONE_EVDEV_EXPORT EventConverterEvdevImpl
// Controller for watching the input fd.
base::MessagePumpLibevent::FileDescriptorWatcher controller_;
// The keys which should be processed. nullptr if all keys should be
// processed.
scoped_ptr<std::set<DomCode>> allowed_keys_;
// The evdev codes of the keys which should be blocked.
std::bitset<KEY_CNT> blocked_keys_;
// Pressed keys bitset.
std::bitset<KEY_CNT> key_state_;
......
......@@ -2,14 +2,13 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include <linux/input.h>
#include "base/bind.h"
#include "base/memory/scoped_ptr.h"
#include "base/memory/scoped_vector.h"
#include "base/message_loop/message_loop.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/events/event.h"
#include "ui/events/keycodes/dom3/dom_code.h"
#include "ui/events/keycodes/keyboard_codes.h"
#include "ui/events/ozone/device/device_manager.h"
#include "ui/events/ozone/evdev/cursor_delegate_evdev.h"
......@@ -19,6 +18,8 @@
#include "ui/events/ozone/evdev/keyboard_evdev.h"
#include "ui/events/ozone/layout/keyboard_layout_engine_manager.h"
#include <linux/input.h>
namespace ui {
const char kTestDevicePath[] = "/dev/input/test-device";
......@@ -127,6 +128,10 @@ class EventConverterEvdevImplTest : public testing::Test {
return static_cast<ui::MouseEvent*>(ev);
}
void ClearDispatchedEvents() {
dispatched_events_.clear();
}
void DestroyDevice() { device_.reset(); }
private:
......@@ -467,3 +472,102 @@ TEST_F(EventConverterEvdevImplTest, ShouldReleaseKeysOnSynDropped) {
EXPECT_EQ(ui::ET_KEY_RELEASED, event->type());
EXPECT_EQ(ui::VKEY_A, event->key_code());
}
// Test that SetAllowedKeys() causes events for non-allowed keys to be dropped.
TEST_F(EventConverterEvdevImplTest, SetAllowedKeys) {
ui::MockEventConverterEvdevImpl* dev = device();
struct input_event mock_kernel_queue[] = {
{{0, 0}, EV_KEY, KEY_A, 1},
{{0, 0}, EV_SYN, SYN_REPORT, 0},
{{0, 0}, EV_KEY, KEY_A, 0},
{{0, 0}, EV_SYN, SYN_REPORT, 0},
{{0, 0}, EV_KEY, KEY_POWER, 1},
{{0, 0}, EV_SYN, SYN_REPORT, 0},
{{0, 0}, EV_KEY, KEY_POWER, 0},
{{0, 0}, EV_KEY, SYN_REPORT, 0},
};
dev->ProcessEvents(mock_kernel_queue, arraysize(mock_kernel_queue));
ASSERT_EQ(4u, size());
ui::KeyEvent* event = dispatched_event(0);
EXPECT_EQ(ui::ET_KEY_PRESSED, event->type());
EXPECT_EQ(ui::VKEY_A, event->key_code());
event = dispatched_event(1);
EXPECT_EQ(ui::ET_KEY_RELEASED, event->type());
EXPECT_EQ(ui::VKEY_A, event->key_code());
event = dispatched_event(2);
EXPECT_EQ(ui::ET_KEY_PRESSED, event->type());
EXPECT_EQ(ui::VKEY_POWER, event->key_code());
event = dispatched_event(3);
EXPECT_EQ(ui::ET_KEY_RELEASED, event->type());
EXPECT_EQ(ui::VKEY_POWER, event->key_code());
ClearDispatchedEvents();
scoped_ptr<std::set<ui::DomCode>> allowed_keys(new std::set<ui::DomCode>);
allowed_keys->insert(ui::DomCode::POWER);
dev->SetAllowedKeys(allowed_keys.Pass());
dev->ProcessEvents(mock_kernel_queue, arraysize(mock_kernel_queue));
ASSERT_EQ(2u, size());
event = dispatched_event(0);
EXPECT_EQ(ui::ET_KEY_PRESSED, event->type());
EXPECT_EQ(ui::VKEY_POWER, event->key_code());
event = dispatched_event(1);
EXPECT_EQ(ui::ET_KEY_RELEASED, event->type());
EXPECT_EQ(ui::VKEY_POWER, event->key_code());
ClearDispatchedEvents();
dev->AllowAllKeys();
dev->ProcessEvents(mock_kernel_queue, arraysize(mock_kernel_queue));
event = dispatched_event(0);
EXPECT_EQ(ui::ET_KEY_PRESSED, event->type());
EXPECT_EQ(ui::VKEY_A, event->key_code());
event = dispatched_event(1);
EXPECT_EQ(ui::ET_KEY_RELEASED, event->type());
EXPECT_EQ(ui::VKEY_A, event->key_code());
event = dispatched_event(2);
EXPECT_EQ(ui::ET_KEY_PRESSED, event->type());
EXPECT_EQ(ui::VKEY_POWER, event->key_code());
event = dispatched_event(3);
EXPECT_EQ(ui::ET_KEY_RELEASED, event->type());
EXPECT_EQ(ui::VKEY_POWER, event->key_code());
}
// Test that if a non-allowed key is pressed when SetAllowedKeys() is called
// that the non-allowed key is released.
TEST_F(EventConverterEvdevImplTest, SetAllowedKeysBlockedKeyPressed) {
ui::MockEventConverterEvdevImpl* dev = device();
struct input_event key_press[] = {
{{0, 0}, EV_KEY, KEY_A, 1},
{{0, 0}, EV_SYN, SYN_REPORT, 0},
};
struct input_event key_release[] = {
{{0, 0}, EV_KEY, KEY_A, 0},
{{0, 0}, EV_SYN, SYN_REPORT, 0},
};
dev->ProcessEvents(key_press, arraysize(key_press));
ASSERT_EQ(1u, size());
ui::KeyEvent* event = dispatched_event(0);
EXPECT_EQ(ui::ET_KEY_PRESSED, event->type());
// Block all key events. Calling SetAllowKeys() should dispatch a synthetic
// key release for VKEY_A.
ClearDispatchedEvents();
scoped_ptr<std::set<ui::DomCode>> allowed_keys(new std::set<ui::DomCode>);
dev->SetAllowedKeys(allowed_keys.Pass());
ASSERT_EQ(1u, size());
event = dispatched_event(0);
EXPECT_EQ(ui::ET_KEY_RELEASED, event->type());
// The real key release should be dropped, whenever it comes.
ClearDispatchedEvents();
dev->ProcessEvents(key_release, arraysize(key_release));
ASSERT_EQ(0u, size());
}
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