// 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 "ui/events/ozone/evdev/event_converter_evdev_impl.h"

#include <linux/input.h>

#include <memory>
#include <utility>

#include "base/bind.h"
#include "base/files/scoped_file.h"
#include "base/macros.h"
#include "base/message_loop/message_loop.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/events/event.h"
#include "ui/events/keycodes/dom/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"
#include "ui/events/ozone/evdev/event_converter_test_util.h"
#include "ui/events/ozone/evdev/event_factory_evdev.h"
#include "ui/events/ozone/evdev/keyboard_evdev.h"
#include "ui/events/ozone/layout/keyboard_layout_engine_manager.h"
#include "ui/events/test/scoped_event_test_tick_clock.h"

namespace ui {

const char kTestDevicePath[] = "/dev/input/test-device";

class MockEventConverterEvdevImpl : public EventConverterEvdevImpl {
 public:
  MockEventConverterEvdevImpl(base::ScopedFD fd,
                              CursorDelegateEvdev* cursor,
                              DeviceEventDispatcherEvdev* dispatcher)
      : EventConverterEvdevImpl(std::move(fd),
                                base::FilePath(kTestDevicePath),
                                1,
                                EventDeviceInfo(),
                                cursor,
                                dispatcher) {
    SetEnabled(true);
  }
  ~MockEventConverterEvdevImpl() override { SetEnabled(false); }

  // EventConverterEvdevImpl:
  bool HasKeyboard() const override { return true; }
  bool HasTouchpad() const override { return true; }

 private:
  DISALLOW_COPY_AND_ASSIGN(MockEventConverterEvdevImpl);
};

class MockCursorEvdev : public CursorDelegateEvdev {
 public:
  MockCursorEvdev() {}
  ~MockCursorEvdev() override {}

  // CursorDelegateEvdev:
  void MoveCursorTo(gfx::AcceleratedWidget widget,
                    const gfx::PointF& location) override {
    cursor_location_ = location;
  }
  void MoveCursorTo(const gfx::PointF& location) override {
    cursor_location_ = location;
  }
  void MoveCursor(const gfx::Vector2dF& delta) override {
    cursor_location_ = gfx::PointF(delta.x(), delta.y());
  }
  bool IsCursorVisible() override { return 1; }
  gfx::Rect GetCursorConfinedBounds() override {
    NOTIMPLEMENTED();
    return gfx::Rect();
  }
  gfx::PointF GetLocation() override { return cursor_location_; }
  void InitializeOnEvdev() override {}
 private:
  // The location of the mock cursor.
  gfx::PointF cursor_location_;

  DISALLOW_COPY_AND_ASSIGN(MockCursorEvdev);
};

}  // namespace ui

// Test fixture.
class EventConverterEvdevImplTest : public testing::Test {
 public:
  EventConverterEvdevImplTest() {}

  // Overridden from testing::Test:
  void SetUp() override {
    // Set up pipe to satisfy message pump (unused).
    int evdev_io[2];
    if (pipe(evdev_io))
      PLOG(FATAL) << "failed pipe";
    base::ScopedFD events_in(evdev_io[0]);
    events_out_.reset(evdev_io[1]);

    cursor_.reset(new ui::MockCursorEvdev());

    device_manager_ = ui::CreateDeviceManagerForTest();
    event_factory_ = ui::CreateEventFactoryEvdevForTest(
        cursor_.get(), device_manager_.get(),
        ui::KeyboardLayoutEngineManager::GetKeyboardLayoutEngine(),
        base::Bind(&EventConverterEvdevImplTest::DispatchEventForTest,
                   base::Unretained(this)));
    dispatcher_ =
        ui::CreateDeviceEventDispatcherEvdevForTest(event_factory_.get());
    device_.reset(new ui::MockEventConverterEvdevImpl(
        std::move(events_in), cursor_.get(), dispatcher_.get()));

    test_clock_.reset(new ui::test::ScopedEventTestTickClock());
  }

  void TearDown() override {
    device_.reset();
    cursor_.reset();
    events_out_.reset();
    test_clock_.reset();
  }

