Mir

Merge lp:~andreas-pokorny/mir/key-repeater-on-timer-fd-utility into lp:mir

Proposed by Andreas Pokorny
Status: Work in progress
Proposed branch: lp:~andreas-pokorny/mir/key-repeater-on-timer-fd-utility
Merge into: lp:mir
Diff against target: 875 lines (+771/-0)
15 files modified
include/common/mir/time/steady_timer_fd.h (+46/-0)
include/common/mir/time/timer_fd.h (+65/-0)
src/common/symbols.map (+6/-0)
src/common/time/CMakeLists.txt (+3/-0)
src/common/time/steady_timer_fd.cpp (+54/-0)
src/platforms/evdev/CMakeLists.txt (+9/-0)
src/platforms/evdev/key_repeater.cpp (+102/-0)
src/platforms/evdev/key_repeater.h (+67/-0)
src/platforms/evdev/steady_timer_fd_factory.cpp (+67/-0)
src/platforms/evdev/steady_timer_fd_factory.h (+48/-0)
src/platforms/evdev/timer_fd_factory.h (+47/-0)
tests/include/mir/test/doubles/fake_timer_fd_factory.h (+69/-0)
tests/include/mir/test/doubles/stub_timer_fd.h (+49/-0)
tests/unit-tests/input/CMakeLists.txt (+1/-0)
tests/unit-tests/input/test_key_repeater.cpp (+138/-0)
To merge this branch: bzr merge lp:~andreas-pokorny/mir/key-repeater-on-timer-fd-utility
Reviewer Review Type Date Requested Status
Mir CI Bot continuous-integration Needs Fixing
Mir development team Pending
Review via email: mp+308212@code.launchpad.net

Commit message

Add a simpler key repeater utility class for stub and evdev input platform

The key repeater is meant to be integrated with the Dispatchable classes and will replace the key repeater that currently abuses the main loop in inject repeated keys inside the mirserver. It uses a new mircommon steady_timer_fd utility that wrapps CLOCK_MONOTONIC timer fds.

This is a preparation step to move the repeat handling inside the input platforms, which will evade another mirserver direct event structure manipulation.

Description of the change

This is a simplified version of the key repeater found in the last attempt. This time there is no interesting alarm provider to review, that integrates with Dispatchable and fulfillls all of our AlarmFactory requirements... Instead a trivial timer fd wrapper - but still tracking all pressed keys.

To post a comment you must log in.
Revision history for this message
Mir CI Bot (mir-ci-bot) wrote :

FAILED: Continuous integration, rev:3757
https://mir-jenkins.ubuntu.com/job/mir-ci/1948/
Executed test runs:
    FAILURE: https://mir-jenkins.ubuntu.com/job/build-mir/2484/console
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-0-fetch/2547
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-1-sourcepkg/release=vivid+overlay/2539
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-1-sourcepkg/release=xenial+overlay/2539
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-1-sourcepkg/release=yakkety/2539
    FAILURE: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=clang,platform=mesa,release=yakkety/2513/console
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=gcc,platform=mesa,release=xenial+overlay/2513
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=gcc,platform=mesa,release=xenial+overlay/2513/artifact/output/*zip*/output.zip
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=gcc,platform=mesa,release=yakkety/2513
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=gcc,platform=mesa,release=yakkety/2513/artifact/output/*zip*/output.zip
    FAILURE: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=cross-armhf,compiler=gcc,platform=android,release=vivid+overlay/2513/console
    FAILURE: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=i386,compiler=gcc,platform=android,release=vivid+overlay/2513/console
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=i386,compiler=gcc,platform=mesa,release=xenial+overlay/2513
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=i386,compiler=gcc,platform=mesa,release=xenial+overlay/2513/artifact/output/*zip*/output.zip

Click here to trigger a rebuild:
https://mir-jenkins.ubuntu.com/job/mir-ci/1948/rebuild

review: Needs Fixing (continuous-integration)
3758. By Andreas Pokorny

relative! instead of TFD_TIMER_ABSTIME

Revision history for this message
Mir CI Bot (mir-ci-bot) wrote :

FAILED: Continuous integration, rev:3758
https://mir-jenkins.ubuntu.com/job/mir-ci/1951/
Executed test runs:
    FAILURE: https://mir-jenkins.ubuntu.com/job/build-mir/2489/console
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-0-fetch/2552
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-1-sourcepkg/release=vivid+overlay/2544
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-1-sourcepkg/release=xenial+overlay/2544
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-1-sourcepkg/release=yakkety/2544
    FAILURE: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=clang,platform=mesa,release=yakkety/2518/console
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=gcc,platform=mesa,release=xenial+overlay/2518
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=gcc,platform=mesa,release=xenial+overlay/2518/artifact/output/*zip*/output.zip
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=gcc,platform=mesa,release=yakkety/2518
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=gcc,platform=mesa,release=yakkety/2518/artifact/output/*zip*/output.zip
    FAILURE: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=cross-armhf,compiler=gcc,platform=android,release=vivid+overlay/2518/console
    FAILURE: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=i386,compiler=gcc,platform=android,release=vivid+overlay/2518/console
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=i386,compiler=gcc,platform=mesa,release=xenial+overlay/2518
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=i386,compiler=gcc,platform=mesa,release=xenial+overlay/2518/artifact/output/*zip*/output.zip

