=== added file 'include/common/mir/time/steady_timer_fd.h'
--- include/common/mir/time/steady_timer_fd.h 1970-01-01 00:00:00 +0000
+++ include/common/mir/time/steady_timer_fd.h 2016-10-12 07:29:58 +0000
@@ -0,0 +1,46 @@
+/*
+ * Copyright © 2016 Canonical Ltd.
+ *
+ * This program is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see .
+ *
+ * Authored by: Andreas Pokorny
+ */
+
+#ifndef MIR_TIME_STEADY_TIMER_FD_
+#define MIR_TIME_STEADY_TIMER_FD_
+
+#include "mir/time/timer_fd.h"
+
+namespace mir
+{
+namespace time
+{
+
+/**
+ * SteadyTimerFd implements TimerFd using timer fds and using CLOCK_MONOTONIC.
+ */
+class SteadyTimerFd : public TimerFd
+{
+public:
+ SteadyTimerFd();
+ Fd const& get_fd() override;
+ void schedule_in(Duration duration) override;
+ void cancel() override;
+private:
+ mir::Fd timer;
+};
+
+}
+}
+
+#endif
=== added file 'include/common/mir/time/timer_fd.h'
--- include/common/mir/time/timer_fd.h 1970-01-01 00:00:00 +0000
+++ include/common/mir/time/timer_fd.h 2016-10-12 07:29:58 +0000
@@ -0,0 +1,65 @@
+/*
+ * Copyright © 2016 Canonical Ltd.
+ *
+ * This program is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see .
+ *
+ * Authored by: Andreas Pokorny
+ */
+
+#ifndef MIR_TIME_TIMER_FD_H_
+#define MIR_TIME_TIMER_FD_H_
+
+#include "mir/fd.h"
+#include "mir/time/types.h"
+
+#include
+
+namespace mir
+{
+namespace time
+{
+
+/**
+ * TimerFd is a timer that notifies via a file descriptor.
+ */
+class TimerFd
+{
+public:
+ TimerFd() = default;
+ virtual ~TimerFd() = default;
+
+ /**
+ * Get access to the file descriptor
+ */
+ virtual Fd const& get_fd() = 0;
+
+ /**
+ * Configure the timer monitored by the file descriptor to expire after the given \a duration.
+ *
+ * \param[in] duration the time to delay
+ */
+ virtual void schedule_in(Duration duration) = 0;
+ /**
+ * Cancel the timer.
+ *
+ * After that call the timer can be configured again using schedule_for.
+ */
+ virtual void cancel() = 0;
+protected:
+ TimerFd(TimerFd const&) = delete;
+ TimerFd& operator=(TimerFd const&) = delete;
+};
+
+}
+}
+#endif
=== modified file 'src/common/symbols.map'
--- src/common/symbols.map 2016-10-12 06:03:15 +0000
+++ src/common/symbols.map 2016-10-12 07:29:58 +0000
@@ -364,6 +364,12 @@
mir::output_type_name*;
MirSurfaceOutputEvent::refresh_rate*;
MirSurfaceOutputEvent::set_refresh_rate*;
+ mir::time::SteadyTimerFd::SteadyTimerFd*;
+ mir::time::SteadyTimerFd::get_fd*;
+ mir::time::SteadyTimerFd::schedule_in*;
+ mir::time::SteadyTimerFd::cancel*;
+ typeinfo?for?mir::time::SteadyTimerFd;
+ vtable?for?mir::time::SteadyTimerFd;
};
local: *;
};
=== modified file 'src/common/time/CMakeLists.txt'
--- src/common/time/CMakeLists.txt 2015-02-22 07:46:25 +0000
+++ src/common/time/CMakeLists.txt 2016-10-12 07:29:58 +0000
@@ -1,5 +1,8 @@
ADD_LIBRARY(
mirtime OBJECT
+ ${CMAKE_SOURCE_DIR}/include/common/mir/time/timer_fd.h
+ ${CMAKE_SOURCE_DIR}/include/common/mir/time/steady_timer_fd.h
steady_clock.cpp
+ steady_timer_fd.cpp
)
=== added file 'src/common/time/steady_timer_fd.cpp'
--- src/common/time/steady_timer_fd.cpp 1970-01-01 00:00:00 +0000
+++ src/common/time/steady_timer_fd.cpp 2016-10-12 07:29:58 +0000
@@ -0,0 +1,54 @@
+/*
+ * Copyright © 2016 Canonical Ltd.
+ *
+ * This program is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see .
+ *
+ * Authored by: Andreas Pokorny
+ */
+
+#include "mir/time/steady_timer_fd.h"
+#include
+#include
+
+namespace mt = mir::time;
+
+mt::SteadyTimerFd::SteadyTimerFd()
+ : timer{timerfd_create(CLOCK_MONOTONIC, TFD_CLOEXEC | TFD_NONBLOCK)}
+{
+}
+
+mir::Fd const& mt::SteadyTimerFd::get_fd()
+{
+ return timer;
+}
+
+void mt::SteadyTimerFd::schedule_in(mir::time::Duration delay)
+{
+ using namespace std::chrono;
+ auto const in_seconds = duration_cast(delay);
+ itimerspec delay_spec;
+
+ delay_spec.it_value.tv_sec = in_seconds.count();
+ delay_spec.it_value.tv_nsec = nanoseconds(delay - in_seconds).count();
+ delay_spec.it_interval.tv_sec = 0;
+ delay_spec.it_interval.tv_nsec = 0;
+
+ const int relative_timeout = 0;
+ timerfd_settime(timer, relative_timeout, &delay_spec, nullptr);
+}
+
+void mt::SteadyTimerFd::cancel()
+{
+ const itimerspec cancel_timer = {{0,0},{0,0}};
+ timerfd_settime(timer, 0, &cancel_timer, nullptr);
+}
=== modified file 'src/platforms/evdev/CMakeLists.txt'
--- src/platforms/evdev/CMakeLists.txt 2016-08-10 07:57:05 +0000
+++ src/platforms/evdev/CMakeLists.txt 2016-10-12 07:29:58 +0000
@@ -18,13 +18,22 @@
add_library(mirevdevutilsobjects OBJECT
evdev_device_detection.cpp
button_utils.cpp
+ key_repeater.cpp
+ key_repeater.h
+ steady_timer_fd_factory.cpp
+ steady_timer_fd_factory.h
)
add_library(mirplatforminputevdevobjects OBJECT
libinput_device.cpp
+ libinput_device.h
libinput_device_ptr.cpp
+ libinput_device_ptr.h
libinput_ptr.cpp
+ libinput_ptr.h
platform.cpp
+ platform.h
+ timer_fd_factory.h
)
add_library(mirplatforminputevdev MODULE
=== added file 'src/platforms/evdev/key_repeater.cpp'
--- src/platforms/evdev/key_repeater.cpp 1970-01-01 00:00:00 +0000
+++ src/platforms/evdev/key_repeater.cpp 2016-10-12 07:29:58 +0000
@@ -0,0 +1,102 @@
+/*
+ * Copyright © 2016 Canonical Ltd.
+ *
+ * This program is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ *
+ * Authored by: Andreas Pokorny
+ */
+
+#include "timer_fd_factory.h"
+#include "key_repeater.h"
+
+#include "mir/time/timer_fd.h"
+
+namespace mie = mir::input::evdev;
+namespace mt = mir::time;
+
+mie::KeyRepeater::KeyRepeater(TimerFdFactory const& timers,
+ std::function const& send_repeat_key)
+ : timers{timers}, send_repeat{send_repeat_key}
+{
+}
+
+mie::KeyRepeater::~KeyRepeater() = default;
+
+void mie::KeyRepeater::enable(std::chrono::milliseconds repeat_delay, std::chrono::milliseconds repeat_interval)
+{
+ enabled_ = true;
+ this->repeat_delay = repeat_delay;
+ this->repeat_interval = repeat_interval;
+}
+
+void mie::KeyRepeater::disable()
+{
+ enabled_ = false;
+ if (timer)
+ {
+ timer->cancel();
+ timer.reset();
+ }
+ depressed_keys.clear();
+}
+
+void mie::KeyRepeater::press(int32_t code)
+{
+ if (enabled_)
+ {
+ if (!timer)
+ {
+ timer = timers.create_timer([this]{handle_timeout();});
+ timer->schedule_in(repeat_delay);
+ }
+ depressed_keys.insert(code);
+ }
+}
+
+void mie::KeyRepeater::release(int32_t code)
+{
+ bool const was_pressed = depressed_keys.erase(code);
+ if (was_pressed && depressed_keys.empty() && timer)
+ {
+ timer->cancel();
+ timer.reset();
+ }
+}
+
+void mie::KeyRepeater::handle_timeout()
+{
+ if (enabled_)
+ {
+ if (!timer)
+ timer = timers.create_timer([this]{handle_timeout();});
+ timer->schedule_in(repeat_interval);
+
+ for (auto const code : depressed_keys)
+ send_repeat(code);
+ }
+}
+
+bool mie::KeyRepeater::enabled() const
+{
+ return enabled_;
+}
+
+std::chrono::milliseconds mie::KeyRepeater::delay() const
+{
+ return repeat_delay;
+}
+
+std::chrono::milliseconds mie::KeyRepeater::interval() const
+{
+ return repeat_interval;
+}
=== added file 'src/platforms/evdev/key_repeater.h'
--- src/platforms/evdev/key_repeater.h 1970-01-01 00:00:00 +0000
+++ src/platforms/evdev/key_repeater.h 2016-10-12 07:29:58 +0000
@@ -0,0 +1,67 @@
+/*
+ * Copyright © 2016 Canonical Ltd.
+ *
+ * This program is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ *
+ * Authored by: Andreas Pokorny
+ */
+
+#ifndef MIR_INPUT_EVDEV_KEY_REPEATER_H_
+#define MIR_INPUT_EVDEV_KEY_REPEATER_H_
+
+#include
+#include
+#include
+#include
+
+namespace mir
+{
+namespace time
+{
+class TimerFd;
+}
+namespace input
+{
+namespace evdev
+{
+class TimerFdFactory;
+
+struct KeyRepeater
+{
+ KeyRepeater(TimerFdFactory const& timers,
+ std::function const& send_repeat_key);
+ ~KeyRepeater();
+ void enable(std::chrono::milliseconds repeat_delay, std::chrono::milliseconds repeat_interval);
+ void disable();
+ bool enabled() const;
+ std::chrono::milliseconds delay() const;
+ std::chrono::milliseconds interval() const;
+ void press(int32_t code);
+ void release(int32_t code);
+
+private:
+ void handle_timeout();
+ TimerFdFactory const& timers;
+ bool enabled_{true};
+
+ std::chrono::milliseconds repeat_delay{500};
+ std::chrono::milliseconds repeat_interval{50};
+
+ std::function send_repeat;
+ std::unordered_set depressed_keys;
+ std::unique_ptr timer;
+};
+}
+}
+}
+#endif
=== added file 'src/platforms/evdev/steady_timer_fd_factory.cpp'
--- src/platforms/evdev/steady_timer_fd_factory.cpp 1970-01-01 00:00:00 +0000
+++ src/platforms/evdev/steady_timer_fd_factory.cpp 2016-10-12 07:29:58 +0000
@@ -0,0 +1,67 @@
+/*
+ * Copyright © 2016 Canonical Ltd.
+ *
+ * This program is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see .
+ *
+ * Authored by: Andreas Pokorny
+ */
+
+#include "steady_timer_fd_factory.h"
+#include "mir/time/steady_timer_fd.h"
+#include "mir/dispatch/readable_fd.h"
+
+namespace mie = mir::input::evdev;
+namespace md = mir::dispatch;
+namespace mt = mir::time;
+
+namespace
+{
+
+struct DispatchableTimerFd : mt::SteadyTimerFd
+{
+public:
+ DispatchableTimerFd(md::MultiplexingDispatchable& dispatchable,
+ std::function const& callback) :
+ readable_fd{std::make_shared(get_fd(), callback)},
+ dispatchable{dispatchable}
+ {
+ }
+
+ void schedule_in(mir::time::Duration delay) override
+ {
+ mt::SteadyTimerFd::schedule_in(delay);
+ dispatchable.add_watch(readable_fd);
+ }
+
+ void cancel() override
+ {
+ mt::SteadyTimerFd::cancel();
+ dispatchable.remove_watch(readable_fd);
+ }
+
+private:
+ std::shared_ptr const readable_fd;
+ md::MultiplexingDispatchable& dispatchable;
+};
+
+}
+
+mie::SteadyTimerFdFactory::SteadyTimerFdFactory(md::MultiplexingDispatchable& dispatchable)
+ : dispatchable(dispatchable)
+{
+}
+
+std::unique_ptr mie::SteadyTimerFdFactory::SteadyTimerFdFactory::create_timer(std::function const& callback_on_timeout) const
+{
+ return std::make_unique(dispatchable, callback_on_timeout);
+}
=== added file 'src/platforms/evdev/steady_timer_fd_factory.h'
--- src/platforms/evdev/steady_timer_fd_factory.h 1970-01-01 00:00:00 +0000
+++ src/platforms/evdev/steady_timer_fd_factory.h 2016-10-12 07:29:58 +0000
@@ -0,0 +1,48 @@
+/*
+ * Copyright © 2016 Canonical Ltd.
+ *
+ * This program is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see .
+ *
+ * Authored by: Andreas Pokorny
+ */
+
+#ifndef MIR_INPUT_EVDEV_STEADY_TIMER_FD_FACTORY_H_
+#define MIR_INPUT_EVDEV_STEADY_TIMER_FD_FACTORY_H_
+
+#include "timer_fd_factory.h"
+
+#include "mir/dispatch/multiplexing_dispatchable.h"
+#include "mir/time/timer_fd.h"
+
+#include
+
+namespace mir
+{
+namespace input
+{
+namespace evdev
+{
+struct SteadyTimerFdFactory : TimerFdFactory
+{
+public:
+ SteadyTimerFdFactory(mir::dispatch::MultiplexingDispatchable& dispatchable);
+ std::unique_ptr create_timer(std::function const& call_on_timeout) const override;
+private:
+ mir::dispatch::MultiplexingDispatchable& dispatchable;
+};
+
+}
+}
+}
+
+#endif
=== added file 'src/platforms/evdev/timer_fd_factory.h'
--- src/platforms/evdev/timer_fd_factory.h 1970-01-01 00:00:00 +0000
+++ src/platforms/evdev/timer_fd_factory.h 2016-10-12 07:29:58 +0000
@@ -0,0 +1,47 @@
+/*
+ * Copyright © 2016 Canonical Ltd.
+ *
+ * This program is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see .
+ *
+ * Authored by: Andreas Pokorny
+ */
+
+#ifndef MIR_INPUT_EVDEV_TIMER_FD_FACTORY_H
+#define MIR_INPUT_EVDEV_TIMER_FD_FACTORY_H
+
+#include "mir/time/timer_fd.h"
+#include
+
+namespace mir
+{
+namespace input
+{
+namespace evdev
+{
+struct TimerFdFactory
+{
+public:
+ TimerFdFactory() = default;
+ virtual std::unique_ptr create_timer(std::function const& callback_on_timeout) const = 0;
+protected:
+ virtual ~TimerFdFactory() = default;
+private:
+ TimerFdFactory(TimerFdFactory const&) = delete;
+ TimerFdFactory& operator=(TimerFdFactory const&) = delete;
+};
+
+}
+}
+}
+
+#endif
=== added file 'tests/include/mir/test/doubles/fake_timer_fd_factory.h'
--- tests/include/mir/test/doubles/fake_timer_fd_factory.h 1970-01-01 00:00:00 +0000
+++ tests/include/mir/test/doubles/fake_timer_fd_factory.h 2016-10-12 07:29:58 +0000
@@ -0,0 +1,69 @@
+/*
+ * Copyright © 2016 Canonical Ltd.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 3 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ *
+ * Authored by: Andreas Pokorny
+ */
+
+#ifndef MIR_TEST_DOUBLES_FAKE_TIMER_FD_FACTORY_H_
+#define MIR_TEST_DOUBLES_FAKE_TIMER_FD_FACTORY_H_
+
+#include "mir/test/doubles/stub_timer_fd.h"
+#include "src/platforms/evdev/timer_fd_factory.h"
+
+#include "mir/time/types.h"
+
+#include
+#include
+
+namespace mir
+{
+namespace test
+{
+namespace doubles
+{
+struct MockTimerFd : StubTimerFd
+{
+ MOCK_METHOD1(schedule_in, void(mir::time::Duration));
+ MOCK_METHOD0(cancel, void());
+};
+
+struct FakeTimerFdFactory : mir::input::evdev::TimerFdFactory
+{
+ using NiceTimerFd = testing::NiceMock;
+ std::unique_ptr mutable prepared_timer;
+ std::function mutable execute_last_timer;
+ MOCK_CONST_METHOD2(timer_created, void(NiceTimerFd* timer, std::function const&));
+
+ inline std::unique_ptr create_timer(std::function const& callback) const override
+ {
+ execute_last_timer = callback;
+ if (!prepared_timer)
+ {
+ auto new_timer = std::make_unique();
+ timer_created(new_timer.get(), callback);
+ return new_timer;
+ }
+ else
+ {
+ timer_created(prepared_timer.get(), callback);
+ return std::move(prepared_timer);
+ }
+ }
+};
+}
+}
+}
+
+#endif
=== added file 'tests/include/mir/test/doubles/stub_timer_fd.h'
--- tests/include/mir/test/doubles/stub_timer_fd.h 1970-01-01 00:00:00 +0000
+++ tests/include/mir/test/doubles/stub_timer_fd.h 2016-10-12 07:29:58 +0000
@@ -0,0 +1,49 @@
+/*
+ * Copyright © 2016 Canonical Ltd.
+ *
+ * This program is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ *
+ * Authored by: Andreas Pokorny
+ */
+
+#ifndef MIR_TEST_DOUBLES_STUB_TIMER_FD_H
+#define MIR_TEST_DOUBLES_STUB_TIMER_FD_H
+
+#include "mir/time/timer_fd.h"
+
+namespace mir
+{
+namespace test
+{
+namespace doubles
+{
+struct StubTimerFd : mir::time::TimerFd
+{
+ Fd const& get_fd() override
+ {
+ return fd;
+ }
+ void schedule_in(mir::time::Duration) override
+ {
+ }
+ void cancel() override
+ {
+ }
+
+ mir::Fd fd{IntOwnedFd{-1}};
+};
+}
+}
+}
+
+#endif
=== modified file 'tests/unit-tests/input/CMakeLists.txt'
--- tests/unit-tests/input/CMakeLists.txt 2016-07-18 07:38:38 +0000
+++ tests/unit-tests/input/CMakeLists.txt 2016-10-12 07:29:58 +0000
@@ -18,6 +18,7 @@
${CMAKE_CURRENT_SOURCE_DIR}/test_key_repeat_dispatcher.cpp
${CMAKE_CURRENT_SOURCE_DIR}/test_validator.cpp
${CMAKE_CURRENT_SOURCE_DIR}/test_nested_input_platform.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/test_key_repeater.cpp
)
list(APPEND UMOCK_UNIT_TEST_SOURCES
=== added file 'tests/unit-tests/input/test_key_repeater.cpp'
--- tests/unit-tests/input/test_key_repeater.cpp 1970-01-01 00:00:00 +0000
+++ tests/unit-tests/input/test_key_repeater.cpp 2016-10-12 07:29:58 +0000
@@ -0,0 +1,138 @@
+/*
+ * Copyright © 2016 Canonical Ltd.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 3 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ *
+ * Authored by: Andreas Pokorny
+ */
+
+#include "src/platforms/evdev/key_repeater.h"
+#include "mir/test/doubles/fake_timer_fd_factory.h"
+#include "mir/test/fake_shared.h"
+
+#include
+#include
+
+#include
+#include
+
+namespace mt = mir::test;
+namespace mtd = mt::doubles;
+namespace mie = mir::input::evdev;
+
+using namespace ::testing;
+using namespace std::chrono_literals;
+
+namespace
+{
+struct KeyRepeater : Test
+{
+ MOCK_METHOD1(repeat_called, void(int32_t));
+
+ NiceMock fake_timers;
+ mie::KeyRepeater repeater{
+ fake_timers,
+ [this](int32_t code)
+ {
+ repeat_called(code);
+ }};
+
+ const int32_t a_key = 32;
+ const int32_t another_key = 10;
+ const int32_t third_key = 54;
+};
+}
+
+TEST_F(KeyRepeater, no_repeat_alarm_when_disabled)
+{
+ repeater.disable();
+ EXPECT_CALL(fake_timers, timer_created(_,_)).Times(0);
+
+ repeater.press(a_key);
+ repeater.release(a_key);
+}
+
+TEST_F(KeyRepeater, repeat_enabled_by_default)
+{
+ EXPECT_THAT(repeater.enabled(), Eq(true));
+}
+
+TEST_F(KeyRepeater, alarm_canceled_on_disable)
+{
+ fake_timers.prepared_timer = std::make_unique();
+ EXPECT_CALL(*fake_timers.prepared_timer.get(), cancel()).Times(1);
+
+ repeater.press(a_key);
+ repeater.disable();
+}
+
+TEST_F(KeyRepeater, alarm_canceled_on_release)
+{
+ fake_timers.prepared_timer = std::make_unique>();
+ EXPECT_CALL(*fake_timers.prepared_timer.get(), schedule_in(_));
+ EXPECT_CALL(*fake_timers.prepared_timer.get(), cancel());
+
+ repeater.press(a_key);
+ repeater.release(a_key);
+}
+
+TEST_F(KeyRepeater, alarm_rescheduled_on_timeout)
+{
+ fake_timers.prepared_timer = std::make_unique>();
+ std::function timer_callback;
+ mir::time::Duration const delay = 50ms;
+ mir::time::Duration const interval = 10ms;
+ EXPECT_CALL(*fake_timers.prepared_timer.get(), schedule_in(delay));
+ EXPECT_CALL(*fake_timers.prepared_timer.get(), schedule_in(interval));
+
+ repeater.enable(50ms, 10ms);
+ repeater.press(a_key);
+ fake_timers.execute_last_timer();
+}
+
+TEST_F(KeyRepeater, callback_called_on_timeout)
+{
+ EXPECT_CALL(*this, repeat_called(a_key)).Times(1);
+
+ repeater.press(a_key);
+ fake_timers.execute_last_timer();
+}
+
+TEST_F(KeyRepeater, one_alarm_for_all_keys)
+{
+ EXPECT_CALL(fake_timers, timer_created(_,_)).Times(1);
+ repeater.press(a_key);
+ repeater.press(another_key);
+}
+
+TEST_F(KeyRepeater, alarm_canceld_on_release_of_last_key)
+{
+ fake_timers.prepared_timer = std::make_unique>();
+ auto & prepared_timer = *fake_timers.prepared_timer.get();
+ EXPECT_CALL(fake_timers, timer_created(_,_)).Times(1);
+ EXPECT_CALL(prepared_timer, schedule_in(_)).Times(1);
+ EXPECT_CALL(prepared_timer, cancel()).Times(0);
+ repeater.press(a_key);
+ repeater.press(another_key);
+ repeater.press(third_key);
+ testing::Mock::VerifyAndClear(&prepared_timer);
+
+ EXPECT_CALL(prepared_timer, cancel()).Times(0);
+ repeater.release(another_key);
+ repeater.release(a_key);
+
+ testing::Mock::VerifyAndClear(&prepared_timer);
+
+ EXPECT_CALL(prepared_timer, cancel()).Times(1);
+ repeater.release(third_key);
+}