  ui::MockCursorEvdev* cursor() { return cursor_.get(); }
  ui::MockEventConverterEvdevImpl* device() { return device_.get(); }

  unsigned size() { return dispatched_events_.size(); }
  ui::KeyEvent* dispatched_event(unsigned index) {
    DCHECK_GT(dispatched_events_.size(), index);
    ui::Event* ev = dispatched_events_[index].get();
    DCHECK(ev->IsKeyEvent());
    return ev->AsKeyEvent();
  }
  ui::MouseEvent* dispatched_mouse_event(unsigned index) {
    DCHECK_GT(dispatched_events_.size(), index);
    ui::Event* ev = dispatched_events_[index].get();
    DCHECK(ev->IsMouseEvent());
    return ev->AsMouseEvent();
  }

  void ClearDispatchedEvents() {
    dispatched_events_.clear();
  }

  void DestroyDevice() { device_.reset(); }

  ui::InputController* GetInputController() {
    return event_factory_->input_controller();
  }

  void SetTestNowSeconds(int64_t seconds) {
    test_clock_->SetNowSeconds(seconds);
  }

 private:
  void DispatchEventForTest(ui::Event* event) {
    std::unique_ptr<ui::Event> cloned_event = ui::Event::Clone(*event);
    dispatched_events_.push_back(std::move(cloned_event));
  }

  base::MessageLoopForUI ui_loop_;

  std::unique_ptr<ui::MockCursorEvdev> cursor_;
  std::unique_ptr<ui::DeviceManager> device_manager_;
  std::unique_ptr<ui::EventFactoryEvdev> event_factory_;
  std::unique_ptr<ui::DeviceEventDispatcherEvdev> dispatcher_;
  std::unique_ptr<ui::MockEventConverterEvdevImpl> device_;
  std::unique_ptr<ui::test::ScopedEventTestTickClock> test_clock_;

  std::vector<std::unique_ptr<ui::Event>> dispatched_events_;

  base::ScopedFD events_out_;

  DISALLOW_COPY_AND_ASSIGN(EventConverterEvdevImplTest);
};

TEST_F(EventConverterEvdevImplTest, KeyPress) {
  ui::MockEventConverterEvdevImpl* dev = device();

  struct input_event mock_kernel_queue[] = {
      {{0, 0}, EV_MSC, MSC_SCAN, 0x7002a},
      {{0, 0}, EV_KEY, KEY_BACKSPACE, 1},
      {{0, 0}, EV_SYN, SYN_REPORT, 0},

      {{0, 0}, EV_MSC, MSC_SCAN, 0x7002a},
      {{0, 0}, EV_KEY, KEY_BACKSPACE, 0},
      {{0, 0}, EV_SYN, SYN_REPORT, 0},
  };

  dev->ProcessEvents(mock_kernel_queue, arraysize(mock_kernel_queue));
  EXPECT_EQ(2u, size());

  ui::KeyEvent* event;

  event = dispatched_event(0);
  EXPECT_EQ(ui::ET_KEY_PRESSED, event->type());
  EXPECT_EQ(ui::VKEY_BACK, event->key_code());
  EXPECT_EQ(0, event->flags());

  event = dispatched_event(1);
  EXPECT_EQ(ui::ET_KEY_RELEASED, event->type());
  EXPECT_EQ(ui::VKEY_BACK, event->key_code());
  EXPECT_EQ(0, event->flags());
}