Click here to trigger a rebuild:
https://mir-jenkins.ubuntu.com/job/mir-ci/1951/rebuild

review: Needs Fixing (continuous-integration)

Unmerged revisions

3758. By Andreas Pokorny

relative! instead of TFD_TIMER_ABSTIME

3757. By Andreas Pokorny

Add a simpler key repeater utility class for stub and evdev input platform

The key repeater is meant to be integrated with the Dispatchable classes and will replace the key repeater that currently abuses the main loop in inject repeated keys inside the mirserver. It uses a new mircommon steady_timer_fd utility that wrapps CLOCK_MONOTONIC timer fds.

This is a preparation step to move the repeat handling inside the input platforms, which will evade another mirserver event type fumbling location.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== added file 'include/common/mir/time/steady_timer_fd.h'
2--- include/common/mir/time/steady_timer_fd.h 1970-01-01 00:00:00 +0000
3+++ include/common/mir/time/steady_timer_fd.h 2016-10-12 07:29:58 +0000
4@@ -0,0 +1,46 @@
5+/*
6+ * Copyright © 2016 Canonical Ltd.
7+ *
8+ * This program is free software: you can redistribute it and/or modify it
9+ * under the terms of the GNU Lesser General Public License version 3,
10+ * as published by the Free Software Foundation.
11+ *
12+ * This program is distributed in the hope that it will be useful,
13+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
14+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15+ * GNU Lesser General Public License for more details.
16+ *
17+ * You should have received a copy of the GNU Lesser General Public License
18+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
19+ *
20+ * Authored by: Andreas Pokorny <andreas.pokorny@canonical.com>
21+ */
22+
23+#ifndef MIR_TIME_STEADY_TIMER_FD_
24+#define MIR_TIME_STEADY_TIMER_FD_
25+
26+#include "mir/time/timer_fd.h"
27+
28+namespace mir
29+{
30+namespace time
31+{
32+
33+/**
34+ * SteadyTimerFd implements TimerFd using timer fds and using CLOCK_MONOTONIC.
35+ */
36+class SteadyTimerFd : public TimerFd
37+{
38+public:
39+ SteadyTimerFd();
40+ Fd const& get_fd() override;
41+ void schedule_in(Duration duration) override;
42+ void cancel() override;
43+private:
44+ mir::Fd timer;
45+};
46+
47+}
48+}
49+
50+#endif
51
52=== added file 'include/common/mir/time/timer_fd.h'
53--- include/common/mir/time/timer_fd.h 1970-01-01 00:00:00 +0000
54+++ include/common/mir/time/timer_fd.h 2016-10-12 07:29:58 +0000
55@@ -0,0 +1,65 @@
56+/*
57+ * Copyright © 2016 Canonical Ltd.
58+ *
59+ * This program is free software: you can redistribute it and/or modify it
60+ * under the terms of the GNU Lesser General Public License version 3,
61+ * as published by the Free Software Foundation.
62+ *
63+ * This program is distributed in the hope that it will be useful,
64+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
65+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
66+ * GNU Lesser General Public License for more details.
67+ *
68+ * You should have received a copy of the GNU Lesser General Public License
69+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
70+ *
71+ * Authored by: Andreas Pokorny <andreas.pokorny@canonical.com>
72+ */
73+
74+#ifndef MIR_TIME_TIMER_FD_H_
75+#define MIR_TIME_TIMER_FD_H_
76+
77+#include "mir/fd.h"
78+#include "mir/time/types.h"
79+
80+#include <chrono>
81+
82+namespace mir
83+{
84+namespace time
85+{
86+
87+/**
88+ * TimerFd is a timer that notifies via a file descriptor.
89+ */
90+class TimerFd
91+{
92+public:
93+ TimerFd() = default;
94+ virtual ~TimerFd() = default;
95+
96+ /**
97+ * Get access to the file descriptor
98+ */
99+ virtual Fd const& get_fd() = 0;
100+
101+ /**
102+ * Configure the timer monitored by the file descriptor to expire after the given \a duration.
103+ *
104+ * \param[in] duration the time to delay
105+ */
106+ virtual void schedule_in(Duration duration) = 0;
107+ /**
108+ * Cancel the timer.
109+ *
110+ * After that call the timer can be configured again using schedule_for.
111+ */
112+ virtual void cancel() = 0;
113+protected:
114+ TimerFd(TimerFd const&) = delete;
115+ TimerFd& operator=(TimerFd const&) = delete;
116+};
117+
118+}
119+}
120+#endif
121
122=== modified file 'src/common/symbols.map'
123--- src/common/symbols.map 2016-10-12 06:03:15 +0000
124+++ src/common/symbols.map 2016-10-12 07:29:58 +0000
125@@ -364,6 +364,12 @@
126 mir::output_type_name*;
127 MirSurfaceOutputEvent::refresh_rate*;
128 MirSurfaceOutputEvent::set_refresh_rate*;
129+ mir::time::SteadyTimerFd::SteadyTimerFd*;
130+ mir::time::SteadyTimerFd::get_fd*;
131+ mir::time::SteadyTimerFd::schedule_in*;
132+ mir::time::SteadyTimerFd::cancel*;
133+ typeinfo?for?mir::time::SteadyTimerFd;
134+ vtable?for?mir::time::SteadyTimerFd;
135 };
136 local: *;
137 };
138
139=== modified file 'src/common/time/CMakeLists.txt'
140--- src/common/time/CMakeLists.txt 2015-02-22 07:46:25 +0000
141+++ src/common/time/CMakeLists.txt 2016-10-12 07:29:58 +0000
142@@ -1,5 +1,8 @@
143 ADD_LIBRARY(
144 mirtime OBJECT
145
146+ ${CMAKE_SOURCE_DIR}/include/common/mir/time/timer_fd.h
147+ ${CMAKE_SOURCE_DIR}/include/common/mir/time/steady_timer_fd.h
148 steady_clock.cpp
149+ steady_timer_fd.cpp
150 )
151
152=== added file 'src/common/time/steady_timer_fd.cpp'
153--- src/common/time/steady_timer_fd.cpp 1970-01-01 00:00:00 +0000
154+++ src/common/time/steady_timer_fd.cpp 2016-10-12 07:29:58 +0000
155@@ -0,0 +1,54 @@
156+/*
157+ * Copyright © 2016 Canonical Ltd.
158+ *
159+ * This program is free software: you can redistribute it and/or modify it
160+ * under the terms of the GNU Lesser General Public License version 3,
161+ * as published by the Free Software Foundation.
162+ *
163+ * This program is distributed in the hope that it will be useful,
164+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
165+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
166+ * GNU Lesser General Public License for more details.
167+ *
168+ * You should have received a copy of the GNU Lesser General Public License
169+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
170+ *
171+ * Authored by: Andreas Pokorny <andreas.pokorny@canonical.com>
172+ */
173+
174+#include "mir/time/steady_timer_fd.h"
175+#include <sys/timerfd.h>
176+#include <chrono>
177+
178+namespace mt = mir::time;
179+
180+mt::SteadyTimerFd::SteadyTimerFd()
181+ : timer{timerfd_create(CLOCK_MONOTONIC, TFD_CLOEXEC | TFD_NONBLOCK)}
182+{
183+}
184+
185+mir::Fd const& mt::SteadyTimerFd::get_fd()
186+{
187+ return timer;
188+}
189+
190+void mt::SteadyTimerFd::schedule_in(mir::time::Duration delay)
191+{
192+ using namespace std::chrono;
193+ auto const in_seconds = duration_cast<seconds>(delay);
194+ itimerspec delay_spec;
195+
196+ delay_spec.it_value.tv_sec = in_seconds.count();
197+ delay_spec.it_value.tv_nsec = nanoseconds(delay - in_seconds).count();
198+ delay_spec.it_interval.tv_sec = 0;
199+ delay_spec.it_interval.tv_nsec = 0;
200+
201+ const int relative_timeout = 0;
202+ timerfd_settime(timer, relative_timeout, &delay_spec, nullptr);
203+}
204+
205+void mt::SteadyTimerFd::cancel()
206+{
207+ const itimerspec cancel_timer = {{0,0},{0,0}};
208+ timerfd_settime(timer, 0, &cancel_timer, nullptr);
209+}
210
211=== modified file 'src/platforms/evdev/CMakeLists.txt'
212--- src/platforms/evdev/CMakeLists.txt 2016-08-10 07:57:05 +0000
213+++ src/platforms/evdev/CMakeLists.txt 2016-10-12 07:29:58 +0000
214@@ -18,13 +18,22 @@
215 add_library(mirevdevutilsobjects OBJECT
216 evdev_device_detection.cpp
217 button_utils.cpp
218+ key_repeater.cpp
219+ key_repeater.h
220+ steady_timer_fd_factory.cpp
221+ steady_timer_fd_factory.h
222 )
223
224 add_library(mirplatforminputevdevobjects OBJECT
225 libinput_device.cpp
226+ libinput_device.h
227 libinput_device_ptr.cpp
228+ libinput_device_ptr.h
229 libinput_ptr.cpp
230+ libinput_ptr.h
231 platform.cpp
232+ platform.h
233+ timer_fd_factory.h
234 )
235
236 add_library(mirplatforminputevdev MODULE
237
238=== added file 'src/platforms/evdev/key_repeater.cpp'
239--- src/platforms/evdev/key_repeater.cpp 1970-01-01 00:00:00 +0000
240+++ src/platforms/evdev/key_repeater.cpp 2016-10-12 07:29:58 +0000
241@@ -0,0 +1,102 @@
242+/*
243+ * Copyright © 2016 Canonical Ltd.
244+ *
245+ * This program is free software: you can redistribute it and/or modify it
246+ * under the terms of the GNU General Public License version 3,
247+ * as published by the Free Software Foundation.
248+ *
249+ * This program is distributed in the hope that it will be useful,
250+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
251+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
252+ * GNU General Public License for more details.
253+ *
254+ * You should have received a copy of the GNU General Public License
255+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
256+ *
257+ * Authored by: Andreas Pokorny <andreas.pokorny@canonical.com>
258+ */
259+
260+#include "timer_fd_factory.h"
261+#include "key_repeater.h"
262+
263+#include "mir/time/timer_fd.h"
264+
265+namespace mie = mir::input::evdev;
266+namespace mt = mir::time;
267+
268+mie::KeyRepeater::KeyRepeater(TimerFdFactory const& timers,
269+ std::function<void(int32_t keycode)> const& send_repeat_key)
270+ : timers{timers}, send_repeat{send_repeat_key}
271+{
272+}
273+
274+mie::KeyRepeater::~KeyRepeater() = default;
275+
276+void mie::KeyRepeater::enable(std::chrono::milliseconds repeat_delay, std::chrono::milliseconds repeat_interval)
277+{
278+ enabled_ = true;
279+ this->repeat_delay = repeat_delay;
280+ this->repeat_interval = repeat_interval;
281+}
282+
283+void mie::KeyRepeater::disable()
284+{
285+ enabled_ = false;
286+ if (timer)
287+ {
288+ timer->cancel();
289+ timer.reset();
290+ }
291+ depressed_keys.clear();
292+}
293+
294+void mie::KeyRepeater::press(int32_t code)
295+{
296+ if (enabled_)
297+ {
298+ if (!timer)
299+ {
300+ timer = timers.create_timer([this]{handle_timeout();});
301+ timer->schedule_in(repeat_delay);
302+ }
303+ depressed_keys.insert(code);
304+ }
305+}
306+
307+void mie::KeyRepeater::release(int32_t code)
308+{
309+ bool const was_pressed = depressed_keys.erase(code);
310+ if (was_pressed && depressed_keys.empty() && timer)
311+ {
312+ timer->cancel();
313+ timer.reset();
314+ }
315+}
316+
317+void mie::KeyRepeater::handle_timeout()
318+{
319+ if (enabled_)
320+ {
321+ if (!timer)
322+ timer = timers.create_timer([this]{handle_timeout();});
323+ timer->schedule_in(repeat_interval);
324+
325+ for (auto const code : depressed_keys)
326+ send_repeat(code);
327+ }
328+}
329+
330+bool mie::KeyRepeater::enabled() const
331+{
332+ return enabled_;
333+}
334+
335+std::chrono::milliseconds mie::KeyRepeater::delay() const
336+{
337+ return repeat_delay;
338+}
339+
340+std::chrono::milliseconds mie::KeyRepeater::interval() const
341+{
342+ return repeat_interval;
343+}
344
345=== added file 'src/platforms/evdev/key_repeater.h'
346--- src/platforms/evdev/key_repeater.h 1970-01-01 00:00:00 +0000
347+++ src/platforms/evdev/key_repeater.h 2016-10-12 07:29:58 +0000
348@@ -0,0 +1,67 @@
349+/*
350+ * Copyright © 2016 Canonical Ltd.
351+ *
352+ * This program is free software: you can redistribute it and/or modify it
353+ * under the terms of the GNU General Public License version 3,
354+ * as published by the Free Software Foundation.
355+ *
356+ * This program is distributed in the hope that it will be useful,
357+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
358+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
359+ * GNU General Public License for more details.
360+ *
361+ * You should have received a copy of the GNU General Public License
362+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
363+ *
364+ * Authored by: Andreas Pokorny <andreas.pokorny@canonical.com>
365+ */
366+
367+#ifndef MIR_INPUT_EVDEV_KEY_REPEATER_H_
368+#define MIR_INPUT_EVDEV_KEY_REPEATER_H_
369+
370+#include <memory>
371+#include <chrono>
372+#include <unordered_set>
373+#include <functional>
374+
375+namespace mir
376+{
377+namespace time
378+{
379+class TimerFd;
380+}
381+namespace input
382+{
383+namespace evdev
384+{
385+class TimerFdFactory;
386+
387+struct KeyRepeater
388+{
389+ KeyRepeater(TimerFdFactory const& timers,
390+ std::function<void(int32_t keycode)> const& send_repeat_key);
391+ ~KeyRepeater();
392+ void enable(std::chrono::milliseconds repeat_delay, std::chrono::milliseconds repeat_interval);
393+ void disable();
394+ bool enabled() const;
395+ std::chrono::milliseconds delay() const;
396+ std::chrono::milliseconds interval() const;
397+ void press(int32_t code);
398+ void release(int32_t code);
399+
400+private:
401+ void handle_timeout();
402+ TimerFdFactory const& timers;
403+ bool enabled_{true};
404+
405+ std::chrono::milliseconds repeat_delay{500};
406+ std::chrono::milliseconds repeat_interval{50};
407+
408+ std::function<void(int32_t)> send_repeat;
409+ std::unordered_set<int32_t> depressed_keys;
410+ std::unique_ptr<mir::time::TimerFd> timer;
411+};
412+}
413+}
414+}
415+#endif
416
417=== added file 'src/platforms/evdev/steady_timer_fd_factory.cpp'
418--- src/platforms/evdev/steady_timer_fd_factory.cpp 1970-01-01 00:00:00 +0000
419+++ src/platforms/evdev/steady_timer_fd_factory.cpp 2016-10-12 07:29:58 +0000
420@@ -0,0 +1,67 @@
421+/*
422+ * Copyright © 2016 Canonical Ltd.
423+ *
424+ * This program is free software: you can redistribute it and/or modify it
425+ * under the terms of the GNU Lesser General Public License version 3,
426+ * as published by the Free Software Foundation.
427+ *
428+ * This program is distributed in the hope that it will be useful,
429+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
430+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
431+ * GNU Lesser General Public License for more details.
432+ *
433+ * You should have received a copy of the GNU Lesser General Public License
434+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
435+ *
436+ * Authored by: Andreas Pokorny <andreas.pokorny@canonical.com>
437+ */
438+
439+#include "steady_timer_fd_factory.h"
440+#include "mir/time/steady_timer_fd.h"
441+#include "mir/dispatch/readable_fd.h"
442+
443+namespace mie = mir::input::evdev;
444+namespace md = mir::dispatch;
445+namespace mt = mir::time;
446+
447+namespace
448+{
449+
450+struct DispatchableTimerFd : mt::SteadyTimerFd
451+{
452+public:
453+ DispatchableTimerFd(md::MultiplexingDispatchable& dispatchable,
454+ std::function<void()> const& callback) :
455+ readable_fd{std::make_shared<md::ReadableFd>(get_fd(), callback)},
456+ dispatchable{dispatchable}
457+ {
458+ }
459+
460+ void schedule_in(mir::time::Duration delay) override
461+ {
462+ mt::SteadyTimerFd::schedule_in(delay);
463+ dispatchable.add_watch(readable_fd);
464+ }
465+
466+ void cancel() override
467+ {
468+ mt::SteadyTimerFd::cancel();
469+ dispatchable.remove_watch(readable_fd);
470+ }
471+
472+private:
473+ std::shared_ptr<md::ReadableFd> const readable_fd;
474+ md::MultiplexingDispatchable& dispatchable;
475+};
476+
477+}
478+
479+mie::SteadyTimerFdFactory::SteadyTimerFdFactory(md::MultiplexingDispatchable& dispatchable)
480+ : dispatchable(dispatchable)
481+{
482+}
483+
484+std::unique_ptr<mt::TimerFd> mie::SteadyTimerFdFactory::SteadyTimerFdFactory::create_timer(std::function<void()> const& callback_on_timeout) const
485+{
486+ return std::make_unique<DispatchableTimerFd>(dispatchable, callback_on_timeout);
487+}
488
489=== added file 'src/platforms/evdev/steady_timer_fd_factory.h'
490--- src/platforms/evdev/steady_timer_fd_factory.h 1970-01-01 00:00:00 +0000
491+++ src/platforms/evdev/steady_timer_fd_factory.h 2016-10-12 07:29:58 +0000
492@@ -0,0 +1,48 @@
493+/*
494+ * Copyright © 2016 Canonical Ltd.
495+ *
496+ * This program is free software: you can redistribute it and/or modify it
497+ * under the terms of the GNU Lesser General Public License version 3,
498+ * as published by the Free Software Foundation.
499+ *
500+ * This program is distributed in the hope that it will be useful,
501+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
502+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
503+ * GNU Lesser General Public License for more details.
504+ *
505+ * You should have received a copy of the GNU Lesser General Public License
506+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
507+ *
508+ * Authored by: Andreas Pokorny <andreas.pokorny@canonical.com>
509+ */
510+
511+#ifndef MIR_INPUT_EVDEV_STEADY_TIMER_FD_FACTORY_H_
512+#define MIR_INPUT_EVDEV_STEADY_TIMER_FD_FACTORY_H_
513+
514+#include "timer_fd_factory.h"
515+
516+#include "mir/dispatch/multiplexing_dispatchable.h"
517+#include "mir/time/timer_fd.h"
518+
519+#include <memory>
520+
521+namespace mir
522+{
523+namespace input
524+{
525+namespace evdev
526+{
527+struct SteadyTimerFdFactory : TimerFdFactory
528+{
529+public:
530+ SteadyTimerFdFactory(mir::dispatch::MultiplexingDispatchable& dispatchable);
531+ std::unique_ptr<mir::time::TimerFd> create_timer(std::function<void()> const& call_on_timeout) const override;
532+private:
533+ mir::dispatch::MultiplexingDispatchable& dispatchable;
534+};
535+
536+}
537+}
538+}
539+
540+#endif
541
542=== added file 'src/platforms/evdev/timer_fd_factory.h'
543--- src/platforms/evdev/timer_fd_factory.h 1970-01-01 00:00:00 +0000
544+++ src/platforms/evdev/timer_fd_factory.h 2016-10-12 07:29:58 +0000
545@@ -0,0 +1,47 @@
546+/*
547+ * Copyright © 2016 Canonical Ltd.
548+ *
549+ * This program is free software: you can redistribute it and/or modify it
550+ * under the terms of the GNU Lesser General Public License version 3,
551+ * as published by the Free Software Foundation.
552+ *
553+ * This program is distributed in the hope that it will be useful,
554+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
555+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
556+ * GNU Lesser General Public License for more details.
557+ *
558+ * You should have received a copy of the GNU Lesser General Public License
559+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
560+ *
561+ * Authored by: Andreas Pokorny <andreas.pokorny@canonical.com>
562+ */
563+
564+#ifndef MIR_INPUT_EVDEV_TIMER_FD_FACTORY_H
565+#define MIR_INPUT_EVDEV_TIMER_FD_FACTORY_H
566+
567+#include "mir/time/timer_fd.h"
568+#include <functional>
569+
570+namespace mir
571+{
572+namespace input
573+{
574+namespace evdev
575+{
576+struct TimerFdFactory
577+{
578+public:
579+ TimerFdFactory() = default;
580+ virtual std::unique_ptr<mir::time::TimerFd> create_timer(std::function<void()> const& callback_on_timeout) const = 0;
581+protected:
582+ virtual ~TimerFdFactory() = default;
583+private:
584+ TimerFdFactory(TimerFdFactory const&) = delete;
585+ TimerFdFactory& operator=(TimerFdFactory const&) = delete;
586+};
587+
588+}
589+}
590+}
591+
592+#endif
593
594=== added file 'tests/include/mir/test/doubles/fake_timer_fd_factory.h'
595--- tests/include/mir/test/doubles/fake_timer_fd_factory.h 1970-01-01 00:00:00 +0000
596+++ tests/include/mir/test/doubles/fake_timer_fd_factory.h 2016-10-12 07:29:58 +0000
597@@ -0,0 +1,69 @@
598+/*
599+ * Copyright © 2016 Canonical Ltd.
600+ *
601+ * This program is free software: you can redistribute it and/or modify
602+ * it under the terms of the GNU General Public License version 3 as
603+ * published by the Free Software Foundation.
604+ *
605+ * This program is distributed in the hope that it will be useful,
606+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
607+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
608+ * GNU General Public License for more details.
609+ *
610+ * You should have received a copy of the GNU General Public License
611+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
612+ *
613+ * Authored by: Andreas Pokorny <andreas.pokorny@canonical.com>
614+ */
615+
616+#ifndef MIR_TEST_DOUBLES_FAKE_TIMER_FD_FACTORY_H_
617+#define MIR_TEST_DOUBLES_FAKE_TIMER_FD_FACTORY_H_
618+
619+#include "mir/test/doubles/stub_timer_fd.h"
620+#include "src/platforms/evdev/timer_fd_factory.h"
621+
622+#include "mir/time/types.h"
623+
624+#include <gmock/gmock.h>
625+#include <memory>
626+
627+namespace mir
628+{
629+namespace test
630+{
631+namespace doubles
632+{
633+struct MockTimerFd : StubTimerFd
634+{
635+ MOCK_METHOD1(schedule_in, void(mir::time::Duration));
636+ MOCK_METHOD0(cancel, void());
637+};
638+
639+struct FakeTimerFdFactory : mir::input::evdev::TimerFdFactory
640+{
641+ using NiceTimerFd = testing::NiceMock<MockTimerFd>;
642+ std::unique_ptr<NiceTimerFd> mutable prepared_timer;
643+ std::function<void()> mutable execute_last_timer;
644+ MOCK_CONST_METHOD2(timer_created, void(NiceTimerFd* timer, std::function<void()> const&));
645+
646+ inline std::unique_ptr<mir::time::TimerFd> create_timer(std::function<void()> const& callback) const override
647+ {
648+ execute_last_timer = callback;
649+ if (!prepared_timer)
650+ {
651+ auto new_timer = std::make_unique<NiceTimerFd>();
652+ timer_created(new_timer.get(), callback);
653+ return new_timer;
654+ }
655+ else
656+ {
657+ timer_created(prepared_timer.get(), callback);
658+ return std::move(prepared_timer);
659+ }
660+ }
661+};
662+}
663+}
664+}
665+
666+#endif
667
668=== added file 'tests/include/mir/test/doubles/stub_timer_fd.h'
669--- tests/include/mir/test/doubles/stub_timer_fd.h 1970-01-01 00:00:00 +0000
670+++ tests/include/mir/test/doubles/stub_timer_fd.h 2016-10-12 07:29:58 +0000
671@@ -0,0 +1,49 @@
672+/*
673+ * Copyright © 2016 Canonical Ltd.
674+ *
675+ * This program is free software: you can redistribute it and/or modify it
676+ * under the terms of the GNU General Public License version 3,
677+ * as published by the Free Software Foundation.
678+ *
679+ * This program is distributed in the hope that it will be useful,
680+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
681+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
682+ * GNU General Public License for more details.
683+ *
684+ * You should have received a copy of the GNU General Public License
685+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
686+ *
687+ * Authored by: Andreas Pokorny <andreas.pokorny@canonical.com>
688+ */
689+
690+#ifndef MIR_TEST_DOUBLES_STUB_TIMER_FD_H
691+#define MIR_TEST_DOUBLES_STUB_TIMER_FD_H
692+
693+#include "mir/time/timer_fd.h"
694+
695+namespace mir
696+{
697+namespace test
698+{
699+namespace doubles
700+{
701+struct StubTimerFd : mir::time::TimerFd
702+{
703+ Fd const& get_fd() override
704+ {
705+ return fd;
706+ }
707+ void schedule_in(mir::time::Duration) override
708+ {
709+ }
710+ void cancel() override
711+ {
712+ }
713+
714+ mir::Fd fd{IntOwnedFd{-1}};
715+};
716+}
717+}
718+}
719+
720+#endif
721
722=== modified file 'tests/unit-tests/input/CMakeLists.txt'
723--- tests/unit-tests/input/CMakeLists.txt 2016-07-18 07:38:38 +0000
724+++ tests/unit-tests/input/CMakeLists.txt 2016-10-12 07:29:58 +0000
725@@ -18,6 +18,7 @@
726 ${CMAKE_CURRENT_SOURCE_DIR}/test_key_repeat_dispatcher.cpp
727 ${CMAKE_CURRENT_SOURCE_DIR}/test_validator.cpp
728 ${CMAKE_CURRENT_SOURCE_DIR}/test_nested_input_platform.cpp
729+ ${CMAKE_CURRENT_SOURCE_DIR}/test_key_repeater.cpp
730 )
731
732 list(APPEND UMOCK_UNIT_TEST_SOURCES
733
734=== added file 'tests/unit-tests/input/test_key_repeater.cpp'
735--- tests/unit-tests/input/test_key_repeater.cpp 1970-01-01 00:00:00 +0000
736+++ tests/unit-tests/input/test_key_repeater.cpp 2016-10-12 07:29:58 +0000
737@@ -0,0 +1,138 @@
738+/*
739+ * Copyright © 2016 Canonical Ltd.
740+ *
741+ * This program is free software: you can redistribute it and/or modify
742+ * it under the terms of the GNU General Public License version 3 as
743+ * published by the Free Software Foundation.
744+ *
745+ * This program is distributed in the hope that it will be useful,
746+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
747+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
748+ * GNU General Public License for more details.
749+ *
750+ * You should have received a copy of the GNU General Public License
751+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
752+ *
753+ * Authored by: Andreas Pokorny <andreas.pokorny@canonical.com>
754+ */
755+
756+#include "src/platforms/evdev/key_repeater.h"
757+#include "mir/test/doubles/fake_timer_fd_factory.h"
758+#include "mir/test/fake_shared.h"
759+
760+#include <gtest/gtest.h>
761+#include <gmock/gmock.h>
762+
763+#include <memory>
764+#include <chrono>
765+
766+namespace mt = mir::test;
767+namespace mtd = mt::doubles;
768+namespace mie = mir::input::evdev;
769+
770+using namespace ::testing;
771+using namespace std::chrono_literals;
772+
773+namespace
774+{
775+struct KeyRepeater : Test
776+{
777+ MOCK_METHOD1(repeat_called, void(int32_t));
778+
779+ NiceMock<mtd::FakeTimerFdFactory> fake_timers;
780+ mie::KeyRepeater repeater{
781+ fake_timers,
782+ [this](int32_t code)
783+ {
784+ repeat_called(code);
785+ }};
786+
787+ const int32_t a_key = 32;
788+ const int32_t another_key = 10;
789+ const int32_t third_key = 54;
790+};
791+}
792+
793+TEST_F(KeyRepeater, no_repeat_alarm_when_disabled)
794+{
795+ repeater.disable();
796+ EXPECT_CALL(fake_timers, timer_created(_,_)).Times(0);
797+
798+ repeater.press(a_key);
799+ repeater.release(a_key);
800+}
801+
802+TEST_F(KeyRepeater, repeat_enabled_by_default)
803+{
804+ EXPECT_THAT(repeater.enabled(), Eq(true));
805+}
806+
807+TEST_F(KeyRepeater, alarm_canceled_on_disable)
808+{
809+ fake_timers.prepared_timer = std::make_unique<mtd::FakeTimerFdFactory::NiceTimerFd>();
810+ EXPECT_CALL(*fake_timers.prepared_timer.get(), cancel()).Times(1);
811+
812+ repeater.press(a_key);
813+ repeater.disable();
814+}
815+
816+TEST_F(KeyRepeater, alarm_canceled_on_release)
817+{
818+ fake_timers.prepared_timer = std::make_unique<NiceMock<mtd::MockTimerFd>>();
819+ EXPECT_CALL(*fake_timers.prepared_timer.get(), schedule_in(_));
820+ EXPECT_CALL(*fake_timers.prepared_timer.get(), cancel());
821+
822+ repeater.press(a_key);
823+ repeater.release(a_key);
824+}
825+
826+TEST_F(KeyRepeater, alarm_rescheduled_on_timeout)
827+{
828+ fake_timers.prepared_timer = std::make_unique<NiceMock<mtd::MockTimerFd>>();
829+ std::function<void()> timer_callback;
830+ mir::time::Duration const delay = 50ms;
831+ mir::time::Duration const interval = 10ms;
832+ EXPECT_CALL(*fake_timers.prepared_timer.get(), schedule_in(delay));
833+ EXPECT_CALL(*fake_timers.prepared_timer.get(), schedule_in(interval));
834+
835+ repeater.enable(50ms, 10ms);
836+ repeater.press(a_key);
837+ fake_timers.execute_last_timer();
838+}
839+
840+TEST_F(KeyRepeater, callback_called_on_timeout)
841+{
842+ EXPECT_CALL(*this, repeat_called(a_key)).Times(1);
843+
844+ repeater.press(a_key);
845+ fake_timers.execute_last_timer();
846+}
847+
848+TEST_F(KeyRepeater, one_alarm_for_all_keys)
849+{
850+ EXPECT_CALL(fake_timers, timer_created(_,_)).Times(1);
851+ repeater.press(a_key);
852+ repeater.press(another_key);
853+}
854+
855+TEST_F(KeyRepeater, alarm_canceld_on_release_of_last_key)
856+{
857+ fake_timers.prepared_timer = std::make_unique<NiceMock<mtd::MockTimerFd>>();
858+ auto & prepared_timer = *fake_timers.prepared_timer.get();
859+ EXPECT_CALL(fake_timers, timer_created(_,_)).Times(1);
860+ EXPECT_CALL(prepared_timer, schedule_in(_)).Times(1);
861+ EXPECT_CALL(prepared_timer, cancel()).Times(0);
862+ repeater.press(a_key);
863+ repeater.press(another_key);
864+ repeater.press(third_key);
865+ testing::Mock::VerifyAndClear(&prepared_timer);
866+
867+ EXPECT_CALL(prepared_timer, cancel()).Times(0);
868+ repeater.release(another_key);
869+ repeater.release(a_key);
870+
871+ testing::Mock::VerifyAndClear(&prepared_timer);
872+
873+ EXPECT_CALL(prepared_timer, cancel()).Times(1);
874+ repeater.release(third_key);
875+}

Subscribers

People subscribed via source and target branches