Mir

Merge lp:~andreas-pokorny/mir/rebase-fix-1550050 into lp:mir

Proposed by Andreas Pokorny
Status: Merged
Approved by: Daniel van Vugt
Approved revision: no longer in the source branch.
Merged at revision: 3397
Proposed branch: lp:~andreas-pokorny/mir/rebase-fix-1550050
Merge into: lp:mir
Diff against target: 343 lines (+153/-31)
5 files modified
src/server/input/default_configuration.cpp (+14/-2)
src/server/input/default_input_device_hub.cpp (+14/-8)
src/server/input/key_repeat_dispatcher.cpp (+41/-0)
src/server/input/key_repeat_dispatcher.h (+7/-4)
tests/unit-tests/input/test_key_repeat_dispatcher.cpp (+77/-17)
To merge this branch: bzr merge lp:~andreas-pokorny/mir/rebase-fix-1550050
Reviewer Review Type Date Requested Status
Alan Griffiths Approve
Mir CI Bot continuous-integration Needs Fixing
Andreas Pokorny (community) Needs Information
Daniel van Vugt Abstain
Cemil Azizoglu (community) Approve
Review via email: mp+288945@code.launchpad.net

Commit message

Fixes the potential endless repeat on unplugged devices (LP: #1550050)

The key repeat dispatcher now reacts on the removal of input devices by resetting potentially still active repeat alarms. The integration here is a bit clumsy, since the input device hub needs the input dispatcher to forward device events. While the input dispatcher needs it to register at the input device hub as an observer.

Description of the change

This fix registers for device changes and then stops sending repeat events for removed devices.

A different approach to this one which requires adding a two step initialization will be proposed soon, but requires an ABI change in the input platform interface.

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

PASSED: Continuous integration, rev:3386
https://mir-jenkins.ubuntu.com/job/mir-ci/560/
Executed test runs:
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-mir/448
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-0-fetch/478
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-1-sourcepkg/release=vivid+overlay/470
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-1-sourcepkg/release=xenial/470
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=clang,platform=mesa,release=vivid+overlay/457
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=clang,platform=mesa,release=vivid+overlay/457/artifact/output/*zip*/output.zip
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=gcc,platform=mesa,release=xenial/457
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=gcc,platform=mesa,release=xenial/457/artifact/output/*zip*/output.zip
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=cross-armhf,compiler=gcc,platform=android,release=vivid+overlay/457
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=cross-armhf,compiler=gcc,platform=android,release=vivid+overlay/457/artifact/output/*zip*/output.zip
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=i386,compiler=gcc,platform=android,release=vivid+overlay/457
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=i386,compiler=gcc,platform=android,release=vivid+overlay/457/artifact/output/*zip*/output.zip
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=i386,compiler=gcc,platform=mesa,release=xenial/457
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=i386,compiler=gcc,platform=mesa,release=xenial/457/artifact/output/*zip*/output.zip

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

review: Approve (continuous-integration)
Revision history for this message
Cemil Azizoglu (cemil-azizoglu) wrote :

LGTM

review: Approve
Revision history for this message
Daniel van Vugt (vanvugt) wrote :

The version is incorrect. Should be 0.21.0 in lp:mir

Also the changelog is incorrect for the same reason.

review: Needs Fixing
Revision history for this message
Daniel van Vugt (vanvugt) wrote :

Separate MPs are up to fix the above issues. You can just remove your version changes here...

review: Needs Fixing
Revision history for this message
Andreas Pokorny (andreas-pokorny) wrote :

ok removed the 'unreleased' changelog entry.
My understanding was that we will make another 0.20.3 release using what is currently in lp:mir - since there are no ABI breaks yet.

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

FAILED: Continuous integration, rev:3387
https://mir-jenkins.ubuntu.com/job/mir-ci/572/
Executed test runs:
    FAILURE: https://mir-jenkins.ubuntu.com/job/build-mir/467/console
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-0-fetch/497
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-1-sourcepkg/release=vivid+overlay/489
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-1-sourcepkg/release=xenial/489
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=clang,platform=mesa,release=vivid+overlay/476
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=clang,platform=mesa,release=vivid+overlay/476/artifact/output/*zip*/output.zip
    FAILURE: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=gcc,platform=mesa,release=xenial/476/console
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=cross-armhf,compiler=gcc,platform=android,release=vivid+overlay/476
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=cross-armhf,compiler=gcc,platform=android,release=vivid+overlay/476/artifact/output/*zip*/output.zip
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=i386,compiler=gcc,platform=android,release=vivid+overlay/476
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=i386,compiler=gcc,platform=android,release=vivid+overlay/476/artifact/output/*zip*/output.zip
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=i386,compiler=gcc,platform=mesa,release=xenial/476
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=i386,compiler=gcc,platform=mesa,release=xenial/476/artifact/output/*zip*/output.zip

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

review: Needs Fixing (continuous-integration)
Revision history for this message
Daniel van Vugt (vanvugt) wrote :

lp:mir is series 0.21, which is clear in the launchpad config:
https://launchpad.net/mir

So lp:mir should always call itself series 0.21 until such time as that's released and we're working on series 0.22.

If you want to release a 0.20.3 then that must occur in lp:mir/0.20.

review: Abstain
Revision history for this message
Andreas Pokorny (andreas-pokorny) wrote :

Agreed. Depending on where we release from we do not need this MP!

review: Needs Information
Revision history for this message
Alan Griffiths (alan-griffiths) wrote :

We probably don't need this on trunk. Either we:

1. release 0.20.x from mir/0.20 - which already has this fix;
2. release a better solution (which I understand will break ABI) as 0.21; or,
3. we release 0.21 with this solution and apply the better solution in 0.22

I think we intend to release 0.20.3 and don't need this (yet).

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

FAILED: Continuous integration, rev:3387
https://mir-jenkins.ubuntu.com/job/mir-ci/578/
Executed test runs:
    FAILURE: https://mir-jenkins.ubuntu.com/job/build-mir/475/console
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-0-fetch/505
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-1-sourcepkg/release=vivid+overlay/497
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-1-sourcepkg/release=xenial/497
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=clang,platform=mesa,release=vivid+overlay/484
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=clang,platform=mesa,release=vivid+overlay/484/artifact/output/*zip*/output.zip
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=gcc,platform=mesa,release=xenial/484
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=gcc,platform=mesa,release=xenial/484/artifact/output/*zip*/output.zip
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=cross-armhf,compiler=gcc,platform=android,release=vivid+overlay/484
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=cross-armhf,compiler=gcc,platform=android,release=vivid+overlay/484/artifact/output/*zip*/output.zip
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=i386,compiler=gcc,platform=android,release=vivid+overlay/484
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=i386,compiler=gcc,platform=android,release=vivid+overlay/484/artifact/output/*zip*/output.zip
    FAILURE: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=i386,compiler=gcc,platform=mesa,release=xenial/484/console

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

review: Needs Fixing (continuous-integration)
Revision history for this message
Alan Griffiths (alan-griffiths) wrote :

> We probably don't need this on trunk. Either we:
>
> 1. release 0.20.x from mir/0.20 - which already has this fix;
> 2. release a better solution (which I understand will break ABI) as 0.21; or,
> 3. we release 0.21 with this solution and apply the better solution in 0.22
>
> I think we intend to release 0.20.3 and don't need this (yet).

...we went for option 3

review: Approve
Revision history for this message
Daniel van Vugt (vanvugt) wrote :

The failure is due to more random display configuration API failures. We've had a lot of them lately.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'src/server/input/default_configuration.cpp'
--- src/server/input/default_configuration.cpp 2016-03-09 11:19:15 +0000
+++ src/server/input/default_configuration.cpp 2016-03-15 07:45:18 +0000
@@ -295,12 +295,18 @@
295 return default_input_device_hub(295 return default_input_device_hub(
296 [this]()296 [this]()
297 {297 {
298 return std::make_shared<mi::DefaultInputDeviceHub>(298 auto input_dispatcher = the_input_dispatcher();
299 auto key_repeater = std::dynamic_pointer_cast<mi::KeyRepeatDispatcher>(input_dispatcher);
300 auto hub = std::make_shared<mi::DefaultInputDeviceHub>(
299 the_global_event_sink(),301 the_global_event_sink(),
300 the_seat(),302 the_seat(),
301 the_input_reading_multiplexer(),303 the_input_reading_multiplexer(),
302 the_main_loop(),304 the_main_loop(),
303 the_cookie_authority());305 the_cookie_authority());
306
307 if (key_repeater)
308 key_repeater->set_input_device_hub(hub);
309 return hub;
304 });310 });
305}311}
306312
@@ -309,11 +315,17 @@
309 return default_input_device_hub(315 return default_input_device_hub(
310 [this]()316 [this]()
311 {317 {
312 return std::make_shared<mi::DefaultInputDeviceHub>(318 auto input_dispatcher = the_input_dispatcher();
319 auto key_repeater = std::dynamic_pointer_cast<mi::KeyRepeatDispatcher>(input_dispatcher);
320 auto hub = std::make_shared<mi::DefaultInputDeviceHub>(
313 the_global_event_sink(),321 the_global_event_sink(),
314 the_seat(),322 the_seat(),
315 the_input_reading_multiplexer(),323 the_input_reading_multiplexer(),
316 the_main_loop(),324 the_main_loop(),
317 the_cookie_authority());325 the_cookie_authority());
326
327 if (key_repeater)
328 key_repeater->set_input_device_hub(hub);
329 return hub;
318 });330 });
319}331}
320332
=== modified file 'src/server/input/default_input_device_hub.cpp'
--- src/server/input/default_input_device_hub.cpp 2016-03-08 20:43:41 +0000
+++ src/server/input/default_input_device_hub.cpp 2016-03-15 07:45:18 +0000
@@ -244,17 +244,23 @@
244void mi::DefaultInputDeviceHub::remove_device_handle(MirInputDeviceId id)244void mi::DefaultInputDeviceHub::remove_device_handle(MirInputDeviceId id)
245{245{
246 std::unique_lock<std::mutex> lock(observer_guard);246 std::unique_lock<std::mutex> lock(observer_guard);
247 auto handle_it = remove_if(begin(handles),247 auto handle_it = remove_if(
248 end(handles),248 begin(handles),
249 [&id](auto const& handle){return handle->id() == id;});249 end(handles),
250 [this,&id](auto const& handle)
251 {
252 if (handle->id() != id)
253 return false;
254 for (auto const& observer : observers)
255 {
256 observer->device_removed(handle);
257 observer->changes_complete();
258 }
259 return true;
260 });
250261
251 if (handle_it == end(handles))262 if (handle_it == end(handles))
252 return;263 return;
253 for (auto const& observer : observers)
254 {
255 observer->device_removed(*handle_it);
256 observer->changes_complete();
257 }
258264
259 handles.erase(handle_it, end(handles));265 handles.erase(handle_it, end(handles));
260 sink->handle_input_device_change(handles);266 sink->handle_input_device_change(handles);
261267
=== modified file 'src/server/input/key_repeat_dispatcher.cpp'
--- src/server/input/key_repeat_dispatcher.cpp 2016-01-29 08:18:22 +0000
+++ src/server/input/key_repeat_dispatcher.cpp 2016-03-15 07:45:18 +0000
@@ -18,6 +18,8 @@
1818
19#include "key_repeat_dispatcher.h"19#include "key_repeat_dispatcher.h"
2020
21#include "mir/input/device.h"
22#include "mir/input/input_device_hub.h"
21#include "mir/time/alarm_factory.h"23#include "mir/time/alarm_factory.h"
22#include "mir/time/alarm.h"24#include "mir/time/alarm.h"
23#include "mir/events/event_private.h"25#include "mir/events/event_private.h"
@@ -31,6 +33,34 @@
3133
32namespace mi = mir::input;34namespace mi = mir::input;
3335
36namespace
37{
38struct DeviceRemovalFilter : mi::InputDeviceObserver
39{
40 DeviceRemovalFilter(std::function<void(MirInputDeviceId)> const& on_removal)
41 : on_removal(on_removal) {}
42
43 void device_added(std::shared_ptr<mi::Device> const&) override
44 {
45 }
46
47 void device_changed(std::shared_ptr<mi::Device> const&) override
48 {
49 }
50
51 void device_removed(std::shared_ptr<mi::Device> const& device) override
52 {
53 on_removal(device->id());
54 }
55
56 void changes_complete() override
57 {
58 }
59 std::function<void(MirInputDeviceId)> on_removal;
60};
61
62}
63
34mi::KeyRepeatDispatcher::KeyRepeatDispatcher(64mi::KeyRepeatDispatcher::KeyRepeatDispatcher(
35 std::shared_ptr<mi::InputDispatcher> const& next_dispatcher,65 std::shared_ptr<mi::InputDispatcher> const& next_dispatcher,
36 std::shared_ptr<mir::time::AlarmFactory> const& factory,66 std::shared_ptr<mir::time::AlarmFactory> const& factory,
@@ -47,6 +77,17 @@
47{77{
48}78}
4979
80void mi::KeyRepeatDispatcher::set_input_device_hub(std::shared_ptr<InputDeviceHub> const& hub)
81{
82 hub->add_observer(std::make_shared<DeviceRemovalFilter>(
83 [this](MirInputDeviceId id)
84 {
85 std::unique_lock<std::mutex> lock(repeat_state_mutex);
86 repeat_state_by_device.erase(id); // destructor cancels alarms
87 }
88 ));
89}
90
50mi::KeyRepeatDispatcher::KeyboardState& mi::KeyRepeatDispatcher::ensure_state_for_device_locked(std::lock_guard<std::mutex> const&, MirInputDeviceId id)91mi::KeyRepeatDispatcher::KeyboardState& mi::KeyRepeatDispatcher::ensure_state_for_device_locked(std::lock_guard<std::mutex> const&, MirInputDeviceId id)
51{92{
52 repeat_state_by_device.insert(std::make_pair(id, KeyboardState()));93 repeat_state_by_device.insert(std::make_pair(id, KeyboardState()));
5394
=== modified file 'src/server/input/key_repeat_dispatcher.h'
--- src/server/input/key_repeat_dispatcher.h 2016-01-29 08:18:22 +0000
+++ src/server/input/key_repeat_dispatcher.h 2016-03-15 07:45:18 +0000
@@ -1,5 +1,5 @@
1/*1/*
2 * Copyright © 2015 Canonical Ltd.2 * Copyright © 2015-2016 Canonical Ltd.
3 *3 *
4 * This program is free software: you can redistribute it and/or modify it4 * This program is free software: you can redistribute it and/or modify it
5 * under the terms of the GNU General Public License version 3,5 * under the terms of the GNU General Public License version 3,
@@ -20,6 +20,7 @@
20#define MIR_INPUT_KEY_REPEAT_DISPATCHER_H_20#define MIR_INPUT_KEY_REPEAT_DISPATCHER_H_
2121
22#include "mir/input/input_dispatcher.h"22#include "mir/input/input_dispatcher.h"
23#include "mir/input/input_device_observer.h"
2324
24#include <memory>25#include <memory>
25#include <chrono>26#include <chrono>
@@ -39,8 +40,8 @@
39}40}
40namespace input41namespace input
41{42{
4243class InputDeviceHub;
43class KeyRepeatDispatcher : public mir::input::InputDispatcher44class KeyRepeatDispatcher : public InputDispatcher
44{45{
45public:46public:
46 KeyRepeatDispatcher(std::shared_ptr<InputDispatcher> const& next_dispatcher,47 KeyRepeatDispatcher(std::shared_ptr<InputDispatcher> const& next_dispatcher,
@@ -54,7 +55,9 @@
54 bool dispatch(MirEvent const& event) override;55 bool dispatch(MirEvent const& event) override;
55 void start() override;56 void start() override;
56 void stop() override;57 void stop() override;
57 58
59 void set_input_device_hub(std::shared_ptr<InputDeviceHub> const& hub);
60
58private:61private:
59 std::mutex repeat_state_mutex;62 std::mutex repeat_state_mutex;
6063
6164
=== modified file 'tests/unit-tests/input/test_key_repeat_dispatcher.cpp'
--- tests/unit-tests/input/test_key_repeat_dispatcher.cpp 2016-01-29 08:18:22 +0000
+++ tests/unit-tests/input/test_key_repeat_dispatcher.cpp 2016-03-15 07:45:18 +0000
@@ -23,9 +23,15 @@
23#include "mir/time/alarm.h"23#include "mir/time/alarm.h"
24#include "mir/time/alarm_factory.h"24#include "mir/time/alarm_factory.h"
25#include "mir/cookie/authority.h"25#include "mir/cookie/authority.h"
26#include "mir/input/input_device_observer.h"
27#include "mir/input/pointer_configuration.h"
28#include "mir/input/touchpad_configuration.h"
29#include "mir/input/device.h"
2630
31#include "mir/test/fake_shared.h"
27#include "mir/test/event_matchers.h"32#include "mir/test/event_matchers.h"
28#include "mir/test/doubles/mock_input_dispatcher.h"33#include "mir/test/doubles/mock_input_dispatcher.h"
34#include "mir/test/doubles/mock_input_device_hub.h"
2935
30#include <gtest/gtest.h>36#include <gtest/gtest.h>
31#include <gmock/gmock.h>37#include <gmock/gmock.h>
@@ -35,6 +41,8 @@
35namespace mt = mir::test;41namespace mt = mir::test;
36namespace mtd = mt::doubles;42namespace mtd = mt::doubles;
3743
44using namespace ::testing;
45
38namespace46namespace
39{47{
40struct MockAlarm : public mir::time::Alarm48struct MockAlarm : public mir::time::Alarm
@@ -43,6 +51,12 @@
43 MOCK_CONST_METHOD0(state, mir::time::Alarm::State());51 MOCK_CONST_METHOD0(state, mir::time::Alarm::State());
44 MOCK_METHOD1(reschedule_in, bool(std::chrono::milliseconds));52 MOCK_METHOD1(reschedule_in, bool(std::chrono::milliseconds));
45 MOCK_METHOD1(reschedule_for, bool(mir::time::Timestamp));53 MOCK_METHOD1(reschedule_for, bool(mir::time::Timestamp));
54
55 // destructor cancels the alarm
56 ~MockAlarm()
57 {
58 cancel();
59 }
46};60};
4761
48struct MockAlarmFactory : public mir::time::AlarmFactory62struct MockAlarmFactory : public mir::time::AlarmFactory
@@ -59,25 +73,60 @@
59 }73 }
60};74};
6175
76struct StubDevice : public mi::Device
77{
78 MirInputDeviceId device_id;
79 StubDevice(MirInputDeviceId id) : device_id(id) {}
80 MirInputDeviceId id() const { return device_id;}
81 mi::DeviceCapabilities capabilities() const {return mi::DeviceCapability::keyboard;}
82 std::string name() const {return {};}
83 std::string unique_id() const {return {};}
84
85 mir::optional_value<mi::PointerConfiguration> pointer_configuration() const {return {};}
86 void apply_pointer_configuration(mi::PointerConfiguration const&) {;}
87 mir::optional_value<mi::TouchpadConfiguration> touchpad_configuration() const {return {};}
88 void apply_touchpad_configuration(mi::TouchpadConfiguration const&) {}
89};
90
62struct KeyRepeatDispatcher : public testing::Test91struct KeyRepeatDispatcher : public testing::Test
63{92{
64 KeyRepeatDispatcher()93 KeyRepeatDispatcher()
65 : dispatcher(mock_next_dispatcher, mock_alarm_factory, cookie_authority, true, repeat_time, repeat_delay)94 : dispatcher(mock_next_dispatcher, mock_alarm_factory, cookie_authority, true, repeat_time, repeat_delay)
66 {95 {
67 }96 ON_CALL(hub,add_observer(_)).WillByDefault(SaveArg<0>(&observer));
97 dispatcher.set_input_device_hub(mt::fake_shared(hub));
98 }
99 void simulate_device_removal()
100 {
101 StubDevice dev(test_device);
102 observer->device_removed(mt::fake_shared(dev));
103 observer->changes_complete();
104 }
105
106 const MirInputDeviceId test_device = 123;
68 std::shared_ptr<mtd::MockInputDispatcher> mock_next_dispatcher = std::make_shared<mtd::MockInputDispatcher>();107 std::shared_ptr<mtd::MockInputDispatcher> mock_next_dispatcher = std::make_shared<mtd::MockInputDispatcher>();
69 std::shared_ptr<MockAlarmFactory> mock_alarm_factory = std::make_shared<MockAlarmFactory>();108 std::shared_ptr<MockAlarmFactory> mock_alarm_factory = std::make_shared<MockAlarmFactory>();
70 std::shared_ptr<mir::cookie::Authority> cookie_authority = mir::cookie::Authority::create();109 std::shared_ptr<mir::cookie::Authority> cookie_authority = mir::cookie::Authority::create();
71 std::chrono::milliseconds const repeat_time{2};110 std::chrono::milliseconds const repeat_time{2};
72 std::chrono::milliseconds const repeat_delay{1};111 std::chrono::milliseconds const repeat_delay{1};
112 std::shared_ptr<mi::InputDeviceObserver> observer;
113 NiceMock<mtd::MockInputDeviceHub> hub;
73 mi::KeyRepeatDispatcher dispatcher;114 mi::KeyRepeatDispatcher dispatcher;
115
116 mir::EventUPtr a_key_down_event()
117 {
118 return mev::make_event(test_device, std::chrono::nanoseconds(0), std::vector<uint8_t>{}, mir_keyboard_action_down, 0, 0, mir_input_event_modifier_alt);
119 }
120
121 mir::EventUPtr a_key_up_event()
122 {
123 return mev::make_event(test_device, std::chrono::nanoseconds(0), std::vector<uint8_t>{}, mir_keyboard_action_up, 0, 0, mir_input_event_modifier_alt);
124 }
74};125};
75}126}
76127
77TEST_F(KeyRepeatDispatcher, forwards_start_stop)128TEST_F(KeyRepeatDispatcher, forwards_start_stop)
78{129{
79 using namespace ::testing;
80
81 InSequence seq;130 InSequence seq;
82 EXPECT_CALL(*mock_next_dispatcher, start()).Times(1);131 EXPECT_CALL(*mock_next_dispatcher, start()).Times(1);
83 EXPECT_CALL(*mock_next_dispatcher, stop()).Times(1);132 EXPECT_CALL(*mock_next_dispatcher, stop()).Times(1);
@@ -86,22 +135,8 @@
86 dispatcher.stop();135 dispatcher.stop();
87}136}
88137
89namespace
90{
91mir::EventUPtr a_key_down_event()
92{
93 return mev::make_event(0, std::chrono::nanoseconds(0), std::vector<uint8_t>{}, mir_keyboard_action_down, 0, 0, mir_input_event_modifier_alt);
94}
95mir::EventUPtr a_key_up_event()
96{
97 return mev::make_event(0, std::chrono::nanoseconds(0), std::vector<uint8_t>{}, mir_keyboard_action_up, 0, 0, mir_input_event_modifier_alt);
98}
99}
100
101TEST_F(KeyRepeatDispatcher, schedules_alarm_to_repeat_key_down)138TEST_F(KeyRepeatDispatcher, schedules_alarm_to_repeat_key_down)
102{139{
103 using namespace ::testing;
104
105 MockAlarm *mock_alarm = new MockAlarm; // deleted by AlarmFactory140 MockAlarm *mock_alarm = new MockAlarm; // deleted by AlarmFactory
106 std::function<void()> alarm_function;141 std::function<void()> alarm_function;
107142
@@ -122,3 +157,28 @@
122 // Trigger the cancel157 // Trigger the cancel
123 dispatcher.dispatch(*a_key_up_event());158 dispatcher.dispatch(*a_key_up_event());
124}159}
160
161TEST_F(KeyRepeatDispatcher, stops_repeat_on_device_removal)
162{
163 MockAlarm *mock_alarm = new MockAlarm;
164 std::function<void()> alarm_function;
165 bool alarm_canceled = false;
166
167 InSequence seq;
168 EXPECT_CALL(*mock_alarm_factory, create_alarm_adapter(_)).Times(1).
169 WillOnce(DoAll(SaveArg<0>(&alarm_function), Return(mock_alarm)));
170 // Once for initial down and again when invoked
171 EXPECT_CALL(*mock_alarm, reschedule_in(repeat_time)).Times(1).WillOnce(Return(true));
172 EXPECT_CALL(*mock_next_dispatcher, dispatch(mt::KeyDownEvent())).Times(1);
173 EXPECT_CALL(*mock_next_dispatcher, dispatch(mt::KeyRepeatEvent())).Times(1);
174 EXPECT_CALL(*mock_alarm, reschedule_in(repeat_delay)).Times(1).WillOnce(Return(true));
175 ON_CALL(*mock_alarm, cancel()).WillByDefault(Invoke([&](){alarm_canceled = true; return true;}));
176
177 dispatcher.dispatch(*a_key_down_event());
178
179 alarm_function();
180 Mock::VerifyAndClearExpectations(mock_alarm); // mock_alarm will be deleted after this
181
182 simulate_device_removal();
183 EXPECT_THAT(alarm_canceled, Eq(true));
184}

Subscribers

People subscribed via source and target branches