TEST_F(EventConverterEvdevImplTest, KeyRepeat) {
  ui::MockEventConverterEvdevImpl* dev = device();

  struct input_event mock_kernel_queue[] = {
      {{0, 0}, EV_MSC, MSC_SCAN, 0x7002a},
      {{0, 0}, EV_KEY, KEY_BACKSPACE, 1},
      {{0, 0}, EV_SYN, SYN_REPORT, 0},

      {{0, 0}, EV_MSC, MSC_SCAN, 0x7002a},
      {{0, 0}, EV_KEY, KEY_BACKSPACE, 2},
      {{0, 0}, EV_SYN, SYN_REPORT, 0},

      {{0, 0}, EV_MSC, MSC_SCAN, 0x7002a},
      {{0, 0}, EV_KEY, KEY_BACKSPACE, 2},
      {{0, 0}, EV_SYN, SYN_REPORT, 0},

      {{0, 0}, EV_MSC, MSC_SCAN, 0x7002a},
      {{0, 0}, EV_KEY, KEY_BACKSPACE, 0},
      {{0, 0}, EV_SYN, SYN_REPORT, 0},
  };

  dev->ProcessEvents(mock_kernel_queue, arraysize(mock_kernel_queue));
  EXPECT_EQ(2u, size());

  ui::KeyEvent* event;

  event = dispatched_event(0);
  EXPECT_EQ(ui::ET_KEY_PRESSED, event->type());
  EXPECT_EQ(ui::VKEY_BACK, event->key_code());
  EXPECT_EQ(0, event->flags());

  event = dispatched_event(1);
  EXPECT_EQ(ui::ET_KEY_RELEASED, event->type());
  EXPECT_EQ(ui::VKEY_BACK, event->key_code());
  EXPECT_EQ(0, event->flags());
}

TEST_F(EventConverterEvdevImplTest, NoEvents) {
  ui::MockEventConverterEvdevImpl* dev = device();
  dev->ProcessEvents(NULL, 0);
  EXPECT_EQ(0u, size());
}

TEST_F(EventConverterEvdevImplTest, KeyWithModifier) {
  ui::MockEventConverterEvdevImpl* dev = device();

  struct input_event mock_kernel_queue[] = {
      {{0, 0}, EV_MSC, MSC_SCAN, 0x700e1},
      {{0, 0}, EV_KEY, KEY_LEFTSHIFT, 1},
      {{0, 0}, EV_SYN, SYN_REPORT, 0},

      {{0, 0}, EV_MSC, MSC_SCAN, 0x70004},
      {{0, 0}, EV_KEY, KEY_A, 1},
      {{0, 0}, EV_SYN, SYN_REPORT, 0},

      {{0, 0}, EV_MSC, MSC_SCAN, 0x70004},
      {{0, 0}, EV_KEY, KEY_A, 0},
      {{0, 0}, EV_SYN, SYN_REPORT, 0},

      {{0, 0}, EV_MSC, MSC_SCAN, 0x700e1},
      {{0, 0}, EV_KEY, KEY_LEFTSHIFT, 0},
      {{0, 0}, EV_SYN, SYN_REPORT, 0},
  };

  dev->ProcessEvents(mock_kernel_queue, arraysize(mock_kernel_queue));
  EXPECT_EQ(4u, size());

  ui::KeyEvent* event;

  event = dispatched_event(0);
  EXPECT_EQ(ui::ET_KEY_PRESSED, event->type());
  EXPECT_EQ(ui::VKEY_SHIFT, event->key_code());
  EXPECT_EQ(ui::EF_SHIFT_DOWN, event->flags());

  event = dispatched_event(1);
  EXPECT_EQ(ui::ET_KEY_PRESSED, event->type());
  EXPECT_EQ(ui::VKEY_A, event->key_code());
  EXPECT_EQ(ui::EF_SHIFT_DOWN, event->flags());

  event = dispatched_event(2);
  EXPECT_EQ(ui::ET_KEY_RELEASED, event->type());
  EXPECT_EQ(ui::VKEY_A, event->key_code());
  EXPECT_EQ(ui::EF_SHIFT_DOWN, event->flags());

  event = dispatched_event(3);
  EXPECT_EQ(ui::ET_KEY_RELEASED, event->type());
  EXPECT_EQ(ui::VKEY_SHIFT, event->key_code());
  EXPECT_EQ(0, event->flags());
}

