Merge lp:~andreas-pokorny/mir/move-key-repeat-into-input-platforms into lp:mir
- move-key-repeat-into-input-platforms
- Merge into development-branch
Status: | Work in progress |
---|---|
Proposed branch: | lp:~andreas-pokorny/mir/move-key-repeat-into-input-platforms |
Merge into: | lp:mir |
Prerequisite: | lp:~andreas-pokorny/mir/add-key-repeat-utility |
Diff against target: |
1902 lines (+514/-581) 31 files modified
include/platform/mir/input/input_device.h (+4/-0) include/platform/mir/input/keyboard_settings.h (+42/-0) src/platforms/evdev/key_repeater.cpp (+2/-0) src/platforms/evdev/key_repeater.h (+1/-0) src/platforms/evdev/libinput_device.cpp (+45/-5) src/platforms/evdev/libinput_device.h (+15/-5) src/platforms/evdev/platform.cpp (+15/-7) src/platforms/evdev/platform.h (+7/-0) src/platforms/mesa/server/x11/input/input_device.cpp (+52/-3) src/platforms/mesa/server/x11/input/input_device.h (+5/-1) src/platforms/mesa/server/x11/input/input_platform.cpp (+9/-12) src/server/input/CMakeLists.txt (+0/-1) src/server/input/default_configuration.cpp (+7/-26) src/server/input/default_input_device_hub.cpp (+12/-2) src/server/input/default_input_device_hub.h (+3/-1) src/server/input/key_repeat_dispatcher.cpp (+0/-186) src/server/input/key_repeat_dispatcher.h (+0/-84) tests/include/mir/test/doubles/mock_input_device.h (+3/-0) tests/include/mir/test/doubles/mock_x11.h (+8/-0) tests/include/mir_test_framework/stub_input_platform.h (+15/-0) tests/mir_test_doubles/mock_input_device.cpp (+8/-0) tests/mir_test_doubles/mock_x11.cpp (+35/-0) tests/mir_test_framework/fake_input_device_impl.cpp (+54/-14) tests/mir_test_framework/fake_input_device_impl.h (+15/-1) tests/mir_test_framework/stub_input_platform.cpp (+21/-0) tests/unit-tests/input/CMakeLists.txt (+0/-1) tests/unit-tests/input/evdev/test_evdev_device_detection.cpp (+8/-1) tests/unit-tests/input/evdev/test_libinput_device.cpp (+42/-10) tests/unit-tests/input/test_default_device.cpp (+6/-37) tests/unit-tests/input/test_key_repeat_dispatcher.cpp (+0/-184) tests/unit-tests/input/test_x11_platform.cpp (+80/-0) |
To merge this branch: | bzr merge lp:~andreas-pokorny/mir/move-key-repeat-into-input-platforms |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Daniel van Vugt | Needs Information | ||
Kevin DuBois (community) | Approve | ||
Mir CI Bot | continuous-integration | Needs Fixing | |
Brandon Schaefer (community) | Approve | ||
Review via email: mp+289963@code.launchpad.net |
Commit message
Introduces KeyboardSettings to configure key repeat and moves the responsibility out to input platforms
X11 forwards the settings to Xkb, while evdev and stub input implement the repeat handling via the KeyRepeater introduced in a previous change. With that the key repeat is also closer to be being runtime configureable. (wiring to mir::input::Device or the client API still outstanding).
Description of the change
This moves the key repeat tracking into the input platform. With that the dynamic_
Kludge: The mir option MIR_SERVER_
Mir CI Bot (mir-ci-bot) wrote : | # |
Mir CI Bot (mir-ci-bot) wrote : | # |
FAILED: Continuous integration, rev:3421
https:/
Executed test runs:
FAILURE: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
FAILURE: https:/
FAILURE: https:/
SUCCESS: https:/
deb: https:/
FAILURE: https:/
FAILURE: https:/
Click here to trigger a rebuild:
https:/
Brandon Schaefer (brandontschaefer) wrote : | # |
Yay for deleting code!
+ std::shared_
+ : report{report},
+ std::unique_
+ : report(report),
+mix::XInputDev
+ : display{display}, info(device_info)
+ std::shared_
+ : x11_connection{
The : needs to go on the same line as the ctor (at lease according to the coding style). I see most of those were on the init list line before this branch. Feel free to fix them (just a nit).
+class Alarm;
I dont see that namespace used? (Unless i missed it :). Do we need this forward dec?
Do we just not care about the key_code here?
sink->
Changes make sense.
- 3422. By Andreas Pokorny
-
removed fwd decl
Andreas Pokorny (andreas-pokorny) wrote : | # |
> Yay for deleting code!
>
> + std::shared_
> clock)
> + : report{report},
>
> + std::unique_
> + : report(report),
>
> +mix::XInputDev
> std::shared_
> + : display{display}, info(device_info)
>
> + std::shared_
> + : x11_connection{
>
> The : needs to go on the same line as the ctor (at lease according to the
> coding style). I see most of those were on the init list line before this
> branch. Feel free to fix them (just a nit).
We have both variants in the style guide - for some reason our current clang-format setup seems to prefer the version above..
>
> +class Alarm;
> I dont see that namespace used? (Unless i missed it :). Do we need this
> forward dec?
ack removed.
> Do we just not care about the key_code here?
> sink->handle_
> mir_keyboard_
I guess testing that the actual key code is repeated might be reasonable thing to test..
Mir CI Bot (mir-ci-bot) wrote : | # |
FAILED: Continuous integration, rev:3422
https:/
Executed test runs:
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
Click here to trigger a rebuild:
https:/
Brandon Schaefer (brandontschaefer) wrote : | # |
(Besides the conflicts, this looks good to me :)
- 3423. By Andreas Pokorny
-
merge prereq
Mir CI Bot (mir-ci-bot) wrote : | # |
FAILED: Continuous integration, rev:3423
https:/
Executed test runs:
FAILURE: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
FAILURE: https:/
FAILURE: https:/
SUCCESS: https:/
deb: https:/
FAILURE: https:/
FAILURE: https:/
Click here to trigger a rebuild:
https:/
Kevin DuBois (kdub) wrote : | # |
nits:
+ KeyboardSettings() {}
not needed
1122: + settings.
why indent further?
1031: braces around multiline if/else
lgtm otherwise
Daniel van Vugt (vanvugt) wrote : | # |
The prerequisite branch is on hold. So should that make this one on hold too?
Unmerged revisions
- 3423. By Andreas Pokorny
-
merge prereq
- 3422. By Andreas Pokorny
-
removed fwd decl
- 3421. By Andreas Pokorny
-
update libinput test fixture
- 3420. By Andreas Pokorny
-
Update X11 Unit tests
- 3419. By Andreas Pokorny
-
add missing file - KeyboardSettings
- 3418. By Andreas Pokorny
-
merge prereq
- 3417. By Andreas Pokorny
-
Integrate Key repeater into stub intput platform
- 3416. By Andreas Pokorny
-
Integrate Key Repeater
- 3415. By Andreas Pokorny
-
Add Key repeat utility
Similar to the key press tracking in KeyRepeatDispat
cher, this class will support the evdev platform and fake input devices in implementing repeat handling. - 3414. By Andreas Pokorny
-
Add mir::dispatch:
:AlarmFactory Implementation of mir::time:
:AlarmFactory that works with mir::dispatch: :Dispatchable and supports all the state transitions required by the test suite accumulated in test_glib_ main_loop. cpp. With this change several GPL interfaces defined inside the mirserver API have been moved to mircommon and LGPL.
Preview Diff
1 | === modified file 'include/platform/mir/input/input_device.h' |
2 | --- include/platform/mir/input/input_device.h 2016-01-29 08:18:22 +0000 |
3 | +++ include/platform/mir/input/input_device.h 2016-03-31 19:18:58 +0000 |
4 | @@ -39,6 +39,7 @@ |
5 | |
6 | class PointerSettings; |
7 | class TouchpadSettings; |
8 | +class KeyboardSettings; |
9 | |
10 | /** |
11 | * Represents an input device. |
12 | @@ -65,6 +66,9 @@ |
13 | |
14 | virtual optional_value<TouchpadSettings> get_touchpad_settings() const = 0; |
15 | virtual void apply_settings(TouchpadSettings const&) = 0; |
16 | + |
17 | + virtual optional_value<KeyboardSettings> get_keyboard_settings() const = 0; |
18 | + virtual void apply_settings(KeyboardSettings const&) = 0; |
19 | protected: |
20 | InputDevice(InputDevice const&) = delete; |
21 | InputDevice& operator=(InputDevice const&) = delete; |
22 | |
23 | === added file 'include/platform/mir/input/keyboard_settings.h' |
24 | --- include/platform/mir/input/keyboard_settings.h 1970-01-01 00:00:00 +0000 |
25 | +++ include/platform/mir/input/keyboard_settings.h 2016-03-31 19:18:58 +0000 |
26 | @@ -0,0 +1,42 @@ |
27 | +/* |
28 | + * Copyright © 2016 Canonical Ltd. |
29 | + * |
30 | + * This program is free software: you can redistribute it and/or modify it |
31 | + * under the terms of the GNU Lesser General Public License version 3, |
32 | + * as published by the Free Software Foundation. |
33 | + * |
34 | + * This program is distributed in the hope that it will be useful, |
35 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
36 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
37 | + * GNU Lesser General Public License for more details. |
38 | + * |
39 | + * You should have received a copy of the GNU Lesser General Public License |
40 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
41 | + * |
42 | + * Authored by: |
43 | + * Andreas Pokorny <andreas.pokorny@canonical.com> |
44 | + */ |
45 | + |
46 | +#ifndef MIR_INPUT_KEY_BOARD_SETTINGS_H_ |
47 | +#define MIR_INPUT_KEY_BOARD_SETTINGS_H_ |
48 | + |
49 | +#include "mir_toolkit/mir_input_device.h" |
50 | +#include <chrono> |
51 | + |
52 | +namespace mir |
53 | +{ |
54 | +namespace input |
55 | +{ |
56 | + |
57 | +struct KeyboardSettings |
58 | +{ |
59 | + KeyboardSettings() {} |
60 | + bool repeat_enabled{true}; |
61 | + std::chrono::milliseconds repeat_delay{50}; |
62 | + std::chrono::milliseconds repeat_interval{500}; |
63 | +}; |
64 | + |
65 | +} |
66 | +} |
67 | + |
68 | +#endif |
69 | |
70 | === modified file 'src/platforms/evdev/key_repeater.cpp' |
71 | --- src/platforms/evdev/key_repeater.cpp 2016-03-31 19:18:58 +0000 |
72 | +++ src/platforms/evdev/key_repeater.cpp 2016-03-31 19:18:58 +0000 |
73 | @@ -29,6 +29,8 @@ |
74 | { |
75 | } |
76 | |
77 | +mie::KeyRepeater::~KeyRepeater() = default; |
78 | + |
79 | void mie::KeyRepeater::enable(std::chrono::milliseconds repeat_delay, std::chrono::milliseconds repeat_interval) |
80 | { |
81 | enabled_ = true; |
82 | |
83 | === modified file 'src/platforms/evdev/key_repeater.h' |
84 | --- src/platforms/evdev/key_repeater.h 2016-03-31 19:18:58 +0000 |
85 | +++ src/platforms/evdev/key_repeater.h 2016-03-31 19:18:58 +0000 |
86 | @@ -39,6 +39,7 @@ |
87 | struct KeyRepeater |
88 | { |
89 | KeyRepeater(std::shared_ptr<mir::time::AlarmFactory> const& alarm_factory, std::function<void(int32_t keycode)> const& send_repeat_key); |
90 | + ~KeyRepeater(); |
91 | void enable(std::chrono::milliseconds repeat_delay, std::chrono::milliseconds repeat_interval); |
92 | void disable(); |
93 | bool enabled() const; |
94 | |
95 | === modified file 'src/platforms/evdev/libinput_device.cpp' |
96 | --- src/platforms/evdev/libinput_device.cpp 2016-03-23 06:39:56 +0000 |
97 | +++ src/platforms/evdev/libinput_device.cpp 2016-03-31 19:18:58 +0000 |
98 | @@ -27,11 +27,11 @@ |
99 | #include "mir/input/device_capability.h" |
100 | #include "mir/input/pointer_settings.h" |
101 | #include "mir/input/touchpad_settings.h" |
102 | +#include "mir/input/keyboard_settings.h" |
103 | #include "mir/input/input_device_info.h" |
104 | #include "mir/events/event_builders.h" |
105 | #include "mir/geometry/displacement.h" |
106 | -#include "mir/dispatch/dispatchable.h" |
107 | -#include "mir/fd.h" |
108 | +#include "mir/time/clock.h" |
109 | #define MIR_LOG_COMPONENT "evdev" |
110 | #include "mir/log.h" |
111 | #include "mir/raii.h" |
112 | @@ -45,13 +45,19 @@ |
113 | #include <sstream> |
114 | #include <algorithm> |
115 | |
116 | -namespace md = mir::dispatch; |
117 | namespace mi = mir::input; |
118 | namespace mie = mi::evdev; |
119 | using namespace std::literals::chrono_literals; |
120 | |
121 | -mie::LibInputDevice::LibInputDevice(std::shared_ptr<mi::InputReport> const& report, LibInputDevicePtr dev) |
122 | - : report{report}, pointer_pos{0, 0}, button_state{0} |
123 | +mie::LibInputDevice::LibInputDevice(std::shared_ptr<mi::InputReport> const& report, |
124 | + LibInputDevicePtr dev, |
125 | + std::shared_ptr<mir::time::AlarmFactory> const& alarm_factory, |
126 | + std::shared_ptr<mir::time::Clock> const& clock) |
127 | + : report{report}, |
128 | + repeater{alarm_factory, [this](auto code) { this->handle_repeat(code); }}, |
129 | + clock{clock}, |
130 | + pointer_pos{0, 0}, |
131 | + button_state{0} |
132 | { |
133 | add_device_of_group(std::move(dev)); |
134 | } |
135 | @@ -135,6 +141,11 @@ |
136 | auto const code = libinput_event_keyboard_get_key(keyboard); |
137 | report->received_event_from_kernel(time.count(), EV_KEY, code, action); |
138 | |
139 | + if (action == mir_keyboard_action_down) |
140 | + repeater.press(code); |
141 | + else |
142 | + repeater.release(code); |
143 | + |
144 | return builder->key_event(time, action, xkb_keysym_t{0}, code); |
145 | } |
146 | |
147 | @@ -476,3 +487,32 @@ |
148 | LIBINPUT_CONFIG_MIDDLE_EMULATION_ENABLED : |
149 | LIBINPUT_CONFIG_MIDDLE_EMULATION_DISABLED); |
150 | } |
151 | + |
152 | +mir::optional_value<mi::KeyboardSettings> mie::LibInputDevice::get_keyboard_settings() const |
153 | +{ |
154 | + if (!contains(info.capabilities, mi::DeviceCapability::keyboard)) |
155 | + return {}; |
156 | + mi::KeyboardSettings settings; |
157 | + |
158 | + settings.repeat_enabled = repeater.enabled(); |
159 | + settings.repeat_delay = repeater.delay(); |
160 | + settings.repeat_interval = repeater.interval(); |
161 | + return settings; |
162 | +} |
163 | + |
164 | +void mie::LibInputDevice::apply_settings(mi::KeyboardSettings const& settings) |
165 | +{ |
166 | + if (!contains(info.capabilities, mi::DeviceCapability::keyboard)) |
167 | + return; |
168 | + |
169 | + if (settings.repeat_enabled) |
170 | + repeater.enable(settings.repeat_delay, settings.repeat_interval); |
171 | + else |
172 | + repeater.disable(); |
173 | +} |
174 | + |
175 | +void mie::LibInputDevice::handle_repeat(int32_t code) |
176 | +{ |
177 | + auto const event_time = clock->now().time_since_epoch(); |
178 | + sink->handle_input(*builder->key_event(event_time, mir_keyboard_action_repeat, 0, code)); |
179 | +} |
180 | |
181 | === modified file 'src/platforms/evdev/libinput_device.h' |
182 | --- src/platforms/evdev/libinput_device.h 2016-03-23 06:39:56 +0000 |
183 | +++ src/platforms/evdev/libinput_device.h 2016-03-31 19:18:58 +0000 |
184 | @@ -21,6 +21,7 @@ |
185 | |
186 | #include "libinput_ptr.h" |
187 | #include "libinput_device_ptr.h" |
188 | +#include "key_repeater.h" |
189 | |
190 | #include "mir/input/event_builder.h" |
191 | #include "mir/input/input_device.h" |
192 | @@ -38,18 +39,23 @@ |
193 | |
194 | namespace mir |
195 | { |
196 | +namespace time |
197 | +{ |
198 | +class Clock; |
199 | +class AlarmFactory; |
200 | +} |
201 | namespace input |
202 | { |
203 | class InputReport; |
204 | namespace evdev |
205 | { |
206 | -struct PointerState; |
207 | -struct KeyboardState; |
208 | |
209 | class LibInputDevice : public input::InputDevice |
210 | { |
211 | public: |
212 | - LibInputDevice(std::shared_ptr<InputReport> const& report, LibInputDevicePtr dev); |
213 | + LibInputDevice(std::shared_ptr<InputReport> const& report, LibInputDevicePtr dev, |
214 | + std::shared_ptr<mir::time::AlarmFactory> const& alarm_factory, |
215 | + std::shared_ptr<mir::time::Clock> const& clock); |
216 | ~LibInputDevice(); |
217 | void start(InputSink* sink, EventBuilder* builder) override; |
218 | void stop() override; |
219 | @@ -58,6 +64,8 @@ |
220 | void apply_settings(PointerSettings const&) override; |
221 | optional_value<TouchpadSettings> get_touchpad_settings() const override; |
222 | void apply_settings(TouchpadSettings const&) override; |
223 | + optional_value<KeyboardSettings> get_keyboard_settings() const override; |
224 | + void apply_settings(KeyboardSettings const&) override; |
225 | |
226 | void process_event(libinput_event* event); |
227 | ::libinput_device* device() const; |
228 | @@ -75,10 +83,11 @@ |
229 | void handle_touch_motion(libinput_event_touch* touch); |
230 | void update_device_info(); |
231 | |
232 | - std::shared_ptr<InputReport> report; |
233 | + std::shared_ptr<InputReport> const report; |
234 | + KeyRepeater repeater; |
235 | + std::shared_ptr<mir::time::Clock> const clock; |
236 | std::shared_ptr<::libinput> lib; |
237 | std::vector<LibInputDevicePtr> devices; |
238 | - std::shared_ptr<dispatch::Dispatchable> dispatchable_fd; |
239 | |
240 | InputSink* sink{nullptr}; |
241 | EventBuilder* builder{nullptr}; |
242 | @@ -98,6 +107,7 @@ |
243 | std::map<MirTouchId,ContactData> last_seen_properties; |
244 | |
245 | void update_contact_data(ContactData &data, MirTouchAction action, libinput_event_touch* touch); |
246 | + void handle_repeat(int32_t code); |
247 | }; |
248 | } |
249 | } |
250 | |
251 | === modified file 'src/platforms/evdev/platform.cpp' |
252 | --- src/platforms/evdev/platform.cpp 2016-03-23 06:39:56 +0000 |
253 | +++ src/platforms/evdev/platform.cpp 2016-03-31 19:18:58 +0000 |
254 | @@ -22,7 +22,10 @@ |
255 | #include "mir/udev/wrapper.h" |
256 | #include "mir/dispatch/dispatchable.h" |
257 | #include "mir/dispatch/readable_fd.h" |
258 | +#include "mir/dispatch/alarm_factory.h" |
259 | #include "mir/dispatch/multiplexing_dispatchable.h" |
260 | +#include "mir/time/steady_clock.h" |
261 | +#include "mir/time/steady_timer_fd.h" |
262 | #include "mir/module_properties.h" |
263 | #include "mir/assert_module_entry_point.h" |
264 | |
265 | @@ -43,6 +46,7 @@ |
266 | |
267 | namespace mi = mir::input; |
268 | namespace md = mir::dispatch; |
269 | +namespace mt = mir::time; |
270 | namespace mu = mir::udev; |
271 | namespace mie = mi::evdev; |
272 | |
273 | @@ -68,12 +72,14 @@ |
274 | } // namespace |
275 | |
276 | mie::Platform::Platform(std::shared_ptr<InputDeviceRegistry> const& registry, |
277 | - std::shared_ptr<InputReport> const& report, |
278 | - std::unique_ptr<udev::Context>&& udev_context) : |
279 | - report(report), |
280 | - udev_context(std::move(udev_context)), |
281 | - input_device_registry(registry), |
282 | - platform_dispatchable{std::make_shared<md::MultiplexingDispatchable>()} |
283 | + std::shared_ptr<InputReport> const& report, |
284 | + std::unique_ptr<udev::Context>&& udev_context) |
285 | + : report(report), |
286 | + udev_context(std::move(udev_context)), |
287 | + input_device_registry(registry), |
288 | + platform_dispatchable{std::make_shared<md::MultiplexingDispatchable>()}, |
289 | + clock{std::make_shared<mt::SteadyClock>()}, |
290 | + alarm_factory{std::make_shared<md::AlarmFactory>(clock, std::make_shared<mt::SteadyTimerFd>())} |
291 | { |
292 | } |
293 | |
294 | @@ -91,6 +97,7 @@ |
295 | Fd{IntOwnedFd{libinput_get_fd(lib.get())}}, [this]{process_input_events();} |
296 | ); |
297 | platform_dispatchable->add_watch(libinput_dispatchable); |
298 | + platform_dispatchable->add_watch(alarm_factory); |
299 | } |
300 | |
301 | void mie::Platform::process_input_events() |
302 | @@ -145,7 +152,7 @@ |
303 | |
304 | try |
305 | { |
306 | - devices.emplace_back(std::make_shared<mie::LibInputDevice>(report, move(device_ptr))); |
307 | + devices.emplace_back(std::make_shared<mie::LibInputDevice>(report, move(device_ptr), alarm_factory, clock)); |
308 | |
309 | input_device_registry->add_device(devices.back()); |
310 | |
311 | @@ -186,6 +193,7 @@ |
312 | |
313 | void mie::Platform::stop() |
314 | { |
315 | + platform_dispatchable->remove_watch(alarm_factory); |
316 | platform_dispatchable->remove_watch(libinput_dispatchable); |
317 | while (!devices.empty()) |
318 | { |
319 | |
320 | === modified file 'src/platforms/evdev/platform.h' |
321 | --- src/platforms/evdev/platform.h 2016-03-23 06:39:56 +0000 |
322 | +++ src/platforms/evdev/platform.h 2016-03-31 19:18:58 +0000 |
323 | @@ -37,10 +37,15 @@ |
324 | class Monitor; |
325 | class Context; |
326 | } |
327 | +namespace time |
328 | +{ |
329 | +class Clock; |
330 | +} |
331 | namespace dispatch |
332 | { |
333 | class MultiplexingDispatchable; |
334 | class ReadableFd; |
335 | +class AlarmFactory; |
336 | } |
337 | namespace input |
338 | { |
339 | @@ -73,6 +78,8 @@ |
340 | std::shared_ptr<udev::Context> const udev_context; |
341 | std::shared_ptr<InputDeviceRegistry> const input_device_registry; |
342 | std::shared_ptr<dispatch::MultiplexingDispatchable> const platform_dispatchable; |
343 | + std::shared_ptr<time::Clock> const clock; |
344 | + std::shared_ptr<dispatch::AlarmFactory> const alarm_factory; |
345 | std::shared_ptr<::libinput> lib; |
346 | std::shared_ptr<dispatch::ReadableFd> libinput_dispatchable; |
347 | |
348 | |
349 | === modified file 'src/platforms/mesa/server/x11/input/input_device.cpp' |
350 | --- src/platforms/mesa/server/x11/input/input_device.cpp 2016-03-23 06:39:56 +0000 |
351 | +++ src/platforms/mesa/server/x11/input/input_device.cpp 2016-03-31 19:18:58 +0000 |
352 | @@ -20,13 +20,16 @@ |
353 | |
354 | #include "mir/input/pointer_settings.h" |
355 | #include "mir/input/touchpad_settings.h" |
356 | +#include "mir/input/keyboard_settings.h" |
357 | #include "mir/input/input_device_info.h" |
358 | #include "mir/input/device_capability.h" |
359 | #include "mir/input/event_builder.h" |
360 | #include "mir/input/input_sink.h" |
361 | |
362 | +#include "mir/raii.h" |
363 | + |
364 | #include <X11/Xlib.h> |
365 | -#include <iostream> |
366 | +#include <X11/XKBlib.h> |
367 | |
368 | namespace mi = mir::input; |
369 | namespace geom = mir::geometry; |
370 | @@ -69,8 +72,8 @@ |
371 | |
372 | } |
373 | |
374 | -mix::XInputDevice::XInputDevice(InputDeviceInfo const& device_info) |
375 | - : info(device_info) |
376 | +mix::XInputDevice::XInputDevice(InputDeviceInfo const& device_info, std::shared_ptr<::Display> const& display) |
377 | + : display{display}, info(device_info) |
378 | { |
379 | } |
380 | |
381 | @@ -210,3 +213,49 @@ |
382 | ) |
383 | ); |
384 | } |
385 | + |
386 | +void mix::XInputDevice::apply_settings(mi::KeyboardSettings const& settings) |
387 | +{ |
388 | + if (!contains(info.capabilities, mi::DeviceCapability::keyboard)) |
389 | + return; |
390 | + |
391 | + XKeyboardControl repeat_enabled; |
392 | + repeat_enabled.auto_repeat_mode = settings.repeat_enabled; |
393 | + XChangeKeyboardControl(display.get(), KBAutoRepeatMode, &repeat_enabled); |
394 | + |
395 | + int xkbopcode, xkbevent, xkberror; |
396 | + int xkbmajor = XkbMajorVersion, xkbminor = XkbMinorVersion; |
397 | + if (XkbQueryExtension(display.get(), &xkbopcode, &xkbevent, &xkberror, &xkbmajor, &xkbminor)) |
398 | + { |
399 | + auto xkb = raii::deleter_for(XkbAllocKeyboard(), [](XkbDescPtr ptr){XkbFreeKeyboard(ptr, 0, True);}); |
400 | + |
401 | + XkbGetControls(display.get(), XkbRepeatKeysMask, xkb.get()); |
402 | + xkb->ctrls->repeat_delay = settings.repeat_delay.count(); |
403 | + xkb->ctrls->repeat_interval = settings.repeat_interval.count(); |
404 | + XkbSetControls(display.get(), XkbRepeatKeysMask, xkb.get()); |
405 | + } |
406 | +} |
407 | + |
408 | +mir::optional_value<mi::KeyboardSettings> mix::XInputDevice::get_keyboard_settings() const |
409 | +{ |
410 | + if (!contains(info.capabilities, mi::DeviceCapability::keyboard)) |
411 | + return {}; |
412 | + |
413 | + KeyboardSettings settings; |
414 | + XKeyboardState repeat_enabled; |
415 | + XGetKeyboardControl(display.get(), &repeat_enabled); |
416 | + settings.repeat_enabled = repeat_enabled.global_auto_repeat; |
417 | + |
418 | + int xkbopcode, xkbevent, xkberror; |
419 | + int xkbmajor = XkbMajorVersion, xkbminor = XkbMinorVersion; |
420 | + if (XkbQueryExtension(display.get(), &xkbopcode, &xkbevent, &xkberror, &xkbmajor, &xkbminor)) |
421 | + { |
422 | + auto xkb = raii::deleter_for(XkbAllocKeyboard(), [](XkbDescPtr ptr){ XkbFreeKeyboard(ptr, 0, True);}); |
423 | + |
424 | + XkbGetControls(display.get(), XkbRepeatKeysMask, xkb.get()); |
425 | + settings.repeat_delay = std::chrono::milliseconds{xkb->ctrls->repeat_delay}; |
426 | + settings.repeat_interval = std::chrono::milliseconds{xkb->ctrls->repeat_interval}; |
427 | + } |
428 | + |
429 | + return settings; |
430 | +} |
431 | |
432 | === modified file 'src/platforms/mesa/server/x11/input/input_device.h' |
433 | --- src/platforms/mesa/server/x11/input/input_device.h 2016-03-23 06:39:56 +0000 |
434 | +++ src/platforms/mesa/server/x11/input/input_device.h 2016-03-31 19:18:58 +0000 |
435 | @@ -26,6 +26,7 @@ |
436 | #include "mir/geometry/displacement.h" |
437 | #include "mir/optional_value.h" |
438 | |
439 | +#include <X11/Xlib.h> |
440 | #include <chrono> |
441 | |
442 | namespace mir |
443 | @@ -39,7 +40,7 @@ |
444 | class XInputDevice : public input::InputDevice |
445 | { |
446 | public: |
447 | - XInputDevice(InputDeviceInfo const& info); |
448 | + XInputDevice(InputDeviceInfo const& info, std::shared_ptr<::Display> const& display); |
449 | |
450 | std::shared_ptr<dispatch::Dispatchable> dispatchable(); |
451 | void start(InputSink* destination, EventBuilder* builder) override; |
452 | @@ -50,6 +51,8 @@ |
453 | void apply_settings(PointerSettings const& settings) override; |
454 | optional_value<TouchpadSettings> get_touchpad_settings() const override; |
455 | void apply_settings(TouchpadSettings const& settings) override; |
456 | + optional_value<KeyboardSettings> get_keyboard_settings() const override; |
457 | + void apply_settings(KeyboardSettings const& settings) override; |
458 | |
459 | bool started() const; |
460 | void key_press(std::chrono::nanoseconds event_time, xkb_keysym_t key_sym, int32_t key_code); |
461 | @@ -60,6 +63,7 @@ |
462 | void pointer_motion(std::chrono::nanoseconds event_time, mir::geometry::Point const& pos, mir::geometry::Displacement scroll); |
463 | |
464 | private: |
465 | + std::shared_ptr<::Display> const display; |
466 | MirPointerButtons button_state{0}; |
467 | InputSink* sink{nullptr}; |
468 | EventBuilder* builder{nullptr}; |
469 | |
470 | === modified file 'src/platforms/mesa/server/x11/input/input_platform.cpp' |
471 | --- src/platforms/mesa/server/x11/input/input_platform.cpp 2016-03-23 06:39:56 +0000 |
472 | +++ src/platforms/mesa/server/x11/input/input_platform.cpp 2016-03-31 19:18:58 +0000 |
473 | @@ -46,18 +46,15 @@ |
474 | namespace mix = mi::X; |
475 | |
476 | mix::XInputPlatform::XInputPlatform(std::shared_ptr<mi::InputDeviceRegistry> const& input_device_registry, |
477 | - std::shared_ptr<::Display> const& conn) : |
478 | - x11_connection{conn}, |
479 | - xcon_dispatchable(std::make_shared<md::ReadableFd>( |
480 | - mir::Fd{mir::IntOwnedFd{XConnectionNumber(conn.get())}}, [this]() |
481 | - { |
482 | - process_input_event(); |
483 | - })), |
484 | - registry(input_device_registry), |
485 | - core_keyboard(std::make_shared<mix::XInputDevice>( |
486 | - mi::InputDeviceInfo{"x11-keyboard-device", "x11-key-dev-1", mi::DeviceCapability::keyboard})), |
487 | - core_pointer(std::make_shared<mix::XInputDevice>( |
488 | - mi::InputDeviceInfo{"x11-mouse-device", "x11-mouse-dev-1", mi::DeviceCapability::pointer})) |
489 | + std::shared_ptr<::Display> const& conn) |
490 | + : x11_connection{conn}, |
491 | + xcon_dispatchable(std::make_shared<md::ReadableFd>(mir::Fd{mir::IntOwnedFd{XConnectionNumber(conn.get())}}, |
492 | + [this]() { process_input_event(); })), |
493 | + registry(input_device_registry), |
494 | + core_keyboard(std::make_shared<mix::XInputDevice>( |
495 | + mi::InputDeviceInfo{"x11-keyboard-device", "x11-key-dev-1", mi::DeviceCapability::keyboard}, conn)), |
496 | + core_pointer(std::make_shared<mix::XInputDevice>( |
497 | + mi::InputDeviceInfo{"x11-mouse-device", "x11-mouse-dev-1", mi::DeviceCapability::pointer}, conn)) |
498 | { |
499 | } |
500 | |
501 | |
502 | === modified file 'src/server/input/CMakeLists.txt' |
503 | --- src/server/input/CMakeLists.txt 2016-03-23 06:39:56 +0000 |
504 | +++ src/server/input/CMakeLists.txt 2016-03-31 19:18:58 +0000 |
505 | @@ -16,7 +16,6 @@ |
506 | event_filter_chain_dispatcher.cpp |
507 | input_modifier_utils.cpp |
508 | input_probe.cpp |
509 | - key_repeat_dispatcher.cpp |
510 | null_input_channel_factory.cpp |
511 | null_input_dispatcher.cpp |
512 | seat_input_device_tracker.cpp |
513 | |
514 | === modified file 'src/server/input/default_configuration.cpp' |
515 | --- src/server/input/default_configuration.cpp 2016-03-23 06:39:56 +0000 |
516 | +++ src/server/input/default_configuration.cpp 2016-03-31 19:18:58 +0000 |
517 | @@ -20,7 +20,6 @@ |
518 | |
519 | #include "android/input_sender.h" |
520 | #include "android/input_channel_factory.h" |
521 | -#include "key_repeat_dispatcher.h" |
522 | #include "display_input_region.h" |
523 | #include "event_filter_chain_dispatcher.h" |
524 | #include "cursor_controller.h" |
525 | @@ -143,15 +142,7 @@ |
526 | return input_dispatcher( |
527 | [this]() |
528 | { |
529 | - std::chrono::milliseconds const key_repeat_timeout{500}; |
530 | - std::chrono::milliseconds const key_repeat_delay{50}; |
531 | - |
532 | - auto const options = the_options(); |
533 | - auto enable_repeat = options->get<bool>(options::enable_key_repeat_opt); |
534 | - |
535 | - return std::make_shared<mi::KeyRepeatDispatcher>( |
536 | - the_event_filter_chain_dispatcher(), the_main_loop(), the_cookie_authority(), |
537 | - enable_repeat, key_repeat_timeout, key_repeat_delay); |
538 | + return the_event_filter_chain_dispatcher(); |
539 | }); |
540 | } |
541 | |
542 | @@ -297,18 +288,13 @@ |
543 | return default_input_device_hub( |
544 | [this]() |
545 | { |
546 | - auto input_dispatcher = the_input_dispatcher(); |
547 | - auto key_repeater = std::dynamic_pointer_cast<mi::KeyRepeatDispatcher>(input_dispatcher); |
548 | - auto hub = std::make_shared<mi::DefaultInputDeviceHub>( |
549 | + return std::make_shared<mi::DefaultInputDeviceHub>( |
550 | the_global_event_sink(), |
551 | the_seat(), |
552 | the_input_reading_multiplexer(), |
553 | the_main_loop(), |
554 | - the_cookie_authority()); |
555 | - |
556 | - if (key_repeater) |
557 | - key_repeater->set_input_device_hub(hub); |
558 | - return hub; |
559 | + the_cookie_authority(), |
560 | + the_options()->get<bool>(options::enable_key_repeat_opt)); |
561 | }); |
562 | } |
563 | |
564 | @@ -324,18 +310,13 @@ |
565 | return default_input_device_hub( |
566 | [this]() |
567 | { |
568 | - auto input_dispatcher = the_input_dispatcher(); |
569 | - auto key_repeater = std::dynamic_pointer_cast<mi::KeyRepeatDispatcher>(input_dispatcher); |
570 | - auto hub = std::make_shared<mi::DefaultInputDeviceHub>( |
571 | + return std::make_shared<mi::DefaultInputDeviceHub>( |
572 | the_global_event_sink(), |
573 | the_seat(), |
574 | the_input_reading_multiplexer(), |
575 | the_main_loop(), |
576 | - the_cookie_authority()); |
577 | - |
578 | - if (key_repeater) |
579 | - key_repeater->set_input_device_hub(hub); |
580 | - return hub; |
581 | + the_cookie_authority(), |
582 | + the_options()->get<bool>(options::enable_key_repeat_opt)); |
583 | }); |
584 | } |
585 | } |
586 | |
587 | === modified file 'src/server/input/default_input_device_hub.cpp' |
588 | --- src/server/input/default_input_device_hub.cpp 2016-03-23 06:39:56 +0000 |
589 | +++ src/server/input/default_input_device_hub.cpp 2016-03-31 19:18:58 +0000 |
590 | @@ -21,6 +21,7 @@ |
591 | |
592 | #include "mir/input/input_device.h" |
593 | #include "mir/input/input_device_observer.h" |
594 | +#include "mir/input/keyboard_settings.h" |
595 | #include "mir/geometry/point.h" |
596 | #include "mir/dispatch/multiplexing_dispatchable.h" |
597 | #include "mir/dispatch/action_queue.h" |
598 | @@ -43,14 +44,16 @@ |
599 | std::shared_ptr<mi::Seat> const& seat, |
600 | std::shared_ptr<dispatch::MultiplexingDispatchable> const& input_multiplexer, |
601 | std::shared_ptr<mir::ServerActionQueue> const& observer_queue, |
602 | - std::shared_ptr<mir::cookie::Authority> const& cookie_authority) |
603 | + std::shared_ptr<mir::cookie::Authority> const& cookie_authority, |
604 | + bool repeat_enabled) |
605 | : seat{seat}, |
606 | sink{sink}, |
607 | input_dispatchable{input_multiplexer}, |
608 | observer_queue(observer_queue), |
609 | device_queue(std::make_shared<dispatch::ActionQueue>()), |
610 | cookie_authority(cookie_authority), |
611 | - device_id_generator{0} |
612 | + device_id_generator{0}, |
613 | + repeat_enabled{repeat_enabled} |
614 | { |
615 | input_dispatchable->add_watch(device_queue); |
616 | } |
617 | @@ -60,6 +63,13 @@ |
618 | if (!device) |
619 | BOOST_THROW_EXCEPTION(std::invalid_argument("Invalid input device")); |
620 | |
621 | + if (contains(device->get_device_info().capabilities, mir::input::DeviceCapability::keyboard)) |
622 | + { |
623 | + auto key_settings = device->get_keyboard_settings().value(); |
624 | + key_settings.repeat_enabled = repeat_enabled; |
625 | + device->apply_settings(key_settings); |
626 | + } |
627 | + |
628 | auto it = find_if(devices.cbegin(), |
629 | devices.cend(), |
630 | [&device](std::unique_ptr<RegisteredDevice> const& item) |
631 | |
632 | === modified file 'src/server/input/default_input_device_hub.h' |
633 | --- src/server/input/default_input_device_hub.h 2016-03-23 06:39:56 +0000 |
634 | +++ src/server/input/default_input_device_hub.h 2016-03-31 19:18:58 +0000 |
635 | @@ -65,7 +65,8 @@ |
636 | std::shared_ptr<Seat> const& seat, |
637 | std::shared_ptr<dispatch::MultiplexingDispatchable> const& input_multiplexer, |
638 | std::shared_ptr<ServerActionQueue> const& observer_queue, |
639 | - std::shared_ptr<cookie::Authority> const& cookie_authority); |
640 | + std::shared_ptr<cookie::Authority> const& cookie_authority, |
641 | + bool repeat_enabled = true); |
642 | |
643 | // InputDeviceRegistry - calls from mi::Platform |
644 | void add_device(std::shared_ptr<InputDevice> const& device) override; |
645 | @@ -117,6 +118,7 @@ |
646 | std::vector<std::shared_ptr<InputDeviceObserver>> observers; |
647 | |
648 | MirInputDeviceId device_id_generator; |
649 | + bool repeat_enabled; |
650 | }; |
651 | |
652 | } |
653 | |
654 | === removed file 'src/server/input/key_repeat_dispatcher.cpp' |
655 | --- src/server/input/key_repeat_dispatcher.cpp 2016-03-29 23:37:32 +0000 |
656 | +++ src/server/input/key_repeat_dispatcher.cpp 1970-01-01 00:00:00 +0000 |
657 | @@ -1,186 +0,0 @@ |
658 | -/* |
659 | - * Copyright © 2012 Canonical Ltd. |
660 | - * |
661 | - * This program is free software: you can redistribute it and/or modify it |
662 | - * under the terms of the GNU General Public License version 3, |
663 | - * as published by the Free Software Foundation. |
664 | - * |
665 | - * This program is distributed in the hope that it will be useful, |
666 | - * but WITHOUT ANY WARRANTY; without even the implied warranty of |
667 | - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
668 | - * GNU General Public License for more details. |
669 | - * |
670 | - * You should have received a copy of the GNU General Public License |
671 | - * along with this program. If not, see <http://www.gnu.org/licenses/>. |
672 | - * |
673 | - * Authored by: Robert Carr <robert.carr@canonical.com> |
674 | - */ |
675 | - |
676 | -#include "key_repeat_dispatcher.h" |
677 | - |
678 | -#include "mir/input/device.h" |
679 | -#include "mir/input/input_device_hub.h" |
680 | -#include "mir/time/alarm_factory.h" |
681 | -#include "mir/time/alarm.h" |
682 | -#include "mir/events/event_private.h" |
683 | -#include "mir/cookie/authority.h" |
684 | - |
685 | -#include <boost/throw_exception.hpp> |
686 | - |
687 | -#include <algorithm> |
688 | -#include <stdexcept> |
689 | -#include <string.h> |
690 | - |
691 | -namespace mi = mir::input; |
692 | - |
693 | -namespace |
694 | -{ |
695 | -struct DeviceRemovalFilter : mi::InputDeviceObserver |
696 | -{ |
697 | - DeviceRemovalFilter(std::function<void(MirInputDeviceId)> const& on_removal) |
698 | - : on_removal(on_removal) {} |
699 | - |
700 | - void device_added(std::shared_ptr<mi::Device> const&) override |
701 | - { |
702 | - } |
703 | - |
704 | - void device_changed(std::shared_ptr<mi::Device> const&) override |
705 | - { |
706 | - } |
707 | - |
708 | - void device_removed(std::shared_ptr<mi::Device> const& device) override |
709 | - { |
710 | - on_removal(device->id()); |
711 | - } |
712 | - |
713 | - void changes_complete() override |
714 | - { |
715 | - } |
716 | - std::function<void(MirInputDeviceId)> on_removal; |
717 | -}; |
718 | - |
719 | -} |
720 | - |
721 | -mi::KeyRepeatDispatcher::KeyRepeatDispatcher( |
722 | - std::shared_ptr<mi::InputDispatcher> const& next_dispatcher, |
723 | - std::shared_ptr<mir::time::AlarmFactory> const& factory, |
724 | - std::shared_ptr<mir::cookie::Authority> const& cookie_authority, |
725 | - bool repeat_enabled, |
726 | - std::chrono::milliseconds repeat_timeout, |
727 | - std::chrono::milliseconds repeat_delay) |
728 | - : next_dispatcher(next_dispatcher), |
729 | - alarm_factory(factory), |
730 | - cookie_authority(cookie_authority), |
731 | - repeat_enabled(repeat_enabled), |
732 | - repeat_timeout(repeat_timeout), |
733 | - repeat_delay(repeat_delay) |
734 | -{ |
735 | -} |
736 | - |
737 | -void mi::KeyRepeatDispatcher::set_input_device_hub(std::shared_ptr<InputDeviceHub> const& hub) |
738 | -{ |
739 | - hub->add_observer(std::make_shared<DeviceRemovalFilter>( |
740 | - [this](MirInputDeviceId id) |
741 | - { |
742 | - std::unique_lock<std::mutex> lock(repeat_state_mutex); |
743 | - repeat_state_by_device.erase(id); // destructor cancels alarms |
744 | - } |
745 | - )); |
746 | -} |
747 | - |
748 | -mi::KeyRepeatDispatcher::KeyboardState& mi::KeyRepeatDispatcher::ensure_state_for_device_locked(std::lock_guard<std::mutex> const&, MirInputDeviceId id) |
749 | -{ |
750 | - repeat_state_by_device.insert(std::make_pair(id, KeyboardState())); |
751 | - return repeat_state_by_device[id]; |
752 | -} |
753 | - |
754 | -bool mi::KeyRepeatDispatcher::dispatch(MirEvent const& event) |
755 | -{ |
756 | - if (!repeat_enabled) // if we made this mutable we'd need a guard |
757 | - { |
758 | - return next_dispatcher->dispatch(event); |
759 | - } |
760 | - |
761 | - if (mir_event_get_type(&event) == mir_event_type_input) |
762 | - { |
763 | - auto iev = mir_event_get_input_event(&event); |
764 | - if (mir_input_event_get_type(iev) != mir_input_event_type_key) |
765 | - return next_dispatcher->dispatch(event); |
766 | - if (!handle_key_input(mir_input_event_get_device_id(iev), mir_input_event_get_keyboard_event(iev))) |
767 | - return next_dispatcher->dispatch(event); |
768 | - else |
769 | - return true; |
770 | - } |
771 | - return next_dispatcher->dispatch(event); |
772 | -} |
773 | - |
774 | -// Returns true if the original event has been handled, that is ::dispatch should not pass it on. |
775 | -bool mi::KeyRepeatDispatcher::handle_key_input(MirInputDeviceId id, MirKeyboardEvent const* kev) |
776 | -{ |
777 | - std::lock_guard<std::mutex> lg(repeat_state_mutex); |
778 | - auto& device_state = ensure_state_for_device_locked(lg, id); |
779 | - |
780 | - auto scan_code = mir_keyboard_event_scan_code(kev); |
781 | - |
782 | - switch (mir_keyboard_event_action(kev)) |
783 | - { |
784 | - case mir_keyboard_action_up: |
785 | - { |
786 | - auto it = device_state.repeat_alarms_by_scancode.find(scan_code); |
787 | - if (it == device_state.repeat_alarms_by_scancode.end()) |
788 | - { |
789 | - return false; |
790 | - } |
791 | - device_state.repeat_alarms_by_scancode.erase(it); |
792 | - break; |
793 | - } |
794 | - case mir_keyboard_action_down: |
795 | - { |
796 | - MirKeyboardEvent new_kev = *kev; |
797 | - new_kev.action = mir_keyboard_action_repeat; |
798 | - |
799 | - auto it = device_state.repeat_alarms_by_scancode.find(scan_code); |
800 | - if (it != device_state.repeat_alarms_by_scancode.end()) |
801 | - { |
802 | - // When we receive a duplicated down we just replace the action |
803 | - next_dispatcher->dispatch(new_kev); |
804 | - return true; |
805 | - } |
806 | - auto& capture_alarm = device_state.repeat_alarms_by_scancode[scan_code]; |
807 | - std::shared_ptr<mir::time::Alarm> alarm = alarm_factory->create_alarm([this, &capture_alarm, new_kev]() mutable |
808 | - { |
809 | - std::lock_guard<std::mutex> lg(repeat_state_mutex); |
810 | - |
811 | - new_kev.event_time = std::chrono::steady_clock::now().time_since_epoch(); |
812 | - auto const cookie = cookie_authority->make_cookie(new_kev.event_time.count()); |
813 | - auto const serialized_cookie = cookie->serialize(); |
814 | - std::copy_n(std::begin(serialized_cookie), new_kev.cookie.size(), std::begin(new_kev.cookie)); |
815 | - next_dispatcher->dispatch(new_kev); |
816 | - |
817 | - capture_alarm->reschedule_in(repeat_delay); |
818 | - }); |
819 | - alarm->reschedule_in(repeat_timeout); |
820 | - device_state.repeat_alarms_by_scancode[scan_code] = {alarm}; |
821 | - } |
822 | - case mir_keyboard_action_repeat: |
823 | - // Should we consume existing repeats? |
824 | - break; |
825 | - default: |
826 | - BOOST_THROW_EXCEPTION(std::logic_error("Unexpected key event action")); |
827 | - } |
828 | - return false; |
829 | -} |
830 | - |
831 | -void mi::KeyRepeatDispatcher::start() |
832 | -{ |
833 | - next_dispatcher->start(); |
834 | -} |
835 | - |
836 | -void mi::KeyRepeatDispatcher::stop() |
837 | -{ |
838 | - std::lock_guard<std::mutex> lg(repeat_state_mutex); |
839 | - |
840 | - repeat_state_by_device.clear(); |
841 | - |
842 | - next_dispatcher->stop(); |
843 | -} |
844 | |
845 | === removed file 'src/server/input/key_repeat_dispatcher.h' |
846 | --- src/server/input/key_repeat_dispatcher.h 2016-03-23 06:39:56 +0000 |
847 | +++ src/server/input/key_repeat_dispatcher.h 1970-01-01 00:00:00 +0000 |
848 | @@ -1,84 +0,0 @@ |
849 | -/* |
850 | - * Copyright © 2015-2016 Canonical Ltd. |
851 | - * |
852 | - * This program is free software: you can redistribute it and/or modify it |
853 | - * under the terms of the GNU General Public License version 3, |
854 | - * as published by the Free Software Foundation. |
855 | - * |
856 | - * This program is distributed in the hope that it will be useful, |
857 | - * but WITHOUT ANY WARRANTY; without even the implied warranty of |
858 | - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
859 | - * GNU General Public License for more details. |
860 | - * |
861 | - * You should have received a copy of the GNU General Public License |
862 | - * along with this program. If not, see <http://www.gnu.org/licenses/>. |
863 | - * |
864 | - * Authored by: Robert Carr <robert.carr@canonical.com> |
865 | - */ |
866 | - |
867 | -#ifndef MIR_INPUT_KEY_REPEAT_DISPATCHER_H_ |
868 | -#define MIR_INPUT_KEY_REPEAT_DISPATCHER_H_ |
869 | - |
870 | -#include "mir/input/input_dispatcher.h" |
871 | -#include "mir/input/input_device_observer.h" |
872 | - |
873 | -#include <memory> |
874 | -#include <chrono> |
875 | -#include <mutex> |
876 | -#include <unordered_map> |
877 | - |
878 | -namespace mir |
879 | -{ |
880 | -namespace cookie |
881 | -{ |
882 | -class Authority; |
883 | -} |
884 | -namespace time |
885 | -{ |
886 | -class AlarmFactory; |
887 | -class Alarm; |
888 | -} |
889 | -namespace input |
890 | -{ |
891 | -class InputDeviceHub; |
892 | -class KeyRepeatDispatcher : public InputDispatcher |
893 | -{ |
894 | -public: |
895 | - KeyRepeatDispatcher(std::shared_ptr<InputDispatcher> const& next_dispatcher, |
896 | - std::shared_ptr<time::AlarmFactory> const& factory, |
897 | - std::shared_ptr<cookie::Authority> const& cookie_authority, |
898 | - bool repeat_enabled, |
899 | - std::chrono::milliseconds repeat_timeout, /* timeout before sending first repeat */ |
900 | - std::chrono::milliseconds repeat_delay /* delay between repeated keys */); |
901 | - |
902 | - // InputDispatcher |
903 | - bool dispatch(MirEvent const& event) override; |
904 | - void start() override; |
905 | - void stop() override; |
906 | - |
907 | - void set_input_device_hub(std::shared_ptr<InputDeviceHub> const& hub); |
908 | - |
909 | -private: |
910 | - std::mutex repeat_state_mutex; |
911 | - |
912 | - std::shared_ptr<InputDispatcher> const next_dispatcher; |
913 | - std::shared_ptr<time::AlarmFactory> const alarm_factory; |
914 | - std::shared_ptr<cookie::Authority> const cookie_authority; |
915 | - bool const repeat_enabled; |
916 | - std::chrono::milliseconds repeat_timeout; |
917 | - std::chrono::milliseconds repeat_delay; |
918 | - |
919 | - struct KeyboardState |
920 | - { |
921 | - std::unordered_map<int, std::shared_ptr<mir::time::Alarm>> repeat_alarms_by_scancode; |
922 | - }; |
923 | - std::unordered_map<MirInputDeviceId, KeyboardState> repeat_state_by_device; |
924 | - KeyboardState& ensure_state_for_device_locked(std::lock_guard<std::mutex> const&, MirInputDeviceId id); |
925 | - |
926 | - bool handle_key_input(MirInputDeviceId id, MirKeyboardEvent const* ev); |
927 | -}; |
928 | - |
929 | -} |
930 | -} |
931 | - |
932 | -#endif // MIR_INPUT_KEY_REPEAT_DISPATCHER_H_ |
933 | |
934 | === modified file 'tests/include/mir/test/doubles/mock_input_device.h' |
935 | --- tests/include/mir/test/doubles/mock_input_device.h 2015-12-18 21:07:54 +0000 |
936 | +++ tests/include/mir/test/doubles/mock_input_device.h 2016-03-31 19:18:58 +0000 |
937 | @@ -23,6 +23,7 @@ |
938 | #include "mir/input/input_device_info.h" // needed for fake device setup |
939 | #include "mir/input/pointer_settings.h" |
940 | #include "mir/input/touchpad_settings.h" |
941 | +#include "mir/input/keyboard_settings.h" |
942 | |
943 | #include <gmock/gmock.h> |
944 | |
945 | @@ -44,6 +45,8 @@ |
946 | MOCK_METHOD1(apply_settings, void(input::PointerSettings const&)); |
947 | MOCK_CONST_METHOD0(get_touchpad_settings, mir::optional_value<input::TouchpadSettings>()); |
948 | MOCK_METHOD1(apply_settings, void(input::TouchpadSettings const&)); |
949 | + MOCK_CONST_METHOD0(get_keyboard_settings, mir::optional_value<input::KeyboardSettings>()); |
950 | + MOCK_METHOD1(apply_settings, void(input::KeyboardSettings const&)); |
951 | }; |
952 | } |
953 | } |
954 | |
955 | === modified file 'tests/include/mir/test/doubles/mock_x11.h' |
956 | --- tests/include/mir/test/doubles/mock_x11.h 2016-03-23 06:39:56 +0000 |
957 | +++ tests/include/mir/test/doubles/mock_x11.h 2016-03-31 19:18:58 +0000 |
958 | @@ -22,6 +22,7 @@ |
959 | #include <gmock/gmock.h> |
960 | |
961 | #include <X11/Xlib.h> |
962 | +#include <X11/XKBlib.h> |
963 | #include <X11/Xutil.h> |
964 | |
965 | namespace mir |
966 | @@ -81,6 +82,13 @@ |
967 | MOCK_METHOD1(XSetErrorHandler, XErrorHandler(XErrorHandler)); |
968 | MOCK_METHOD0(XInitThreads, Status()); |
969 | MOCK_METHOD3(XSetWMHints, int(Display*, Window, XWMHints*)); |
970 | + MOCK_METHOD3(XChangeKeyboardControl, int(Display*, unsigned long, XKeyboardControl*)); |
971 | + MOCK_METHOD2(XGetKeyboardControl, int(Display*, XKeyboardState*)); |
972 | + MOCK_METHOD6(XkbQueryExtension, Bool(Display*, int*, int*, int*, int*, int*)); |
973 | + MOCK_METHOD3(XkbFreeKeyboard, void(XkbDescPtr, unsigned int, Bool)); |
974 | + MOCK_METHOD0(XkbAllocKeyboard, XkbDescPtr()); |
975 | + MOCK_METHOD3(XkbGetControls, Status(Display*, unsigned long, XkbDescPtr)); |
976 | + MOCK_METHOD3(XkbSetControls, Bool(Display*, unsigned long, XkbDescPtr)); |
977 | |
978 | FakeX11Resources fake_x11; |
979 | }; |
980 | |
981 | === modified file 'tests/include/mir_test_framework/stub_input_platform.h' |
982 | --- tests/include/mir_test_framework/stub_input_platform.h 2016-01-29 08:18:22 +0000 |
983 | +++ tests/include/mir_test_framework/stub_input_platform.h 2016-03-31 19:18:58 +0000 |
984 | @@ -26,8 +26,16 @@ |
985 | |
986 | namespace mir |
987 | { |
988 | +namespace time |
989 | +{ |
990 | +class AlarmFactory; |
991 | +class Clock; |
992 | +class SteadyTimerFd; |
993 | +class SteadyClock; |
994 | +} |
995 | namespace dispatch |
996 | { |
997 | +class AlarmFactory; |
998 | class ActionQueue; |
999 | class MultiplexingDispatchable; |
1000 | } |
1001 | @@ -53,6 +61,8 @@ |
1002 | static void remove(std::shared_ptr<mir::input::InputDevice> const& dev); |
1003 | static void register_dispatchable(std::shared_ptr<mir::dispatch::Dispatchable> const& queue); |
1004 | static void unregister_dispatchable(std::shared_ptr<mir::dispatch::Dispatchable> const& queue); |
1005 | + static std::shared_ptr<mir::time::AlarmFactory> get_alarm_factory(); |
1006 | + static std::shared_ptr<mir::time::Clock> get_clock(); |
1007 | |
1008 | private: |
1009 | std::shared_ptr<mir::dispatch::MultiplexingDispatchable> const platform_dispatchable; |
1010 | @@ -61,6 +71,11 @@ |
1011 | static std::atomic<StubInputPlatform*> stub_input_platform; |
1012 | static std::vector<std::weak_ptr<mir::input::InputDevice>> device_store; |
1013 | static std::mutex device_store_guard; |
1014 | + static std::shared_ptr<mir::time::SteadyClock> steady_clock; |
1015 | + static std::shared_ptr<mir::time::SteadyTimerFd> steady_timer_fd; |
1016 | + static std::shared_ptr<mir::dispatch::AlarmFactory> alarm_factory; |
1017 | + |
1018 | + |
1019 | }; |
1020 | |
1021 | } |
1022 | |
1023 | === modified file 'tests/mir_test_doubles/mock_input_device.cpp' |
1024 | --- tests/mir_test_doubles/mock_input_device.cpp 2015-12-18 21:07:54 +0000 |
1025 | +++ tests/mir_test_doubles/mock_input_device.cpp 2016-03-31 19:18:58 +0000 |
1026 | @@ -40,4 +40,12 @@ |
1027 | else |
1028 | ON_CALL(*this, get_touchpad_settings()) |
1029 | .WillByDefault(Return(mir::optional_value<input::TouchpadSettings>())); |
1030 | + |
1031 | + if (contains(caps, input::DeviceCapability::keyboard)) |
1032 | + ON_CALL(*this, get_keyboard_settings()) |
1033 | + .WillByDefault(Return(input::KeyboardSettings())); |
1034 | + else |
1035 | + ON_CALL(*this, get_keyboard_settings()) |
1036 | + .WillByDefault(Return(mir::optional_value<input::KeyboardSettings>())); |
1037 | + |
1038 | } |
1039 | |
1040 | === modified file 'tests/mir_test_doubles/mock_x11.cpp' |
1041 | --- tests/mir_test_doubles/mock_x11.cpp 2016-03-23 06:39:56 +0000 |
1042 | +++ tests/mir_test_doubles/mock_x11.cpp 2016-03-31 19:18:58 +0000 |
1043 | @@ -195,3 +195,38 @@ |
1044 | { |
1045 | return global_mock->XPending(display); |
1046 | } |
1047 | + |
1048 | +int XChangeKeyboardControl(Display* display, unsigned long value_mask, XKeyboardControl* control) |
1049 | +{ |
1050 | + return global_mock->XChangeKeyboardControl(display, value_mask, control); |
1051 | +} |
1052 | + |
1053 | +int XGetKeyboardControl(Display* display, XKeyboardState* control) |
1054 | +{ |
1055 | + return global_mock->XGetKeyboardControl(display, control); |
1056 | +} |
1057 | + |
1058 | +Bool XkbQueryExtension(Display* dpy, int* opcode, int* event_base, int* error_base, int* major, int* minor) |
1059 | +{ |
1060 | + return global_mock->XkbQueryExtension(dpy, opcode, event_base, error_base, major, minor); |
1061 | +} |
1062 | + |
1063 | +void XkbFreeKeyboard(XkbDescPtr xkb, unsigned int which, Bool free_desc) |
1064 | +{ |
1065 | + global_mock->XkbFreeKeyboard(xkb, which, free_desc); |
1066 | +} |
1067 | + |
1068 | +XkbDescPtr XkbAllocKeyboard() |
1069 | +{ |
1070 | + return global_mock->XkbAllocKeyboard(); |
1071 | +} |
1072 | + |
1073 | +Status XkbGetControls(Display* dpy, unsigned long which, XkbDescPtr desc) |
1074 | +{ |
1075 | + return global_mock->XkbGetControls(dpy, which, desc); |
1076 | +} |
1077 | + |
1078 | +Bool XkbSetControls(Display* dpy, unsigned long which, XkbDescPtr desc) |
1079 | +{ |
1080 | + return global_mock->XkbSetControls(dpy, which, desc); |
1081 | +} |
1082 | |
1083 | === modified file 'tests/mir_test_framework/fake_input_device_impl.cpp' |
1084 | --- tests/mir_test_framework/fake_input_device_impl.cpp 2016-03-23 06:39:56 +0000 |
1085 | +++ tests/mir_test_framework/fake_input_device_impl.cpp 2016-03-31 19:18:58 +0000 |
1086 | @@ -24,7 +24,9 @@ |
1087 | #include "mir/input/input_sink.h" |
1088 | #include "mir/input/pointer_settings.h" |
1089 | #include "mir/input/touchpad_settings.h" |
1090 | +#include "mir/input/keyboard_settings.h" |
1091 | #include "mir/input/event_builder.h" |
1092 | +#include "mir/time/clock.h" |
1093 | #include "mir/dispatch/action_queue.h" |
1094 | #include "mir/geometry/displacement.h" |
1095 | #include "src/platforms/evdev/button_utils.h" |
1096 | @@ -41,7 +43,9 @@ |
1097 | namespace mtf = mir_test_framework; |
1098 | |
1099 | mtf::FakeInputDeviceImpl::FakeInputDeviceImpl(mi::InputDeviceInfo const& info) |
1100 | - : queue{std::make_shared<md::ActionQueue>()}, device{std::make_shared<InputDevice>(info, queue)} |
1101 | + : queue{std::make_shared<md::ActionQueue>()}, |
1102 | + device{std::make_shared<InputDevice>( |
1103 | + info, queue, mtf::StubInputPlatform::get_clock(), mtf::StubInputPlatform::get_alarm_factory())} |
1104 | { |
1105 | mtf::StubInputPlatform::add(device); |
1106 | } |
1107 | @@ -92,24 +96,31 @@ |
1108 | } |
1109 | |
1110 | mtf::FakeInputDeviceImpl::InputDevice::InputDevice(mi::InputDeviceInfo const& info, |
1111 | - std::shared_ptr<mir::dispatch::Dispatchable> const& dispatchable) |
1112 | - : info(info), queue{dispatchable}, buttons{0} |
1113 | + std::shared_ptr<mir::dispatch::Dispatchable> const& dispatchable, |
1114 | + std::shared_ptr<mir::time::Clock> const& clock, |
1115 | + std::shared_ptr<mir::time::AlarmFactory> const& alarm_factory) |
1116 | + : info(info), queue{dispatchable}, clock{clock}, buttons{0}, repeater{alarm_factory, [this](auto key_code) { |
1117 | + this->handle_repeat(key_code);}} |
1118 | { |
1119 | - // the default setup results in a direct mapping of input velocity to output velocity. |
1120 | - settings.acceleration = mir_pointer_acceleration_none; |
1121 | - settings.cursor_acceleration_bias = 0.0; |
1122 | + // the default setup results in a direct mapping of input velocity to output velocity. |
1123 | + settings.acceleration = mir_pointer_acceleration_none; |
1124 | + settings.cursor_acceleration_bias = 0.0; |
1125 | } |
1126 | |
1127 | void mtf::FakeInputDeviceImpl::InputDevice::synthesize_events(synthesis::KeyParameters const& key_params) |
1128 | { |
1129 | xkb_keysym_t key_code = 0; |
1130 | |
1131 | - auto event_time = std::chrono::duration_cast<std::chrono::nanoseconds>( |
1132 | - std::chrono::steady_clock::now().time_since_epoch()); |
1133 | + auto const event_time = clock->now().time_since_epoch(); |
1134 | |
1135 | auto input_action = |
1136 | (key_params.action == synthesis::EventAction::Down) ? mir_keyboard_action_down : mir_keyboard_action_up; |
1137 | |
1138 | + if (input_action == mir_keyboard_action_down) |
1139 | + repeater.press(key_params.scancode); |
1140 | + else |
1141 | + repeater.release(key_params.scancode); |
1142 | + |
1143 | auto key_event = builder->key_event(event_time, input_action, key_code, key_params.scancode); |
1144 | |
1145 | if (!sink) |
1146 | @@ -119,8 +130,7 @@ |
1147 | |
1148 | void mtf::FakeInputDeviceImpl::InputDevice::synthesize_events(synthesis::ButtonParameters const& button) |
1149 | { |
1150 | - auto event_time = std::chrono::duration_cast<std::chrono::nanoseconds>( |
1151 | - std::chrono::steady_clock::now().time_since_epoch()); |
1152 | + auto const event_time = clock->now().time_since_epoch(); |
1153 | auto action = update_buttons(button.action, mie::to_pointer_button(button.button, settings.handedness)); |
1154 | auto button_event = builder->pointer_event(event_time, |
1155 | action, |
1156 | @@ -154,8 +164,7 @@ |
1157 | if (!sink) |
1158 | BOOST_THROW_EXCEPTION(std::runtime_error("Device is not started.")); |
1159 | |
1160 | - auto event_time = std::chrono::duration_cast<std::chrono::nanoseconds>( |
1161 | - std::chrono::steady_clock::now().time_since_epoch()); |
1162 | + auto const event_time = clock->now().time_since_epoch(); |
1163 | // constant scaling is used here to simplify checking for the |
1164 | // expected results. Default settings of the device lead to no |
1165 | // scaling at all. |
1166 | @@ -179,8 +188,7 @@ |
1167 | if (!sink) |
1168 | BOOST_THROW_EXCEPTION(std::runtime_error("Device is not started.")); |
1169 | |
1170 | - auto event_time = std::chrono::duration_cast<std::chrono::nanoseconds>( |
1171 | - std::chrono::steady_clock::now().time_since_epoch()); |
1172 | + auto const event_time = clock->now().time_since_epoch(); |
1173 | |
1174 | auto touch_event = builder->touch_event(event_time); |
1175 | |
1176 | @@ -247,6 +255,29 @@ |
1177 | // forwards already interpreted events. |
1178 | } |
1179 | |
1180 | +mir::optional_value<mi::KeyboardSettings> mtf::FakeInputDeviceImpl::InputDevice::get_keyboard_settings() const |
1181 | +{ |
1182 | + if (!contains(info.capabilities, mi::DeviceCapability::keyboard)) |
1183 | + return {}; |
1184 | + mi::KeyboardSettings settings; |
1185 | + |
1186 | + settings.repeat_enabled = repeater.enabled(); |
1187 | + settings.repeat_delay = repeater.delay(); |
1188 | + settings.repeat_interval = repeater.interval(); |
1189 | + return settings; |
1190 | +} |
1191 | + |
1192 | +void mtf::FakeInputDeviceImpl::InputDevice::apply_settings(mi::KeyboardSettings const& settings) |
1193 | +{ |
1194 | + if (!contains(info.capabilities, mi::DeviceCapability::keyboard)) |
1195 | + return; |
1196 | + |
1197 | + if (settings.repeat_enabled) |
1198 | + repeater.enable(settings.repeat_delay, settings.repeat_interval); |
1199 | + else |
1200 | + repeater.disable(); |
1201 | +} |
1202 | + |
1203 | void mtf::FakeInputDeviceImpl::InputDevice::map_touch_coordinates(float& x, float& y) |
1204 | { |
1205 | // TODO take orientation of input sink into account? |
1206 | @@ -258,6 +289,15 @@ |
1207 | y = (y - float(FakeInputDevice::minimum_touch_axis_value))*y_scale + area.top_left.y.as_float(); |
1208 | } |
1209 | |
1210 | +void mtf::FakeInputDeviceImpl::InputDevice::handle_repeat(int32_t code) |
1211 | +{ |
1212 | + if (!sink) |
1213 | + BOOST_THROW_EXCEPTION(std::runtime_error("Device is not started.")); |
1214 | + auto const event_time = clock->now().time_since_epoch(); |
1215 | + auto key_event = builder->key_event(event_time, mir_keyboard_action_repeat, 0, code); |
1216 | + sink->handle_input(*key_event); |
1217 | +} |
1218 | + |
1219 | void mtf::FakeInputDeviceImpl::InputDevice::start(mi::InputSink* destination, mi::EventBuilder* event_builder) |
1220 | { |
1221 | sink = destination; |
1222 | |
1223 | === modified file 'tests/mir_test_framework/fake_input_device_impl.h' |
1224 | --- tests/mir_test_framework/fake_input_device_impl.h 2016-03-23 06:39:56 +0000 |
1225 | +++ tests/mir_test_framework/fake_input_device_impl.h 2016-03-31 19:18:58 +0000 |
1226 | @@ -20,6 +20,7 @@ |
1227 | #define MIR_TEST_FRAMEWORK_FAKE_INPUT_DEVICE_IMPL_H_ |
1228 | |
1229 | #include "mir_test_framework/fake_input_device.h" |
1230 | +#include "src/platforms/evdev/key_repeater.h" |
1231 | |
1232 | #include "mir/input/input_device.h" |
1233 | #include "mir/input/pointer_settings.h" |
1234 | @@ -28,6 +29,11 @@ |
1235 | |
1236 | namespace mir |
1237 | { |
1238 | +namespace time |
1239 | +{ |
1240 | +class Clock; |
1241 | +class AlarmFactory; |
1242 | +} |
1243 | namespace dispatch |
1244 | { |
1245 | class ActionQueue; |
1246 | @@ -52,7 +58,10 @@ |
1247 | { |
1248 | public: |
1249 | InputDevice(mir::input::InputDeviceInfo const& info, |
1250 | - std::shared_ptr<mir::dispatch::Dispatchable> const& dispatchable); |
1251 | + std::shared_ptr<mir::dispatch::Dispatchable> const& dispatchable, |
1252 | + std::shared_ptr<mir::time::Clock> const& clock, |
1253 | + std::shared_ptr<mir::time::AlarmFactory> const& alarm_factory |
1254 | + ); |
1255 | |
1256 | void start(mir::input::InputSink* destination, mir::input::EventBuilder* builder) override; |
1257 | void stop() override; |
1258 | @@ -70,19 +79,24 @@ |
1259 | void apply_settings(mir::input::PointerSettings const& settings) override; |
1260 | mir::optional_value<mir::input::TouchpadSettings> get_touchpad_settings() const override; |
1261 | void apply_settings(mir::input::TouchpadSettings const& settings) override; |
1262 | + mir::optional_value<mir::input::KeyboardSettings> get_keyboard_settings() const override; |
1263 | + void apply_settings(mir::input::KeyboardSettings const& settings) override; |
1264 | |
1265 | private: |
1266 | MirPointerAction update_buttons(synthesis::EventAction action, MirPointerButton button); |
1267 | void update_position(int rel_x, int rel_y); |
1268 | void map_touch_coordinates(float& x, float& y); |
1269 | + void handle_repeat(int32_t code); |
1270 | |
1271 | mir::input::InputSink* sink{nullptr}; |
1272 | mir::input::EventBuilder* builder{nullptr}; |
1273 | mir::input::InputDeviceInfo info; |
1274 | std::shared_ptr<mir::dispatch::Dispatchable> const queue; |
1275 | + std::shared_ptr<mir::time::Clock> const clock; |
1276 | mir::geometry::Point pos, scroll; |
1277 | MirPointerButtons buttons; |
1278 | mir::input::PointerSettings settings; |
1279 | + mir::input::evdev::KeyRepeater repeater; |
1280 | }; |
1281 | std::shared_ptr<mir::dispatch::ActionQueue> queue; |
1282 | std::shared_ptr<InputDevice> device; |
1283 | |
1284 | === modified file 'tests/mir_test_framework/stub_input_platform.cpp' |
1285 | --- tests/mir_test_framework/stub_input_platform.cpp 2016-03-23 06:39:56 +0000 |
1286 | +++ tests/mir_test_framework/stub_input_platform.cpp 2016-03-31 19:18:58 +0000 |
1287 | @@ -19,7 +19,10 @@ |
1288 | #include "mir_test_framework/stub_input_platform.h" |
1289 | |
1290 | #include "mir/input/input_device_registry.h" |
1291 | +#include "mir/time/steady_timer_fd.h" |
1292 | +#include "mir/time/steady_clock.h" |
1293 | #include "mir/dispatch/action_queue.h" |
1294 | +#include "mir/dispatch/alarm_factory.h" |
1295 | #include "mir/dispatch/multiplexing_dispatchable.h" |
1296 | #include "mir/module_deleter.h" |
1297 | |
1298 | @@ -27,6 +30,8 @@ |
1299 | |
1300 | namespace mtf = mir_test_framework; |
1301 | namespace mi = mir::input; |
1302 | +namespace md = mir::dispatch; |
1303 | +namespace mt = mir::time; |
1304 | |
1305 | mtf::StubInputPlatform::StubInputPlatform( |
1306 | std::shared_ptr<mi::InputDeviceRegistry> const& input_device_registry) |
1307 | @@ -36,10 +41,12 @@ |
1308 | { |
1309 | stub_input_platform = this; |
1310 | platform_dispatchable->add_watch(platform_queue); |
1311 | + platform_dispatchable->add_watch(alarm_factory); |
1312 | } |
1313 | |
1314 | mtf::StubInputPlatform::~StubInputPlatform() |
1315 | { |
1316 | + platform_dispatchable->remove_watch(alarm_factory); |
1317 | std::lock_guard<decltype(device_store_guard)> lk{device_store_guard}; |
1318 | device_store.clear(); |
1319 | stub_input_platform = nullptr; |
1320 | @@ -128,6 +135,20 @@ |
1321 | input_platform->platform_dispatchable->remove_watch(queue); |
1322 | } |
1323 | |
1324 | +std::shared_ptr<mt::AlarmFactory> mtf::StubInputPlatform::get_alarm_factory() |
1325 | +{ |
1326 | + return alarm_factory; |
1327 | +} |
1328 | + |
1329 | +std::shared_ptr<mt::Clock> mtf::StubInputPlatform::get_clock() |
1330 | +{ |
1331 | + return steady_clock; |
1332 | +} |
1333 | + |
1334 | +std::shared_ptr<mt::SteadyClock> mtf::StubInputPlatform::steady_clock{std::make_shared<mt::SteadyClock>()}; |
1335 | +std::shared_ptr<mt::SteadyTimerFd> mtf::StubInputPlatform::steady_timer_fd{std::make_shared<mt::SteadyTimerFd>()}; |
1336 | +std::shared_ptr<md::AlarmFactory> mtf::StubInputPlatform::alarm_factory{ |
1337 | + std::make_shared<md::AlarmFactory>(mtf::StubInputPlatform::steady_clock, mtf::StubInputPlatform::steady_timer_fd)}; |
1338 | std::atomic<mtf::StubInputPlatform*> mtf::StubInputPlatform::stub_input_platform{nullptr}; |
1339 | std::vector<std::weak_ptr<mir::input::InputDevice>> mtf::StubInputPlatform::device_store; |
1340 | std::mutex mtf::StubInputPlatform::device_store_guard; |
1341 | |
1342 | === modified file 'tests/unit-tests/input/CMakeLists.txt' |
1343 | --- tests/unit-tests/input/CMakeLists.txt 2016-03-31 19:18:58 +0000 |
1344 | +++ tests/unit-tests/input/CMakeLists.txt 2016-03-31 19:18:58 +0000 |
1345 | @@ -14,7 +14,6 @@ |
1346 | ${CMAKE_CURRENT_SOURCE_DIR}/test_default_input_manager.cpp |
1347 | ${CMAKE_CURRENT_SOURCE_DIR}/test_surface_input_dispatcher.cpp |
1348 | ${CMAKE_CURRENT_SOURCE_DIR}/test_seat_input_device_tracker.cpp |
1349 | - ${CMAKE_CURRENT_SOURCE_DIR}/test_key_repeat_dispatcher.cpp |
1350 | ${CMAKE_CURRENT_SOURCE_DIR}/test_key_repeater.cpp |
1351 | ${CMAKE_CURRENT_SOURCE_DIR}/test_validator.cpp |
1352 | ) |
1353 | |
1354 | === modified file 'tests/unit-tests/input/evdev/test_evdev_device_detection.cpp' |
1355 | --- tests/unit-tests/input/evdev/test_evdev_device_detection.cpp 2016-03-23 06:39:56 +0000 |
1356 | +++ tests/unit-tests/input/evdev/test_evdev_device_detection.cpp 2016-03-31 19:18:58 +0000 |
1357 | @@ -22,13 +22,18 @@ |
1358 | #include "src/platforms/evdev/libinput_device.h" |
1359 | #include "src/server/report/null_report_factory.h" |
1360 | |
1361 | +#include "mir/test/doubles/mock_alarm_factory.h" |
1362 | +#include "mir/test/doubles/advanceable_clock.h" |
1363 | #include "mir_test_framework/libinput_environment.h" |
1364 | +#include "mir/test/fake_shared.h" |
1365 | |
1366 | #include <gtest/gtest.h> |
1367 | #include <gmock/gmock.h> |
1368 | #include <tuple> |
1369 | |
1370 | namespace mtf = mir_test_framework; |
1371 | +namespace mt = mir::test; |
1372 | +namespace mtd = mt::doubles; |
1373 | namespace mi = mir::input; |
1374 | namespace mie = mi::evdev; |
1375 | |
1376 | @@ -44,7 +49,9 @@ |
1377 | udev* ctx = reinterpret_cast<udev*>(1); |
1378 | auto dev = env.setup_device(std::get<0>(param)); |
1379 | std::shared_ptr<libinput> lib = mie::make_libinput(ctx); |
1380 | - mie::LibInputDevice device(mir::report::null_input_report(), mie::make_libinput_device(lib, dev)); |
1381 | + ::testing::NiceMock<mtd::MockAlarmFactory> mock_alarm_factory; |
1382 | + mtd::AdvanceableClock clock; |
1383 | + mie::LibInputDevice device(mir::report::null_input_report(), mie::make_libinput_device(lib, dev), mt::fake_shared(mock_alarm_factory), mt::fake_shared(clock)); |
1384 | auto info = device.get_device_info(); |
1385 | EXPECT_THAT(info.capabilities, Eq(std::get<1>(param))); |
1386 | } |
1387 | |
1388 | === modified file 'tests/unit-tests/input/evdev/test_libinput_device.cpp' |
1389 | --- tests/unit-tests/input/evdev/test_libinput_device.cpp 2016-03-23 06:39:56 +0000 |
1390 | +++ tests/unit-tests/input/evdev/test_libinput_device.cpp 2016-03-31 19:18:58 +0000 |
1391 | @@ -25,12 +25,16 @@ |
1392 | #include "mir/input/input_sink.h" |
1393 | #include "mir/input/pointer_settings.h" |
1394 | #include "mir/input/touchpad_settings.h" |
1395 | +#include "mir/input/keyboard_settings.h" |
1396 | #include "mir/flags.h" |
1397 | #include "mir/geometry/point.h" |
1398 | #include "mir/geometry/rectangle.h" |
1399 | #include "mir/test/event_matchers.h" |
1400 | #include "mir/test/doubles/mock_libinput.h" |
1401 | +#include "mir/test/doubles/fake_alarm_factory.h" |
1402 | +#include "mir/test/doubles/advanceable_clock.h" |
1403 | #include "mir/test/gmock_fixes.h" |
1404 | +#include "mir/test/fake_shared.h" |
1405 | #include "mir/udev/wrapper.h" |
1406 | #include "mir/cookie/authority.h" |
1407 | #include "mir_test_framework/libinput_environment.h" |
1408 | @@ -60,6 +64,7 @@ |
1409 | }; |
1410 | |
1411 | using namespace ::testing; |
1412 | +using namespace std::chrono_literals; |
1413 | |
1414 | struct MockInputSink : mi::InputSink |
1415 | { |
1416 | @@ -124,6 +129,8 @@ |
1417 | struct LibInputDevice : public ::testing::Test |
1418 | { |
1419 | mtf::LibInputEnvironment env; |
1420 | + mtd::AdvanceableClock clock; |
1421 | + mtd::FakeAlarmFactory alarm_factory; |
1422 | ::testing::NiceMock<MockInputSink> mock_sink; |
1423 | ::testing::NiceMock<MockEventBuilder> mock_builder; |
1424 | std::shared_ptr<libinput> lib; |
1425 | @@ -243,33 +250,33 @@ |
1426 | struct LibInputDeviceOnLaptopKeyboard : public LibInputDevice |
1427 | { |
1428 | libinput_device*const fake_device = setup_laptop_keyboard(); |
1429 | - mie::LibInputDevice keyboard{mir::report::null_input_report(), mie::make_libinput_device(lib, fake_device)}; |
1430 | + mie::LibInputDevice keyboard{mir::report::null_input_report(), mie::make_libinput_device(lib, fake_device), mt::fake_shared(alarm_factory), mt::fake_shared(clock)}; |
1431 | }; |
1432 | |
1433 | struct LibInputDeviceOnMouse : public LibInputDevice |
1434 | { |
1435 | libinput_device*const fake_device = setup_mouse(); |
1436 | - mie::LibInputDevice mouse{mir::report::null_input_report(), mie::make_libinput_device(lib, fake_device)}; |
1437 | + mie::LibInputDevice mouse{mir::report::null_input_report(), mie::make_libinput_device(lib, fake_device), mt::fake_shared(alarm_factory), mt::fake_shared(clock)}; |
1438 | }; |
1439 | |
1440 | struct LibInputDeviceOnLaptopKeyboardAndMouse : public LibInputDevice |
1441 | { |
1442 | libinput_device*const fake_device = setup_mouse(); |
1443 | libinput_device*const fake_device_2 = setup_laptop_keyboard(); |
1444 | - mie::LibInputDevice keyboard{mir::report::null_input_report(), mie::make_libinput_device(lib, fake_device_2)}; |
1445 | - mie::LibInputDevice mouse{mir::report::null_input_report(), mie::make_libinput_device(lib, fake_device)}; |
1446 | + mie::LibInputDevice keyboard{mir::report::null_input_report(), mie::make_libinput_device(lib, fake_device_2), mt::fake_shared(alarm_factory), mt::fake_shared(clock)}; |
1447 | + mie::LibInputDevice mouse{mir::report::null_input_report(), mie::make_libinput_device(lib, fake_device), mt::fake_shared(alarm_factory), mt::fake_shared(clock)}; |
1448 | }; |
1449 | |
1450 | struct LibInputDeviceOnTouchScreen : public LibInputDevice |
1451 | { |
1452 | libinput_device*const fake_device = setup_touchscreen(); |
1453 | - mie::LibInputDevice touch_screen{mir::report::null_input_report(), mie::make_libinput_device(lib, fake_device)}; |
1454 | + mie::LibInputDevice touch_screen{mir::report::null_input_report(), mie::make_libinput_device(lib, fake_device), mt::fake_shared(alarm_factory), mt::fake_shared(clock)}; |
1455 | }; |
1456 | |
1457 | struct LibInputDeviceOnTouchpad : public LibInputDevice |
1458 | { |
1459 | libinput_device*const fake_device = setup_touchpad(); |
1460 | - mie::LibInputDevice touchpad{mir::report::null_input_report(), mie::make_libinput_device(lib, fake_device)}; |
1461 | + mie::LibInputDevice touchpad{mir::report::null_input_report(), mie::make_libinput_device(lib, fake_device), mt::fake_shared(alarm_factory), mt::fake_shared(clock)}; |
1462 | }; |
1463 | } |
1464 | |
1465 | @@ -284,7 +291,7 @@ |
1466 | .Times(1); |
1467 | |
1468 | mie::LibInputDevice dev(mir::report::null_input_report(), |
1469 | - mie::make_libinput_device(lib, fake_device)); |
1470 | + mie::make_libinput_device(lib, fake_device), mt::fake_shared(alarm_factory), mt::fake_shared(clock)); |
1471 | dev.start(&mock_sink, &mock_builder); |
1472 | } |
1473 | |
1474 | @@ -299,7 +306,7 @@ |
1475 | EXPECT_CALL(env.mock_libinput, libinput_device_ref(second_fake_device)).Times(1); |
1476 | |
1477 | mie::LibInputDevice dev(mir::report::null_input_report(), |
1478 | - mie::make_libinput_device(lib, fake_device)); |
1479 | + mie::make_libinput_device(lib, fake_device), mt::fake_shared(alarm_factory), mt::fake_shared(clock)); |
1480 | dev.add_device_of_group(mie::make_libinput_device(lib, second_fake_device)); |
1481 | dev.start(&mock_sink, &mock_builder); |
1482 | } |
1483 | @@ -310,7 +317,7 @@ |
1484 | auto second_fake_device = setup_trackpad(); |
1485 | |
1486 | mie::LibInputDevice dev(mir::report::null_input_report(), |
1487 | - mie::make_libinput_device(lib, fake_device)); |
1488 | + mie::make_libinput_device(lib, fake_device), mt::fake_shared(alarm_factory), mt::fake_shared(clock)); |
1489 | dev.add_device_of_group(mie::make_libinput_device(lib, second_fake_device)); |
1490 | auto info = dev.get_device_info(); |
1491 | |
1492 | @@ -327,7 +334,7 @@ |
1493 | EXPECT_CALL(env.mock_libinput, libinput_device_unref(fake_device)) |
1494 | .Times(1); |
1495 | |
1496 | - mie::LibInputDevice dev(mir::report::null_input_report(), mie::make_libinput_device(lib, fake_device)); |
1497 | + mie::LibInputDevice dev(mir::report::null_input_report(), mie::make_libinput_device(lib, fake_device), mt::fake_shared(alarm_factory), mt::fake_shared(clock)); |
1498 | } |
1499 | |
1500 | TEST_F(LibInputDeviceOnLaptopKeyboard, process_event_converts_key_event) |
1501 | @@ -343,6 +350,31 @@ |
1502 | process_events(keyboard); |
1503 | } |
1504 | |
1505 | +TEST_F(LibInputDeviceOnLaptopKeyboard, key_press_triggers_repeat) |
1506 | +{ |
1507 | + mi::KeyboardSettings keyboard_settings; |
1508 | + keyboard_settings.repeat_delay = 600ms; |
1509 | + keyboard_settings.repeat_interval = 200ms; |
1510 | + std::function<void()> timer_callback; |
1511 | + |
1512 | + EXPECT_CALL(mock_sink, handle_input(AllOf( |
1513 | + mt::KeyOfScanCode(KEY_A), |
1514 | + mt::KeyDownEvent()))) |
1515 | + .Times(1); |
1516 | + EXPECT_CALL(mock_sink, handle_input(AllOf( |
1517 | + mt::KeyOfScanCode(KEY_A), |
1518 | + mt::KeyRepeatEvent()))) |
1519 | + .Times(2); |
1520 | + |
1521 | + keyboard.start(&mock_sink, &mock_builder); |
1522 | + keyboard.apply_settings(keyboard_settings); |
1523 | + env.mock_libinput.setup_key_event(fake_device, event_time_1, KEY_A, LIBINPUT_KEY_STATE_PRESSED); |
1524 | + process_events(keyboard); |
1525 | + |
1526 | + alarm_factory.advance_by(601ms); |
1527 | + alarm_factory.advance_by(201ms); |
1528 | +} |
1529 | + |
1530 | TEST_F(LibInputDeviceOnLaptopKeyboard, process_event_accumulates_key_state) |
1531 | { |
1532 | InSequence seq; |
1533 | |
1534 | === modified file 'tests/unit-tests/input/test_default_device.cpp' |
1535 | --- tests/unit-tests/input/test_default_device.cpp 2016-03-23 06:39:56 +0000 |
1536 | +++ tests/unit-tests/input/test_default_device.cpp 2016-03-31 19:18:58 +0000 |
1537 | @@ -21,54 +21,23 @@ |
1538 | #include "mir/input/touchpad_configuration.h" |
1539 | #include "mir/input/pointer_configuration.h" |
1540 | #include "mir/dispatch/action_queue.h" |
1541 | +#include "mir/test/doubles/mock_input_device.h" |
1542 | #include <gtest/gtest.h> |
1543 | #include <gmock/gmock.h> |
1544 | #include <stdexcept> |
1545 | |
1546 | namespace mi = mir::input; |
1547 | +namespace mtd = mir::test::doubles; |
1548 | namespace md = mir::dispatch; |
1549 | using namespace ::testing; |
1550 | namespace |
1551 | { |
1552 | -struct MockInputDevice : public mi::InputDevice |
1553 | -{ |
1554 | - MOCK_METHOD2(start, void(mi::InputSink* destination, mi::EventBuilder* builder)); |
1555 | - MOCK_METHOD0(stop, void()); |
1556 | - MOCK_METHOD0(get_device_info, mi::InputDeviceInfo()); |
1557 | - MOCK_CONST_METHOD0(get_pointer_settings, mir::optional_value<mi::PointerSettings>()); |
1558 | - MOCK_METHOD1(apply_settings, void(mi::PointerSettings const&)); |
1559 | - MOCK_CONST_METHOD0(get_touchpad_settings, mir::optional_value<mi::TouchpadSettings>()); |
1560 | - MOCK_METHOD1(apply_settings, void(mi::TouchpadSettings const&)); |
1561 | -}; |
1562 | - |
1563 | struct DefaultDevice : Test |
1564 | { |
1565 | - NiceMock<MockInputDevice> touchpad; |
1566 | - NiceMock<MockInputDevice> mouse; |
1567 | - NiceMock<MockInputDevice> keyboard; |
1568 | + NiceMock<mtd::MockInputDevice> touchpad{"name", "unique", mi::DeviceCapability::touchpad|mi::DeviceCapability::pointer}; |
1569 | + NiceMock<mtd::MockInputDevice> mouse{"name", "unique", mi::DeviceCapability::pointer}; |
1570 | + NiceMock<mtd::MockInputDevice> keyboard{"name", "unique", mi::DeviceCapability::keyboard}; |
1571 | std::shared_ptr<md::ActionQueue> queue{std::make_shared<md::ActionQueue>()}; |
1572 | - |
1573 | - DefaultDevice() |
1574 | - { |
1575 | - using optional_pointer_settings = mir::optional_value<mi::PointerSettings>; |
1576 | - using optional_touchpad_settings = mir::optional_value<mi::TouchpadSettings>; |
1577 | - ON_CALL(touchpad, get_device_info()) |
1578 | - .WillByDefault(Return(mi::InputDeviceInfo{"name", "unique", mi::DeviceCapability::touchpad|mi::DeviceCapability::pointer})); |
1579 | - ON_CALL(touchpad, get_pointer_settings()) |
1580 | - .WillByDefault(Return(optional_pointer_settings{mi::PointerSettings{}})); |
1581 | - ON_CALL(touchpad, get_touchpad_settings()) |
1582 | - .WillByDefault(Return(optional_touchpad_settings{mi::TouchpadSettings{}})); |
1583 | - |
1584 | - ON_CALL(mouse, get_device_info()) |
1585 | - .WillByDefault(Return(mi::InputDeviceInfo{"name", "unique", mi::DeviceCapability::pointer})); |
1586 | - ON_CALL(mouse, get_pointer_settings()).WillByDefault(Return(optional_pointer_settings{mi::PointerSettings{}})); |
1587 | - ON_CALL(mouse, get_touchpad_settings()).WillByDefault(Return(optional_touchpad_settings{})); |
1588 | - |
1589 | - ON_CALL(keyboard, get_device_info()) |
1590 | - .WillByDefault(Return(mi::InputDeviceInfo{"name", "unique", mi::DeviceCapability::keyboard})); |
1591 | - ON_CALL(keyboard, get_pointer_settings()).WillByDefault(Return(optional_pointer_settings{})); |
1592 | - ON_CALL(keyboard, get_touchpad_settings()).WillByDefault(Return(optional_touchpad_settings{})); |
1593 | - } |
1594 | }; |
1595 | |
1596 | } |
1597 | @@ -91,7 +60,6 @@ |
1598 | EXPECT_THROW({dev.apply_pointer_configuration(pointer_conf);}, std::invalid_argument); |
1599 | } |
1600 | |
1601 | - |
1602 | TEST_F(DefaultDevice, accepts_pointer_config_on_mice) |
1603 | { |
1604 | mi::DefaultDevice dev(MirInputDeviceId{17}, queue, mouse); |
1605 | @@ -118,6 +86,7 @@ |
1606 | queue->dispatch(md::FdEvent::readable); |
1607 | } |
1608 | |
1609 | + |
1610 | TEST_F(DefaultDevice, ensures_cursor_accleration_bias_is_in_range) |
1611 | { |
1612 | mi::DefaultDevice dev(MirInputDeviceId{17}, queue, touchpad); |
1613 | |
1614 | === removed file 'tests/unit-tests/input/test_key_repeat_dispatcher.cpp' |
1615 | --- tests/unit-tests/input/test_key_repeat_dispatcher.cpp 2016-03-23 06:39:56 +0000 |
1616 | +++ tests/unit-tests/input/test_key_repeat_dispatcher.cpp 1970-01-01 00:00:00 +0000 |
1617 | @@ -1,184 +0,0 @@ |
1618 | -/* |
1619 | - * Copyright © 2015 Canonical Ltd. |
1620 | - * |
1621 | - * This program is free software: you can redistribute it and/or modify |
1622 | - * it under the terms of the GNU General Public License version 3 as |
1623 | - * published by the Free Software Foundation. |
1624 | - * |
1625 | - * This program is distributed in the hope that it will be useful, |
1626 | - * but WITHOUT ANY WARRANTY; without even the implied warranty of |
1627 | - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
1628 | - * GNU General Public License for more details. |
1629 | - * |
1630 | - * You should have received a copy of the GNU General Public License |
1631 | - * along with this program. If not, see <http://www.gnu.org/licenses/>. |
1632 | - * |
1633 | - * Authored by: Robert Carr <robert.carr@canonical.com> |
1634 | - */ |
1635 | - |
1636 | -#include "src/server/input/key_repeat_dispatcher.h" |
1637 | - |
1638 | -#include "mir/events/event_private.h" |
1639 | -#include "mir/events/event_builders.h" |
1640 | -#include "mir/time/alarm.h" |
1641 | -#include "mir/time/alarm_factory.h" |
1642 | -#include "mir/cookie/authority.h" |
1643 | -#include "mir/input/input_device_observer.h" |
1644 | -#include "mir/input/pointer_configuration.h" |
1645 | -#include "mir/input/touchpad_configuration.h" |
1646 | -#include "mir/input/device.h" |
1647 | - |
1648 | -#include "mir/test/fake_shared.h" |
1649 | -#include "mir/test/event_matchers.h" |
1650 | -#include "mir/test/doubles/mock_input_dispatcher.h" |
1651 | -#include "mir/test/doubles/mock_input_device_hub.h" |
1652 | - |
1653 | -#include <gtest/gtest.h> |
1654 | -#include <gmock/gmock.h> |
1655 | - |
1656 | -namespace mi = mir::input; |
1657 | -namespace mev = mir::events; |
1658 | -namespace mt = mir::test; |
1659 | -namespace mtd = mt::doubles; |
1660 | - |
1661 | -using namespace ::testing; |
1662 | - |
1663 | -namespace |
1664 | -{ |
1665 | -struct MockAlarm : public mir::time::Alarm |
1666 | -{ |
1667 | - MOCK_METHOD0(cancel, bool()); |
1668 | - MOCK_CONST_METHOD0(state, mir::time::Alarm::State()); |
1669 | - MOCK_METHOD1(reschedule_in, bool(std::chrono::milliseconds)); |
1670 | - MOCK_METHOD1(reschedule_for, bool(mir::time::Timestamp)); |
1671 | - |
1672 | - // destructor cancels the alarm |
1673 | - ~MockAlarm() |
1674 | - { |
1675 | - cancel(); |
1676 | - } |
1677 | -}; |
1678 | - |
1679 | -struct MockAlarmFactory : public mir::time::AlarmFactory |
1680 | -{ |
1681 | - MOCK_METHOD1(create_alarm_adapter, mir::time::Alarm*(std::function<void()> const&)); |
1682 | - std::unique_ptr<mir::time::Alarm> create_alarm(std::function<void()> const& cb) |
1683 | - { |
1684 | - return std::unique_ptr<mir::time::Alarm>(create_alarm_adapter(cb)); |
1685 | - } |
1686 | - |
1687 | - std::unique_ptr<mir::time::Alarm> create_alarm(std::shared_ptr<mir::LockableCallback> const&) |
1688 | - { |
1689 | - return nullptr; |
1690 | - } |
1691 | -}; |
1692 | - |
1693 | -struct StubDevice : public mi::Device |
1694 | -{ |
1695 | - MirInputDeviceId device_id; |
1696 | - StubDevice(MirInputDeviceId id) : device_id(id) {} |
1697 | - MirInputDeviceId id() const { return device_id;} |
1698 | - mi::DeviceCapabilities capabilities() const {return mi::DeviceCapability::keyboard;} |
1699 | - std::string name() const {return {};} |
1700 | - std::string unique_id() const {return {};} |
1701 | - |
1702 | - mir::optional_value<mi::PointerConfiguration> pointer_configuration() const {return {};} |
1703 | - void apply_pointer_configuration(mi::PointerConfiguration const&) {;} |
1704 | - mir::optional_value<mi::TouchpadConfiguration> touchpad_configuration() const {return {};} |
1705 | - void apply_touchpad_configuration(mi::TouchpadConfiguration const&) {} |
1706 | -}; |
1707 | - |
1708 | -struct KeyRepeatDispatcher : public testing::Test |
1709 | -{ |
1710 | - KeyRepeatDispatcher() |
1711 | - : dispatcher(mock_next_dispatcher, mock_alarm_factory, cookie_authority, true, repeat_time, repeat_delay) |
1712 | - { |
1713 | - ON_CALL(hub,add_observer(_)).WillByDefault(SaveArg<0>(&observer)); |
1714 | - dispatcher.set_input_device_hub(mt::fake_shared(hub)); |
1715 | - } |
1716 | - void simulate_device_removal() |
1717 | - { |
1718 | - StubDevice dev(test_device); |
1719 | - observer->device_removed(mt::fake_shared(dev)); |
1720 | - observer->changes_complete(); |
1721 | - } |
1722 | - |
1723 | - const MirInputDeviceId test_device = 123; |
1724 | - std::shared_ptr<mtd::MockInputDispatcher> mock_next_dispatcher = std::make_shared<mtd::MockInputDispatcher>(); |
1725 | - std::shared_ptr<MockAlarmFactory> mock_alarm_factory = std::make_shared<MockAlarmFactory>(); |
1726 | - std::shared_ptr<mir::cookie::Authority> cookie_authority = mir::cookie::Authority::create(); |
1727 | - std::chrono::milliseconds const repeat_time{2}; |
1728 | - std::chrono::milliseconds const repeat_delay{1}; |
1729 | - std::shared_ptr<mi::InputDeviceObserver> observer; |
1730 | - NiceMock<mtd::MockInputDeviceHub> hub; |
1731 | - mi::KeyRepeatDispatcher dispatcher; |
1732 | - |
1733 | - mir::EventUPtr a_key_down_event() |
1734 | - { |
1735 | - 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); |
1736 | - } |
1737 | - |
1738 | - mir::EventUPtr a_key_up_event() |
1739 | - { |
1740 | - 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); |
1741 | - } |
1742 | -}; |
1743 | -} |
1744 | - |
1745 | -TEST_F(KeyRepeatDispatcher, forwards_start_stop) |
1746 | -{ |
1747 | - InSequence seq; |
1748 | - EXPECT_CALL(*mock_next_dispatcher, start()).Times(1); |
1749 | - EXPECT_CALL(*mock_next_dispatcher, stop()).Times(1); |
1750 | - |
1751 | - dispatcher.start(); |
1752 | - dispatcher.stop(); |
1753 | -} |
1754 | - |
1755 | -TEST_F(KeyRepeatDispatcher, schedules_alarm_to_repeat_key_down) |
1756 | -{ |
1757 | - MockAlarm *mock_alarm = new MockAlarm; // deleted by AlarmFactory |
1758 | - std::function<void()> alarm_function; |
1759 | - |
1760 | - InSequence seq; |
1761 | - EXPECT_CALL(*mock_alarm_factory, create_alarm_adapter(_)).Times(1). |
1762 | - WillOnce(DoAll(SaveArg<0>(&alarm_function), Return(mock_alarm))); |
1763 | - // Once for initial down and again when invoked |
1764 | - EXPECT_CALL(*mock_alarm, reschedule_in(repeat_time)).Times(1).WillOnce(Return(true)); |
1765 | - EXPECT_CALL(*mock_next_dispatcher, dispatch(mt::KeyDownEvent())).Times(1); |
1766 | - EXPECT_CALL(*mock_next_dispatcher, dispatch(mt::KeyRepeatEvent())).Times(1); |
1767 | - EXPECT_CALL(*mock_alarm, reschedule_in(repeat_delay)).Times(1).WillOnce(Return(true)); |
1768 | - EXPECT_CALL(*mock_next_dispatcher, dispatch(mt::KeyUpEvent())).Times(1); |
1769 | - |
1770 | - // Schedule the repeat |
1771 | - dispatcher.dispatch(*a_key_down_event()); |
1772 | - // Trigger the repeat |
1773 | - alarm_function(); |
1774 | - // Trigger the cancel |
1775 | - dispatcher.dispatch(*a_key_up_event()); |
1776 | -} |
1777 | - |
1778 | -TEST_F(KeyRepeatDispatcher, stops_repeat_on_device_removal) |
1779 | -{ |
1780 | - MockAlarm *mock_alarm = new MockAlarm; |
1781 | - std::function<void()> alarm_function; |
1782 | - bool alarm_canceled = false; |
1783 | - |
1784 | - InSequence seq; |
1785 | - EXPECT_CALL(*mock_alarm_factory, create_alarm_adapter(_)).Times(1). |
1786 | - WillOnce(DoAll(SaveArg<0>(&alarm_function), Return(mock_alarm))); |
1787 | - // Once for initial down and again when invoked |
1788 | - EXPECT_CALL(*mock_alarm, reschedule_in(repeat_time)).Times(1).WillOnce(Return(true)); |
1789 | - EXPECT_CALL(*mock_next_dispatcher, dispatch(mt::KeyDownEvent())).Times(1); |
1790 | - EXPECT_CALL(*mock_next_dispatcher, dispatch(mt::KeyRepeatEvent())).Times(1); |
1791 | - EXPECT_CALL(*mock_alarm, reschedule_in(repeat_delay)).Times(1).WillOnce(Return(true)); |
1792 | - ON_CALL(*mock_alarm, cancel()).WillByDefault(Invoke([&](){alarm_canceled = true; return true;})); |
1793 | - |
1794 | - dispatcher.dispatch(*a_key_down_event()); |
1795 | - |
1796 | - alarm_function(); |
1797 | - Mock::VerifyAndClearExpectations(mock_alarm); // mock_alarm will be deleted after this |
1798 | - |
1799 | - simulate_device_removal(); |
1800 | - EXPECT_THAT(alarm_canceled, Eq(true)); |
1801 | -} |
1802 | |
1803 | === modified file 'tests/unit-tests/input/test_x11_platform.cpp' |
1804 | --- tests/unit-tests/input/test_x11_platform.cpp 2016-03-23 06:39:56 +0000 |
1805 | +++ tests/unit-tests/input/test_x11_platform.cpp 2016-03-31 19:18:58 +0000 |
1806 | @@ -34,12 +34,15 @@ |
1807 | #include "mir/cookie/authority.h" |
1808 | #include "mir/test/event_matchers.h" |
1809 | |
1810 | +#include "mir/input/keyboard_settings.h" |
1811 | + |
1812 | namespace md = mir::dispatch; |
1813 | namespace mi = mir::input; |
1814 | namespace mt = mir::test; |
1815 | namespace mtd = mt::doubles; |
1816 | |
1817 | using namespace ::testing; |
1818 | +using namespace std::chrono_literals; |
1819 | |
1820 | namespace |
1821 | { |
1822 | @@ -245,3 +248,80 @@ |
1823 | |
1824 | process_input_event(); |
1825 | } |
1826 | + |
1827 | +TEST_F(X11PlatformTest, keyboard_device_forwards_x11_repeat_settings) |
1828 | +{ |
1829 | + XkbControlsRec ctrls_desc; |
1830 | + XkbDescRec xkb_desc; |
1831 | + ctrls_desc.repeat_delay = 600; |
1832 | + ctrls_desc.repeat_interval = 100; |
1833 | + EXPECT_CALL(mock_x11, XGetKeyboardControl(_,_)) |
1834 | + .WillOnce(Invoke([](Display*, XKeyboardState* state) |
1835 | + { |
1836 | + state->global_auto_repeat = 1; |
1837 | + return 1; |
1838 | + })); |
1839 | + EXPECT_CALL(mock_x11, XkbQueryExtension(_,_,_,_,_,_)) |
1840 | + .WillOnce(Return(1)); |
1841 | + EXPECT_CALL(mock_x11, XkbAllocKeyboard()) |
1842 | + .WillOnce(Return(&xkb_desc)); |
1843 | + EXPECT_CALL(mock_x11, XkbGetControls(_,XkbRepeatKeysMask, &xkb_desc)) |
1844 | + .WillOnce(Invoke([&](Display*, int, XkbDescPtr) |
1845 | + { |
1846 | + xkb_desc.ctrls = &ctrls_desc; |
1847 | + return 1; |
1848 | + })); |
1849 | + EXPECT_CALL(mock_x11, XkbFreeKeyboard(&xkb_desc, _, _)); |
1850 | + |
1851 | + |
1852 | + capture_devices(); x11_platform.start(); |
1853 | + |
1854 | + for (auto const device : devices) |
1855 | + { |
1856 | + if (contains(device->get_device_info().capabilities,mi::DeviceCapability::keyboard)) |
1857 | + { |
1858 | + auto settings = device->get_keyboard_settings(); |
1859 | + EXPECT_THAT(settings.value().repeat_enabled, Eq(true)); |
1860 | + EXPECT_THAT(settings.value().repeat_delay, Eq(600ms)); |
1861 | + EXPECT_THAT(settings.value().repeat_interval, Eq(100ms)); |
1862 | + } |
1863 | + } |
1864 | +} |
1865 | + |
1866 | +TEST_F(X11PlatformTest, keyboard_device_forwards_settings_to_x11) |
1867 | +{ |
1868 | + XkbControlsRec ctrls_desc; |
1869 | + XkbDescRec xkb_desc; |
1870 | + |
1871 | + EXPECT_CALL(mock_x11, XChangeKeyboardControl(_, KBAutoRepeatMode,_)); |
1872 | + EXPECT_CALL(mock_x11, XkbQueryExtension(_,_,_,_,_,_)) |
1873 | + .WillOnce(Return(1)); |
1874 | + EXPECT_CALL(mock_x11, XkbAllocKeyboard()) |
1875 | + .WillOnce(Return(&xkb_desc)); |
1876 | + EXPECT_CALL(mock_x11, XkbGetControls(_,XkbRepeatKeysMask, &xkb_desc)) |
1877 | + .WillOnce(Invoke([&](Display*, int, XkbDescPtr) |
1878 | + { |
1879 | + xkb_desc.ctrls = &ctrls_desc; |
1880 | + return 1; |
1881 | + })); |
1882 | + EXPECT_CALL(mock_x11, XkbSetControls(_,XkbRepeatKeysMask, &xkb_desc)) |
1883 | + .WillOnce(Return(1)); |
1884 | + EXPECT_CALL(mock_x11, XkbFreeKeyboard(&xkb_desc, _, _)); |
1885 | + |
1886 | + |
1887 | + capture_devices(); x11_platform.start(); |
1888 | + |
1889 | + for (auto const device : devices) |
1890 | + { |
1891 | + if (contains(device->get_device_info().capabilities,mi::DeviceCapability::keyboard)) |
1892 | + { |
1893 | + mi::KeyboardSettings settings; |
1894 | + settings.repeat_interval = 23ms; |
1895 | + settings.repeat_delay = 1000ms; |
1896 | + device->apply_settings(settings); |
1897 | + |
1898 | + EXPECT_THAT(ctrls_desc.repeat_delay, Eq(1000)); |
1899 | + EXPECT_THAT(ctrls_desc.repeat_interval, Eq(23)); |
1900 | + } |
1901 | + } |
1902 | +} |
FAILED: Continuous integration, rev:3421 /mir-jenkins. ubuntu. com/job/ mir-ci/ 644/ /mir-jenkins. ubuntu. com/job/ build-mir/ 580/console /mir-jenkins. ubuntu. com/job/ build-0- fetch/616 /mir-jenkins. ubuntu. com/job/ build-1- sourcepkg/ release= vivid+overlay/ 608 /mir-jenkins. ubuntu. com/job/ build-1- sourcepkg/ release= xenial/ 608 /mir-jenkins. ubuntu. com/job/ build-2- binpkg- mir/arch= amd64,compiler= clang,platform= mesa,release= vivid+overlay/ 590/console /mir-jenkins. ubuntu. com/job/ build-2- binpkg- mir/arch= amd64,compiler= gcc,platform= mesa,release= xenial/ 590/console /mir-jenkins. ubuntu. com/job/ build-2- binpkg- mir/arch= cross-armhf, compiler= gcc,platform= android, release= vivid+overlay/ 590/console /mir-jenkins. ubuntu. com/job/ build-2- binpkg- mir/arch= cross-armhf, compiler= gcc,platform= android, release= vivid+overlay/ 590/artifact/ output/ *zip*/output. zip /mir-jenkins. ubuntu. com/job/ build-2- binpkg- mir/arch= i386,compiler= gcc,platform= android, release= vivid+overlay/ 590/console /mir-jenkins. ubuntu. com/job/ build-2- binpkg- mir/arch= i386,compiler= gcc,platform= mesa,release= xenial/ 590/console
https:/
Executed test runs:
FAILURE: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
deb: https:/
FAILURE: https:/
FAILURE: https:/
Click here to trigger a rebuild: /mir-jenkins. ubuntu. com/job/ mir-ci/ 644/rebuild
https:/