TEST_F(EventConverterEvdevImplTest, KeyWithDuplicateModifier) {
  ui::MockEventConverterEvdevImpl* dev = device();

  struct input_event mock_kernel_queue[] = {
      {{0, 0}, EV_MSC, MSC_SCAN, 0x700e1},
      {{0, 0}, EV_KEY, KEY_LEFTCTRL, 1},
      {{0, 0}, EV_SYN, SYN_REPORT, 0},

      {{0, 0}, EV_MSC, MSC_SCAN, 0x700e5},
      {{0, 0}, EV_KEY, KEY_RIGHTCTRL, 1},
      {{0, 0}, EV_SYN, SYN_REPORT, 0},

      {{0, 0}, EV_MSC, MSC_SCAN, 0x7001d},
      {{0, 0}, EV_KEY, KEY_Z, 1},
      {{0, 0}, EV_SYN, SYN_REPORT, 0},

      {{0, 0}, EV_MSC, MSC_SCAN, 0x7001d},
      {{0, 0}, EV_KEY, KEY_Z, 0},
      {{0, 0}, EV_SYN, SYN_REPORT, 0},

      {{0, 0}, EV_MSC, MSC_SCAN, 0x700e1},
      {{0, 0}, EV_KEY, KEY_LEFTCTRL, 0},
      {{0, 0}, EV_SYN, SYN_REPORT, 0},

      {{0, 0}, EV_MSC, MSC_SCAN, 0x700e5},
      {{0, 0}, EV_KEY, KEY_RIGHTCTRL, 0},
      {{0, 0}, EV_SYN, SYN_REPORT, 0},
  };

  dev->ProcessEvents(mock_kernel_queue, arraysize(mock_kernel_queue));
  EXPECT_EQ(6u, size());

  ui::KeyEvent* event;

  event = dispatched_event(0);
  EXPECT_EQ(ui::ET_KEY_PRESSED, event->type());
  EXPECT_EQ(ui::VKEY_CONTROL, event->key_code());
  EXPECT_EQ(ui::EF_CONTROL_DOWN, event->flags());

  event = dispatched_event(1);
  EXPECT_EQ(ui::ET_KEY_PRESSED, event->type());
  EXPECT_EQ(ui::VKEY_CONTROL, event->key_code());
  EXPECT_EQ(ui::EF_CONTROL_DOWN, event->flags());

  event = dispatched_event(2);
  EXPECT_EQ(ui::ET_KEY_PRESSED, event->type());
  EXPECT_EQ(ui::VKEY_Z, event->key_code());
  EXPECT_EQ(ui::EF_CONTROL_DOWN, event->flags());

  event = dispatched_event(3);
  EXPECT_EQ(ui::ET_KEY_RELEASED, event->type());
  EXPECT_EQ(ui::VKEY_Z, event->key_code());
  EXPECT_EQ(ui::EF_CONTROL_DOWN, event->flags());

  event = dispatched_event(4);
  EXPECT_EQ(ui::ET_KEY_RELEASED, event->type());
  EXPECT_EQ(ui::VKEY_CONTROL, event->key_code());
  EXPECT_EQ(ui::EF_CONTROL_DOWN, event->flags());

  event = dispatched_event(5);
  EXPECT_EQ(ui::ET_KEY_RELEASED, event->type());
  EXPECT_EQ(ui::VKEY_CONTROL, event->key_code());
  EXPECT_EQ(0, event->flags());
}

TEST_F(EventConverterEvdevImplTest, KeyWithLock) {
  ui::MockEventConverterEvdevImpl* dev = device();

  struct input_event mock_kernel_queue[] = {
      {{0, 0}, EV_MSC, MSC_SCAN, 0x70039},
      {{0, 0}, EV_KEY, KEY_CAPSLOCK, 1},
      {{0, 0}, EV_SYN, SYN_REPORT, 0},

      {{0, 0}, EV_MSC, MSC_SCAN, 0x70039},
      {{0, 0}, EV_KEY, KEY_CAPSLOCK, 0},
      {{0, 0}, EV_SYN, SYN_REPORT, 0},
  };

  dev->ProcessEvents(mock_kernel_queue, arraysize(mock_kernel_queue));
  EXPECT_EQ(2u, size());

  ui::KeyEvent* event;

  event = dispatched_event(0);
  EXPECT_EQ(ui::ET_KEY_PRESSED, event->type());
  EXPECT_EQ(ui::VKEY_CAPITAL, event->key_code());
  EXPECT_EQ(ui::EF_MOD3_DOWN, event->flags());

  event = dispatched_event(1);
  EXPECT_EQ(ui::ET_KEY_RELEASED, event->type());
  EXPECT_EQ(ui::VKEY_CAPITAL, event->key_code());
  EXPECT_EQ(ui::EF_NONE, event->flags());
}

TEST_F(EventConverterEvdevImplTest, MouseButton) {
  ui::MockEventConverterEvdevImpl* dev = device();

  struct input_event mock_kernel_queue[] = {
      {{0, 0}, EV_KEY, BTN_LEFT, 1},
      {{0, 0}, EV_SYN, SYN_REPORT, 0},

      {{0, 0}, EV_KEY, BTN_LEFT, 0},
      {{0, 0}, EV_SYN, SYN_REPORT, 0},
  };

  dev->ProcessEvents(mock_kernel_queue, arraysize(mock_kernel_queue));
  EXPECT_EQ(2u, size());

  ui::MouseEvent* event;

  event = dispatched_mouse_event(0);
  EXPECT_EQ(ui::ET_MOUSE_PRESSED, event->type());
  EXPECT_EQ(true, event->IsLeftMouseButton());

  event = dispatched_mouse_event(1);
  EXPECT_EQ(ui::ET_MOUSE_RELEASED, event->type());
  EXPECT_EQ(true, event->IsLeftMouseButton());
}

// Test that BTN_BACK and BTN_SIDE are treated as the same button.
TEST_F(EventConverterEvdevImplTest, MouseBackButton) {
  ui::MockEventConverterEvdevImpl* dev = device();

  struct input_event mock_kernel_queue[] = {
      {{0, 0}, EV_KEY, BTN_SIDE, 1},
      {{0, 0}, EV_SYN, SYN_REPORT, 0},

      {{0, 0}, EV_KEY, BTN_BACK, 1},
      {{0, 0}, EV_SYN, SYN_REPORT, 0},

      {{0, 0}, EV_KEY, BTN_SIDE, 0},
      {{0, 0}, EV_SYN, SYN_REPORT, 0},

      {{0, 0}, EV_KEY, BTN_BACK, 0},
      {{0, 0}, EV_SYN, SYN_REPORT, 0}
  };

  dev->ProcessEvents(mock_kernel_queue, arraysize(mock_kernel_queue));
  EXPECT_EQ(2u, size());

  ui::MouseEvent* event = nullptr;

  event = dispatched_mouse_event(0);
  EXPECT_EQ(ui::ET_MOUSE_PRESSED, event->type());
  EXPECT_EQ(ui::EF_BACK_MOUSE_BUTTON, event->changed_button_flags());

  event = dispatched_mouse_event(1);
  EXPECT_EQ(ui::ET_MOUSE_RELEASED, event->type());
  EXPECT_EQ(ui::EF_BACK_MOUSE_BUTTON, event->changed_button_flags());
}

// Test that BTN_FORWARD and BTN_EXTRA are treated as the same button.
TEST_F(EventConverterEvdevImplTest, MouseForwardButton) {
  ui::MockEventConverterEvdevImpl* dev = device();

  struct input_event mock_kernel_queue[] = {
      {{0, 0}, EV_KEY, BTN_FORWARD, 1},
      {{0, 0}, EV_SYN, SYN_REPORT, 0},

      {{0, 0}, EV_KEY, BTN_EXTRA, 1},
      {{0, 0}, EV_SYN, SYN_REPORT, 0},

      {{0, 0}, EV_KEY, BTN_EXTRA, 0},
      {{0, 0}, EV_SYN, SYN_REPORT, 0},

      {{0, 0}, EV_KEY, BTN_FORWARD, 0},
      {{0, 0}, EV_SYN, SYN_REPORT, 0}
  };

  dev->ProcessEvents(mock_kernel_queue, arraysize(mock_kernel_queue));
  EXPECT_EQ(2u, size());

  ui::MouseEvent* event = nullptr;

  event = dispatched_mouse_event(0);
  EXPECT_EQ(ui::ET_MOUSE_PRESSED, event->type());
  EXPECT_EQ(ui::EF_FORWARD_MOUSE_BUTTON, event->changed_button_flags());

  event = dispatched_mouse_event(1);
  EXPECT_EQ(ui::ET_MOUSE_RELEASED, event->type());
  EXPECT_EQ(ui::EF_FORWARD_MOUSE_BUTTON, event->changed_button_flags());
}

TEST_F(EventConverterEvdevImplTest, MouseMove) {
  ui::MockEventConverterEvdevImpl* dev = device();

  struct input_event mock_kernel_queue[] = {
      {{0, 0}, EV_REL, REL_X, 4},
      {{0, 0}, EV_REL, REL_Y, 2},
      {{0, 0}, EV_SYN, SYN_REPORT, 0},
  };

  dev->ProcessEvents(mock_kernel_queue, arraysize(mock_kernel_queue));
  EXPECT_EQ(1u, size());

  ui::MouseEvent* event;

  event = dispatched_mouse_event(0);
  EXPECT_EQ(ui::ET_MOUSE_MOVED, event->type());
  EXPECT_EQ(cursor()->GetLocation(), gfx::PointF(4, 2));
}

TEST_F(EventConverterEvdevImplTest, UnmappedKeyPress) {
  ui::MockEventConverterEvdevImpl* dev = device();

  struct input_event mock_kernel_queue[] = {
      {{0, 0}, EV_KEY, BTN_TOUCH, 1},
      {{0, 0}, EV_SYN, SYN_REPORT, 0},

      {{0, 0}, EV_KEY, BTN_TOUCH, 0},
      {{0, 0}, EV_SYN, SYN_REPORT, 0},
  };

  dev->ProcessEvents(mock_kernel_queue, arraysize(mock_kernel_queue));
  EXPECT_EQ(0u, size());
}

TEST_F(EventConverterEvdevImplTest, ShouldReleaseKeysOnUnplug) {
  ui::MockEventConverterEvdevImpl* dev = device();

  struct input_event mock_kernel_queue[] = {
      {{0, 0}, EV_KEY, KEY_A, 1},
      {{0, 0}, EV_SYN, SYN_REPORT, 0},
  };

  dev->ProcessEvents(mock_kernel_queue, arraysize(mock_kernel_queue));
  EXPECT_EQ(1u, size());

  DestroyDevice();
  EXPECT_EQ(2u, 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());
}

TEST_F(EventConverterEvdevImplTest, ShouldReleaseKeysOnSynDropped) {
  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_SYN, SYN_DROPPED, 0},
  };

  dev->ProcessEvents(mock_kernel_queue, arraysize(mock_kernel_queue));
  EXPECT_EQ(2u, 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());
}

TEST_F(EventConverterEvdevImplTest, ShouldReleaseKeysOnDisable) {
  ui::MockEventConverterEvdevImpl* dev = device();

  struct input_event mock_kernel_queue[] = {
      {{0, 0}, EV_KEY, KEY_A, 1},
      {{0, 0}, EV_SYN, SYN_REPORT, 0},
  };

  dev->ProcessEvents(mock_kernel_queue, arraysize(mock_kernel_queue));
  EXPECT_EQ(1u, size());

  dev->SetEnabled(false);
  EXPECT_EQ(2u, 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());
}


// 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();
  std::vector<ui::DomCode> allowed_keys;
  allowed_keys.push_back(ui::DomCode::POWER);
  dev->SetKeyFilter(true /* enable_filter */, allowed_keys);
  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->SetKeyFilter(false /* enable_filter */, std::vector<ui::DomCode>());
  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();
  std::vector<ui::DomCode> allowed_keys;
  dev->SetKeyFilter(true /* enable_filter */, allowed_keys);
  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());
}

TEST_F(EventConverterEvdevImplTest, ShouldSwapMouseButtonsFromUserPreference) {
  ui::MockEventConverterEvdevImpl* dev = device();

  // Captured from Evoluent VerticalMouse 4.
  const struct input_event mock_kernel_queue[] = {
      {{1510019413, 83905}, EV_MSC, MSC_SCAN, 589825},
      {{1510019413, 83905}, EV_KEY, BTN_LEFT, 1},
      {{1510019413, 83905}, EV_SYN, SYN_REPORT, 0},
      {{1510019413, 171859}, EV_MSC, MSC_SCAN, 589825},
      {{1510019413, 171859}, EV_KEY, BTN_LEFT, 0},
      {{1510019413, 171859}, EV_SYN, SYN_REPORT, 0},

      {{1510019414, 43907}, EV_MSC, MSC_SCAN, 589826},
      {{1510019414, 43907}, EV_KEY, BTN_RIGHT, 1},
      {{1510019414, 43907}, EV_SYN, SYN_REPORT, 0},
      {{1510019414, 171863}, EV_MSC, MSC_SCAN, 589826},
      {{1510019414, 171863}, EV_KEY, BTN_RIGHT, 0},
      {{1510019414, 171863}, EV_SYN, SYN_REPORT, 0},
  };

  SetTestNowSeconds(1510019415);
  ClearDispatchedEvents();
  GetInputController()->SetPrimaryButtonRight(false);
  dev->ProcessEvents(mock_kernel_queue, arraysize(mock_kernel_queue));
  EXPECT_EQ(4u, size());

  ui::MouseEvent* event;
  event = dispatched_mouse_event(0);
  EXPECT_EQ(ui::ET_MOUSE_PRESSED, event->type());
  EXPECT_EQ(true, event->IsLeftMouseButton());

  event = dispatched_mouse_event(1);
  EXPECT_EQ(ui::ET_MOUSE_RELEASED, event->type());
  EXPECT_EQ(true, event->IsLeftMouseButton());

  event = dispatched_mouse_event(2);
  EXPECT_EQ(ui::ET_MOUSE_PRESSED, event->type());
  EXPECT_EQ(true, event->IsRightMouseButton());

  event = dispatched_mouse_event(3);
  EXPECT_EQ(ui::ET_MOUSE_RELEASED, event->type());
  EXPECT_EQ(true, event->IsRightMouseButton());

  // Captured from Evoluent VerticalMouse 4.
  const struct input_event mock_kernel_queue2[] = {
      {{1510019415, 747945}, EV_MSC, MSC_SCAN, 589825},
      {{1510019415, 747945}, EV_KEY, BTN_LEFT, 1},
      {{1510019415, 747945}, EV_SYN, SYN_REPORT, 0},
      {{1510019415, 859942}, EV_MSC, MSC_SCAN, 589825},
      {{1510019415, 859942}, EV_KEY, BTN_LEFT, 0},
      {{1510019415, 859942}, EV_SYN, SYN_REPORT, 0},

      {{1510019416, 459916}, EV_MSC, MSC_SCAN, 589826},
      {{1510019416, 459916}, EV_KEY, BTN_RIGHT, 1},
      {{1510019416, 459916}, EV_SYN, SYN_REPORT, 0},
      {{1510019416, 555892}, EV_MSC, MSC_SCAN, 589826},
      {{1510019416, 555892}, EV_KEY, BTN_RIGHT, 0},
      {{1510019416, 555892}, EV_SYN, SYN_REPORT, 0},
  };
  SetTestNowSeconds(1510019417);

  ClearDispatchedEvents();
  GetInputController()->SetPrimaryButtonRight(true);
  dev->ProcessEvents(mock_kernel_queue2, arraysize(mock_kernel_queue2));
  EXPECT_EQ(4u, size());

  event = dispatched_mouse_event(0);
  EXPECT_EQ(ui::ET_MOUSE_PRESSED, event->type());
  EXPECT_EQ(true, event->IsRightMouseButton());

  event = dispatched_mouse_event(1);
  EXPECT_EQ(ui::ET_MOUSE_RELEASED, event->type());
  EXPECT_EQ(true, event->IsRightMouseButton());

  event = dispatched_mouse_event(2);
  EXPECT_EQ(ui::ET_MOUSE_PRESSED, event->type());
  EXPECT_EQ(true, event->IsLeftMouseButton());

  event = dispatched_mouse_event(3);
  EXPECT_EQ(ui::ET_MOUSE_RELEASED, event->type());
  EXPECT_EQ(true, event->IsLeftMouseButton());
}
