Merge lp:~andreas-pokorny/mir/libinput-platform into lp:mir
- libinput-platform
- Merge into development-branch
Status: | Merged |
---|---|
Approved by: | Andreas Pokorny |
Approved revision: | no longer in the source branch. |
Merged at revision: | 2956 |
Proposed branch: | lp:~andreas-pokorny/mir/libinput-platform |
Merge into: | lp:mir |
Prerequisite: | lp:~andreas-pokorny/mir/remove-dispatchable-from-input-device |
Diff against target: |
2503 lines (+2279/-9) 25 files modified
CMakeLists.txt (+1/-0) debian/control (+1/-0) include/test/mir/test/event_matchers.h (+45/-0) src/CMakeLists.txt (+1/-0) src/platforms/CMakeLists.txt (+2/-0) src/platforms/evdev/CMakeLists.txt (+29/-0) src/platforms/evdev/input_modifier_utils.cpp (+8/-5) src/platforms/evdev/input_modifier_utils.h (+1/-1) src/platforms/evdev/libinput_device.cpp (+347/-0) src/platforms/evdev/libinput_device.h (+90/-0) src/platforms/evdev/libinput_device_ptr.cpp (+30/-0) src/platforms/evdev/libinput_device_ptr.h (+40/-0) src/platforms/evdev/libinput_ptr.cpp (+47/-0) src/platforms/evdev/libinput_ptr.h (+42/-0) src/platforms/evdev/platform.cpp (+238/-0) src/platforms/evdev/platform.h (+94/-0) src/platforms/evdev/platform_factory.cpp (+68/-0) tests/include/mir/test/doubles/mock_libinput.h (+110/-0) tests/mir_test_doubles/CMakeLists.txt (+1/-0) tests/mir_test_doubles/mock_libinput.cpp (+316/-0) tests/mir_test_framework/CMakeLists.txt (+1/-1) tests/mir_test_framework/fake_input_device_impl.cpp (+2/-2) tests/unit-tests/input/evdev/CMakeLists.txt (+3/-0) tests/unit-tests/input/evdev/test_evdev_input_platform.cpp (+264/-0) tests/unit-tests/input/evdev/test_libinput_device.cpp (+498/-0) |
To merge this branch: | bzr merge lp:~andreas-pokorny/mir/libinput-platform |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
PS Jenkins bot (community) | continuous-integration | Approve | |
Alexandros Frantzis (community) | Approve | ||
Kevin DuBois (community) | Approve | ||
Alan Griffiths | Approve | ||
Cemil Azizoglu (community) | Needs Fixing | ||
Review via email: mp+270313@code.launchpad.net |
This proposal supersedes a proposal from 2015-08-28.
Commit message
Add input-evdev.so based on libinput
This adds the evdev platform that shall replace InputReader, EventHub and the InputMappers. The platform is not yet selected by default. Code to probe and select the right platform is still missing for the input side.
Description of the change
This adds the libinput platform as input-evdev.so
It does not yet use the extended libinput_
You can test that in the build dir with --platform-
Andreas Pokorny (andreas-pokorny) wrote : Posted in a previous version of this proposal | # |
PS Jenkins bot (ps-jenkins) wrote : Posted in a previous version of this proposal | # |
FAILED: Continuous integration, rev:2402
http://
Executed test runs:
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
Click here to trigger a rebuild:
http://
PS Jenkins bot (ps-jenkins) wrote : Posted in a previous version of this proposal | # |
FAILED: Continuous integration, rev:2403
http://
Executed test runs:
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
Click here to trigger a rebuild:
http://
Andreas Pokorny (andreas-pokorny) wrote : Posted in a previous version of this proposal | # |
This MP needs a newer libinput in vivid+overlay. Silo for that is on the way.
PS Jenkins bot (ps-jenkins) wrote : Posted in a previous version of this proposal | # |
FAILED: Continuous integration, rev:2404
http://
Executed test runs:
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
SUCCESS: http://
deb: http://
FAILURE: http://
Click here to trigger a rebuild:
http://
PS Jenkins bot (ps-jenkins) wrote : Posted in a previous version of this proposal | # |
FAILED: Continuous integration, rev:2406
http://
Executed test runs:
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
SUCCESS: http://
deb: http://
FAILURE: http://
Click here to trigger a rebuild:
http://
PS Jenkins bot (ps-jenkins) wrote : Posted in a previous version of this proposal | # |
FAILED: Continuous integration, rev:2406
http://
Executed test runs:
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
SUCCESS: http://
deb: http://
FAILURE: http://
Click here to trigger a rebuild:
http://
PS Jenkins bot (ps-jenkins) wrote : Posted in a previous version of this proposal | # |
FAILED: Continuous integration, rev:2406
http://
Executed test runs:
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
SUCCESS: http://
deb: http://
FAILURE: http://
Click here to trigger a rebuild:
http://
PS Jenkins bot (ps-jenkins) wrote : Posted in a previous version of this proposal | # |
FAILED: Continuous integration, rev:2406
http://
Executed test runs:
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
SUCCESS: http://
deb: http://
FAILURE: http://
Click here to trigger a rebuild:
http://
PS Jenkins bot (ps-jenkins) wrote : Posted in a previous version of this proposal | # |
FAILED: Continuous integration, rev:2406
http://
Executed test runs:
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
SUCCESS: http://
deb: http://
FAILURE: http://
Click here to trigger a rebuild:
http://
PS Jenkins bot (ps-jenkins) wrote : Posted in a previous version of this proposal | # |
FAILED: Continuous integration, rev:2404
http://
Executed test runs:
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
SUCCESS: http://
deb: http://
FAILURE: http://
Click here to trigger a rebuild:
http://
Alan Griffiths (alan-griffiths) wrote : Posted in a previous version of this proposal | # |
Text conflict in include/
1 conflicts encountered
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:2408
http://
Executed test runs:
FAILURE: http://
FAILURE: http://
FAILURE: http://
SUCCESS: http://
deb: http://
FAILURE: http://
Click here to trigger a rebuild:
http://
PS Jenkins bot (ps-jenkins) wrote : Posted in a previous version of this proposal | # |
FAILED: Continuous integration, rev:2407
http://
Executed test runs:
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
Click here to trigger a rebuild:
http://
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:2409
http://
Executed test runs:
FAILURE: http://
FAILURE: http://
FAILURE: http://
SUCCESS: http://
deb: http://
FAILURE: http://
Click here to trigger a rebuild:
http://
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:2412
http://
Executed test runs:
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
Click here to trigger a rebuild:
http://
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:2413
http://
Executed test runs:
SUCCESS: http://
FAILURE: http://
FAILURE: http://
SUCCESS: http://
deb: http://
FAILURE: http://
Click here to trigger a rebuild:
http://
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:2413
http://
Executed test runs:
SUCCESS: http://
FAILURE: http://
FAILURE: http://
SUCCESS: http://
deb: http://
FAILURE: http://
Click here to trigger a rebuild:
http://
Cemil Azizoglu (cemil-azizoglu) wrote : | # |
(Haven't completed the review yet.)
1211 +extern "C" mir::UniqueModu
1222 +extern "C" void add_input_
1228 +extern "C" mi::PlatformPri
1238 +extern "C" mir::ModuleProp
Please remove these "extern" keywords in the definition of functions as they cause problems with
abi-compliance-
-------
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:2414
http://
Executed test runs:
SUCCESS: http://
FAILURE: http://
FAILURE: http://
SUCCESS: http://
deb: http://
FAILURE: http://
Click here to trigger a rebuild:
http://
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:2414
http://
Executed test runs:
SUCCESS: http://
FAILURE: http://
FAILURE: http://
SUCCESS: http://
deb: http://
FAILURE: http://
Click here to trigger a rebuild:
http://
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:2414
http://
Executed test runs:
SUCCESS: http://
FAILURE: http://
FAILURE: http://
SUCCESS: http://
deb: http://
FAILURE: http://
Click here to trigger a rebuild:
http://
Francis Ginther (fginther) wrote : | # |
Andreas, the most recent CI run includes the addition of the overlay PPA for all builds. Please let me know if you have any questions.
PS Jenkins bot (ps-jenkins) wrote : | # |
PASSED: Continuous integration, rev:2416
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
Alan Griffiths (alan-griffiths) wrote : | # |
A mild "needs fixing"
+ EXPECT_
+ EXPECT_
+ EXPECT_
These magic numbers are hard to interpret. Couldn't we have, for example:
EXPECT_
~~~~
-MirInputEventM
+MirInputEventM
Now the function name disagrees with the return type.
~~~~
+ auto action = ...
Here and elsewhere could be "auto const"
Andreas Pokorny (andreas-pokorny) wrote : | # |
> A mild "needs fixing"
>
> + EXPECT_
> handle_
> + EXPECT_
> + EXPECT_
>
> These magic numbers are hard to interpret. Couldn't we have, for example:
>
> EXPECT_
> mir_pointer_
>
Only did that for the new matcher. The other matchers are used frequently. I think we can do the typing of event matchers in separate mps.
PS Jenkins bot (ps-jenkins) wrote : | # |
PASSED: Continuous integration, rev:2418
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
Kevin DuBois (kdub) wrote : | # |
LGTM... I have a slight preference for aligning indentation at 4 spaces for multiline instead of open-parenthesis alignment, but thats no reason to block.
Alexandros Frantzis (afrantzis) wrote : | # |
+ MATCHER_
+ ...
+ if (mir_pointer_
+ return false;
Shouldn't this be != mir_pointer_
+void mie::Platform:
+{
+ log_info("device added %s", dev.devnode());
Wrong log message.
+ mir::log_
+ report-
If the logging report is selected we will get the message twice. The mix of logging and reporting here doesn't seem correct.
+ for(auto ev = next_event(); ev; ev = next_event())
Simpler as 'while (auto ev = next_event()) ...'
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:2419
http://
Executed test runs:
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
Click here to trigger a rebuild:
http://
PS Jenkins bot (ps-jenkins) wrote : | # |
PASSED: Continuous integration, rev:2420
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
Alexandros Frantzis (afrantzis) wrote : | # |
Looks good.
PS Jenkins bot (ps-jenkins) : | # |
Preview Diff
1 | === modified file 'CMakeLists.txt' |
2 | --- CMakeLists.txt 2015-09-08 21:22:41 +0000 |
3 | +++ CMakeLists.txt 2015-09-18 10:27:31 +0000 |
4 | @@ -175,6 +175,7 @@ |
5 | find_package(LTTngUST REQUIRED) |
6 | pkg_check_modules(UDEV REQUIRED libudev) |
7 | pkg_check_modules(GLIB REQUIRED glib-2.0) |
8 | +pkg_check_modules(LIBINPUT REQUIRED libinput) |
9 | pkg_check_modules(NETTLE REQUIRED nettle) |
10 | pkg_check_modules(UUID REQUIRED uuid) |
11 | |
12 | |
13 | === modified file 'debian/control' |
14 | --- debian/control 2015-09-18 10:23:57 +0000 |
15 | +++ debian/control 2015-09-18 10:27:31 +0000 |
16 | @@ -40,6 +40,7 @@ |
17 | libfreetype6-dev, |
18 | abi-compliance-checker, |
19 | libevdev-dev, |
20 | + libinput-dev (>= 0.21), |
21 | uuid-dev, |
22 | python3:any, |
23 | dh-python, |
24 | |
25 | === modified file 'include/test/mir/test/event_matchers.h' |
26 | --- include/test/mir/test/event_matchers.h 2015-07-27 07:24:50 +0000 |
27 | +++ include/test/mir/test/event_matchers.h 2015-09-18 10:27:31 +0000 |
28 | @@ -250,6 +250,22 @@ |
29 | return button_event_matches(pev, x, y, mir_pointer_action_button_down, 0, true, false); |
30 | } |
31 | |
32 | +MATCHER_P2(ButtonDownEventWithButton, pos, button, "") |
33 | +{ |
34 | + auto pev = maybe_pointer_event(to_address(arg)); |
35 | + if (pev == nullptr) |
36 | + return false; |
37 | + if (mir_pointer_event_action(pev) != mir_pointer_action_button_down) |
38 | + return false; |
39 | + if (mir_pointer_event_button_state(pev, static_cast<MirPointerButton>(button)) == false) |
40 | + return false; |
41 | + if (mir_pointer_event_axis_value(pev, mir_pointer_axis_x) != pos.x.as_float()) |
42 | + return false; |
43 | + if (mir_pointer_event_axis_value(pev, mir_pointer_axis_y) != pos.y.as_float()) |
44 | + return false; |
45 | + return true; |
46 | +} |
47 | + |
48 | MATCHER_P2(ButtonUpEvent, x, y, "") |
49 | { |
50 | auto pev = maybe_pointer_event(to_address(arg)); |
51 | @@ -262,6 +278,35 @@ |
52 | return button_event_matches(pev, x, y, mir_pointer_action_button_down, buttons, false); |
53 | } |
54 | |
55 | +MATCHER_P2(ButtonUpEventWithButton, pos, button, "") |
56 | +{ |
57 | + auto pev = maybe_pointer_event(to_address(arg)); |
58 | + if (pev == nullptr) |
59 | + return false; |
60 | + if (mir_pointer_event_action(pev) != mir_pointer_action_button_up) |
61 | + return false; |
62 | + if (mir_pointer_event_button_state(pev, button) == true) |
63 | + return false; |
64 | + if (mir_pointer_event_axis_value(pev, mir_pointer_axis_x) != pos.x.as_float()) |
65 | + return false; |
66 | + if (mir_pointer_event_axis_value(pev, mir_pointer_axis_y) != pos.y.as_float()) |
67 | + return false; |
68 | + return true; |
69 | +} |
70 | + |
71 | +MATCHER_P2(PointerAxisChange, scroll_axis, value, "") |
72 | +{ |
73 | + auto parg = to_address(arg); |
74 | + auto pev = maybe_pointer_event(parg); |
75 | + if (pev == nullptr) |
76 | + return false; |
77 | + if (mir_pointer_event_action(pev) != mir_pointer_action_motion) |
78 | + return false; |
79 | + if (mir_pointer_event_axis_value(pev, scroll_axis) != value) |
80 | + return false; |
81 | + return true; |
82 | +} |
83 | + |
84 | MATCHER_P2(TouchEvent, x, y, "") |
85 | { |
86 | auto tev = maybe_touch_event(to_address(arg)); |
87 | |
88 | === modified file 'src/CMakeLists.txt' |
89 | --- src/CMakeLists.txt 2015-09-17 08:57:46 +0000 |
90 | +++ src/CMakeLists.txt 2015-09-18 10:27:31 +0000 |
91 | @@ -49,4 +49,5 @@ |
92 | # We need the ABI versions in the tests |
93 | set(MIR_SERVER_GRAPHICS_PLATFORM_ABI ${MIR_SERVER_GRAPHICS_PLATFORM_ABI} PARENT_SCOPE) |
94 | set(MIR_CLIENT_PLATFORM_ABI ${MIR_CLIENT_PLATFORM_ABI} PARENT_SCOPE) |
95 | +set(MIR_INPUT_PLATFORM_VERSION_SCRIPT ${MIR_INPUT_PLATFORM_VERSION_SCRIPT} PARENT_SCOPE) |
96 | set(MIR_CLIENT_PLATFORM_VERSION ${MIR_CLIENT_PLATFORM_VERSION} PARENT_SCOPE) |
97 | |
98 | === modified file 'src/platforms/CMakeLists.txt' |
99 | --- src/platforms/CMakeLists.txt 2015-09-15 17:13:45 +0000 |
100 | +++ src/platforms/CMakeLists.txt 2015-09-18 10:27:31 +0000 |
101 | @@ -11,6 +11,8 @@ |
102 | set(MIR_SERVER_GRAPHICS_PLATFORM_ABI ${MIR_SERVER_GRAPHICS_PLATFORM_ABI} PARENT_SCOPE) |
103 | set(MIR_SERVER_GRAPHICS_PLATFORM_VERSION "MIR_GRAPHICS_PLATFORM_${MIR_SERVER_GRAPHICS_PLATFORM_ABI}") |
104 | set(MIR_SERVER_GRAPHICS_PLATFORM_VERSION ${MIR_SERVER_GRAPHICS_PLATFORM_VERSION} PARENT_SCOPE) |
105 | +set(MIR_INPUT_PLATFORM_VERSION_SCRIPT ${CMAKE_CURRENT_SOURCE_DIR}/input_platform_symbols.map) |
106 | +set(MIR_INPUT_PLATFORM_VERSION_SCRIPT ${MIR_INPUT_PLATFORM_VERSION_SCRIPT} PARENT_SCOPE) |
107 | |
108 | set(MIR_SERVER_PLATFORM_PATH |
109 | ${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_LIBDIR}/mir/server-platform |
110 | |
111 | === modified file 'src/platforms/evdev/CMakeLists.txt' |
112 | --- src/platforms/evdev/CMakeLists.txt 2015-09-08 03:25:06 +0000 |
113 | +++ src/platforms/evdev/CMakeLists.txt 2015-09-18 10:27:31 +0000 |
114 | @@ -1,5 +1,7 @@ |
115 | include_directories( |
116 | + ${LIBINPUT_CFLAGS} |
117 | ${PROJECT_SOURCE_DIR}/include/platform |
118 | + ${PROJECT_SOURCE_DIR}/src/include/platform # udev wrapper |
119 | ${PROJECT_SOURCE_DIR}/include/common |
120 | ${PROJECT_SOURCE_DIR}/include/client |
121 | ) |
122 | @@ -9,3 +11,30 @@ |
123 | input_modifier_utils.cpp |
124 | ) |
125 | |
126 | +add_library(mirplatforminputevdevobjects OBJECT |
127 | + libinput_device.cpp |
128 | + libinput_device_ptr.cpp |
129 | + libinput_ptr.cpp |
130 | + platform.cpp |
131 | + ) |
132 | + |
133 | +add_library(mirplatforminputevdev MODULE |
134 | + platform_factory.cpp |
135 | + $<TARGET_OBJECTS:mirplatforminputevdevobjects> |
136 | + $<TARGET_OBJECTS:mirevdevutilsobjects> |
137 | +) |
138 | + |
139 | +set_target_properties( |
140 | + mirplatforminputevdev PROPERTIES |
141 | + OUTPUT_NAME input-evdev |
142 | + LIBRARY_OUTPUT_DIRECTORY ${CMAKE_LIBRARY_OUTPUT_DIRECTORY}/server-modules |
143 | + PREFIX "" |
144 | + LINK_FLAGS "-Wl,--exclude-libs=ALL -Wl,--version-script,${MIR_INPUT_PLATFORM_VERSION_SCRIPT}" |
145 | +) |
146 | + |
147 | +target_link_libraries(mirplatforminputevdev |
148 | + mirplatform |
149 | + mirclient |
150 | + ${Boost_PROGRAM_OPTIONS_LIBRARY} |
151 | + ${LIBINPUT_LDFLAGS} ${LIBINPUT_LIBRARIES} |
152 | +) |
153 | |
154 | === modified file 'src/platforms/evdev/input_modifier_utils.cpp' |
155 | --- src/platforms/evdev/input_modifier_utils.cpp 2015-08-05 13:04:00 +0000 |
156 | +++ src/platforms/evdev/input_modifier_utils.cpp 2015-09-18 10:27:31 +0000 |
157 | @@ -40,7 +40,7 @@ |
158 | BOOST_THROW_EXCEPTION(std::runtime_error("Invalid mouse button")); |
159 | } |
160 | |
161 | -MirInputEventModifier mie::to_modifier(int32_t scan_code) |
162 | +MirInputEventModifiers mie::to_modifiers(int32_t scan_code) |
163 | { |
164 | switch(scan_code) |
165 | { |
166 | @@ -67,12 +67,15 @@ |
167 | case KEY_RIGHTSHIFT: |
168 | return mir_input_event_modifier_shift_right; |
169 | default: |
170 | + return MirInputEventModifiers{0}; |
171 | + } |
172 | +} |
173 | + |
174 | +MirInputEventModifiers mie::expand_modifiers(MirInputEventModifiers modifiers) |
175 | +{ |
176 | + if (modifiers == 0) |
177 | return mir_input_event_modifier_none; |
178 | - } |
179 | -} |
180 | |
181 | -MirInputEventModifiers mie::expand_modifiers(MirInputEventModifiers modifiers) |
182 | -{ |
183 | if ((modifiers & mir_input_event_modifier_alt_left) || (modifiers & mir_input_event_modifier_alt_right)) |
184 | modifiers |= mir_input_event_modifier_alt; |
185 | |
186 | |
187 | === modified file 'src/platforms/evdev/input_modifier_utils.h' |
188 | --- src/platforms/evdev/input_modifier_utils.h 2015-08-05 13:04:00 +0000 |
189 | +++ src/platforms/evdev/input_modifier_utils.h 2015-09-18 10:27:31 +0000 |
190 | @@ -28,7 +28,7 @@ |
191 | namespace evdev |
192 | { |
193 | MirPointerButton to_pointer_button(int button); |
194 | -MirInputEventModifier to_modifier(int32_t scan_code); |
195 | +MirInputEventModifiers to_modifiers(int32_t scan_code); |
196 | MirInputEventModifiers expand_modifiers(MirInputEventModifiers modifiers); |
197 | } |
198 | } |
199 | |
200 | === added file 'src/platforms/evdev/libinput_device.cpp' |
201 | --- src/platforms/evdev/libinput_device.cpp 1970-01-01 00:00:00 +0000 |
202 | +++ src/platforms/evdev/libinput_device.cpp 2015-09-18 10:27:31 +0000 |
203 | @@ -0,0 +1,347 @@ |
204 | +/* |
205 | + * Copyright © 2015 Canonical Ltd. |
206 | + * |
207 | + * This program is free software: you can redistribute it and/or modify it |
208 | + * under the terms of the GNU Lesser General Public License version 3, |
209 | + * as published by the Free Software Foundation. |
210 | + * |
211 | + * This program is distributed in the hope that it will be useful, |
212 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
213 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
214 | + * GNU Lesser General Public License for more details. |
215 | + * |
216 | + * You should have received a copy of the GNU Lesser General Public License |
217 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
218 | + * |
219 | + * Authored by: Andreas Pokorny <andreas.pokorny@canonical.com> |
220 | + */ |
221 | + |
222 | +#include "libinput_device.h" |
223 | +#include "libinput_ptr.h" |
224 | +#include "libinput_device_ptr.h" |
225 | +#include "input_modifier_utils.h" |
226 | +#include "evdev_device_detection.h" |
227 | + |
228 | +#include "mir/input/input_sink.h" |
229 | +#include "mir/input/input_report.h" |
230 | +#include "mir/input/device_capability.h" |
231 | +#include "mir/input/input_device_info.h" |
232 | +#include "mir/events/event_builders.h" |
233 | +#include "mir/geometry/displacement.h" |
234 | +#include "mir/dispatch/dispatchable.h" |
235 | +#include "mir/fd.h" |
236 | + |
237 | +#include <libinput.h> |
238 | +#include <linux/input.h> // only used to get constants for input reports |
239 | + |
240 | +#include <cstring> |
241 | +#include <chrono> |
242 | +#include <sstream> |
243 | +#include <algorithm> |
244 | + |
245 | +namespace md = mir::dispatch; |
246 | +namespace mi = mir::input; |
247 | +namespace mie = mi::evdev; |
248 | +using namespace std::literals::chrono_literals; |
249 | + |
250 | +namespace |
251 | +{ |
252 | + |
253 | +void null_deleter(MirEvent *) {} |
254 | + |
255 | +} |
256 | + |
257 | +mie::LibInputDevice::LibInputDevice(std::shared_ptr<mi::InputReport> const& report, char const* path, |
258 | + LibInputDevicePtr dev) |
259 | + : report{report}, accumulated_touch_event{nullptr, null_deleter}, pointer_pos{0, 0}, modifier_state{0}, |
260 | + button_state{0} |
261 | +{ |
262 | + add_device_of_group(path, std::move(dev)); |
263 | +} |
264 | + |
265 | +void mie::LibInputDevice::add_device_of_group(char const* path, LibInputDevicePtr dev) |
266 | +{ |
267 | + paths.emplace_back(path); |
268 | + devices.emplace_back(std::move(dev)); |
269 | +} |
270 | + |
271 | +bool mie::LibInputDevice::is_in_group(char const* path) |
272 | +{ |
273 | + return end(paths) != find(begin(paths), end(paths), std::string{path}); |
274 | +} |
275 | + |
276 | +mie::LibInputDevice::~LibInputDevice() = default; |
277 | + |
278 | +void mie::LibInputDevice::start(InputSink* sink, EventBuilder* builder) |
279 | +{ |
280 | + this->sink = sink; |
281 | + this->builder = builder; |
282 | +} |
283 | + |
284 | +void mie::LibInputDevice::stop() |
285 | +{ |
286 | + sink = nullptr; |
287 | + builder = nullptr; |
288 | +} |
289 | + |
290 | +void mie::LibInputDevice::process_event(libinput_event* event) |
291 | +{ |
292 | + if (!sink) |
293 | + return; |
294 | + |
295 | + switch(libinput_event_get_type(event)) |
296 | + { |
297 | + case LIBINPUT_EVENT_KEYBOARD_KEY: |
298 | + sink->handle_input(*convert_event(libinput_event_get_keyboard_event(event))); |
299 | + break; |
300 | + case LIBINPUT_EVENT_POINTER_MOTION: |
301 | + sink->handle_input(*convert_motion_event(libinput_event_get_pointer_event(event))); |
302 | + break; |
303 | + case LIBINPUT_EVENT_POINTER_MOTION_ABSOLUTE: |
304 | + sink->handle_input(*convert_absolute_motion_event(libinput_event_get_pointer_event(event))); |
305 | + break; |
306 | + case LIBINPUT_EVENT_POINTER_BUTTON: |
307 | + sink->handle_input(*convert_button_event(libinput_event_get_pointer_event(event))); |
308 | + break; |
309 | + case LIBINPUT_EVENT_POINTER_AXIS: |
310 | + sink->handle_input(*convert_axis_event(libinput_event_get_pointer_event(event))); |
311 | + break; |
312 | + // touch events are processed as a batch of changes over all touch pointts |
313 | + case LIBINPUT_EVENT_TOUCH_DOWN: |
314 | + add_touch_down_event(libinput_event_get_touch_event(event)); |
315 | + break; |
316 | + case LIBINPUT_EVENT_TOUCH_UP: |
317 | + add_touch_up_event(libinput_event_get_touch_event(event)); |
318 | + break; |
319 | + case LIBINPUT_EVENT_TOUCH_MOTION: |
320 | + add_touch_motion_event(libinput_event_get_touch_event(event)); |
321 | + break; |
322 | + case LIBINPUT_EVENT_TOUCH_CANCEL: |
323 | + // Not yet provided by libinput. |
324 | + break; |
325 | + case LIBINPUT_EVENT_TOUCH_FRAME: |
326 | + sink->handle_input(get_accumulated_touch_event(0ns)); |
327 | + accumulated_touch_event.reset(); |
328 | + break; |
329 | + default: |
330 | + break; |
331 | + } |
332 | +} |
333 | + |
334 | +mir::EventUPtr mie::LibInputDevice::convert_event(libinput_event_keyboard* keyboard) |
335 | +{ |
336 | + std::chrono::nanoseconds const time = std::chrono::microseconds(libinput_event_keyboard_get_time_usec(keyboard)); |
337 | + auto const action = libinput_event_keyboard_get_key_state(keyboard) == LIBINPUT_KEY_STATE_PRESSED ? |
338 | + mir_keyboard_action_down : |
339 | + mir_keyboard_action_up; |
340 | + auto const code = libinput_event_keyboard_get_key(keyboard); |
341 | + report->received_event_from_kernel(time.count(), EV_KEY, code, action); |
342 | + |
343 | + auto event = builder->key_event(time, |
344 | + action, |
345 | + xkb_keysym_t{0}, |
346 | + code, |
347 | + mie::expand_modifiers(modifier_state)); |
348 | + |
349 | + if (action == mir_keyboard_action_down) |
350 | + modifier_state |= mie::to_modifiers(code); |
351 | + else |
352 | + modifier_state &= ~mie::to_modifiers(code); |
353 | + |
354 | + return event; |
355 | +} |
356 | + |
357 | +mir::EventUPtr mie::LibInputDevice::convert_button_event(libinput_event_pointer* pointer) |
358 | +{ |
359 | + std::chrono::nanoseconds const time = std::chrono::microseconds(libinput_event_pointer_get_time_usec(pointer)); |
360 | + auto const button = libinput_event_pointer_get_button(pointer); |
361 | + auto const action = (libinput_event_pointer_get_button_state(pointer) == LIBINPUT_BUTTON_STATE_PRESSED)? |
362 | + mir_pointer_action_button_down : mir_pointer_action_button_up; |
363 | + |
364 | + auto const pointer_button = mie::to_pointer_button(button); |
365 | + auto const relative_x_value = 0.0f; |
366 | + auto const relative_y_value = 0.0f; |
367 | + auto const hscroll_value = 0.0f; |
368 | + auto const vscroll_value = 0.0f; |
369 | + |
370 | + report->received_event_from_kernel(time.count(), EV_KEY, pointer_button, action); |
371 | + |
372 | + if (action == mir_pointer_action_button_down) |
373 | + button_state = MirPointerButton(button_state | uint32_t(pointer_button)); |
374 | + else |
375 | + button_state = MirPointerButton(button_state & ~uint32_t(pointer_button)); |
376 | + |
377 | + auto event = builder->pointer_event(time, mie::expand_modifiers(modifier_state), action, button_state, |
378 | + pointer_pos.x.as_float(), pointer_pos.y.as_float(), hscroll_value, |
379 | + vscroll_value, relative_x_value, relative_y_value); |
380 | + |
381 | + return event; |
382 | +} |
383 | + |
384 | +mir::EventUPtr mie::LibInputDevice::convert_motion_event(libinput_event_pointer* pointer) |
385 | +{ |
386 | + std::chrono::nanoseconds const time = std::chrono::microseconds(libinput_event_pointer_get_time_usec(pointer)); |
387 | + auto const action = mir_pointer_action_motion; |
388 | + auto const hscroll_value = 0.0f; |
389 | + auto const vscroll_value = 0.0f; |
390 | + |
391 | + report->received_event_from_kernel(time.count(), EV_REL, 0, 0); |
392 | + |
393 | + mir::geometry::Displacement const movement{ |
394 | + libinput_event_pointer_get_dx(pointer), |
395 | + libinput_event_pointer_get_dy(pointer)}; |
396 | + pointer_pos = pointer_pos + movement; |
397 | + |
398 | + sink->confine_pointer(pointer_pos); |
399 | + |
400 | + auto event = builder->pointer_event(time, mie::expand_modifiers(modifier_state), action, button_state, |
401 | + pointer_pos.x.as_float(), pointer_pos.y.as_float(), hscroll_value, |
402 | + vscroll_value, movement.dx.as_float(), movement.dy.as_float()); |
403 | + |
404 | + return event; |
405 | +} |
406 | + |
407 | +mir::EventUPtr mie::LibInputDevice::convert_absolute_motion_event(libinput_event_pointer* pointer) |
408 | +{ |
409 | + // a pointing device that emits absolute coordinates |
410 | + std::chrono::nanoseconds const time = std::chrono::microseconds(libinput_event_pointer_get_time_usec(pointer)); |
411 | + auto const action = mir_pointer_action_motion; |
412 | + auto const hscroll_value = 0.0f; |
413 | + auto const vscroll_value = 0.0f; |
414 | + |
415 | + report->received_event_from_kernel(time.count(), EV_ABS, 0, 0); |
416 | + auto const old_pointer_pos = pointer_pos; |
417 | + pointer_pos = mir::geometry::Point{ |
418 | + libinput_event_pointer_get_absolute_x(pointer), |
419 | + libinput_event_pointer_get_absolute_y(pointer)}; |
420 | + auto const movement = pointer_pos - old_pointer_pos; |
421 | + |
422 | + sink->confine_pointer(pointer_pos); |
423 | + |
424 | + auto event = builder->pointer_event(time, mie::expand_modifiers(modifier_state), action, button_state, |
425 | + pointer_pos.x.as_float(), pointer_pos.y.as_float(), hscroll_value, |
426 | + vscroll_value, movement.dx.as_float(), movement.dy.as_float()); |
427 | + return event; |
428 | +} |
429 | + |
430 | +mir::EventUPtr mie::LibInputDevice::convert_axis_event(libinput_event_pointer* pointer) |
431 | +{ |
432 | + std::chrono::nanoseconds const time = std::chrono::microseconds(libinput_event_pointer_get_time_usec(pointer)); |
433 | + auto const action = mir_pointer_action_motion; |
434 | + auto const relative_x_value = 0.0f; |
435 | + auto const relative_y_value = 0.0f; |
436 | + auto const hscroll_value = libinput_event_pointer_has_axis(pointer, LIBINPUT_POINTER_AXIS_SCROLL_HORIZONTAL) |
437 | + ? libinput_event_pointer_get_axis_value(pointer, LIBINPUT_POINTER_AXIS_SCROLL_HORIZONTAL) |
438 | + : 0.0f; |
439 | + auto const vscroll_value = libinput_event_pointer_has_axis(pointer, LIBINPUT_POINTER_AXIS_SCROLL_VERTICAL) |
440 | + ? libinput_event_pointer_get_axis_value(pointer, LIBINPUT_POINTER_AXIS_SCROLL_VERTICAL) |
441 | + : 0.0f; |
442 | + |
443 | + report->received_event_from_kernel(time.count(), EV_REL, 0, 0); |
444 | + auto event = builder->pointer_event(time, mie::expand_modifiers(modifier_state), action, button_state, |
445 | + pointer_pos.x.as_float(), pointer_pos.y.as_float(), hscroll_value, |
446 | + vscroll_value, relative_x_value, relative_y_value); |
447 | + return event; |
448 | +} |
449 | + |
450 | +MirEvent& mie::LibInputDevice::get_accumulated_touch_event(std::chrono::nanoseconds timestamp) |
451 | +{ |
452 | + if (!accumulated_touch_event) |
453 | + { |
454 | + report->received_event_from_kernel(timestamp.count(), EV_SYN, 0, 0); |
455 | + accumulated_touch_event = builder->touch_event(timestamp, mie::expand_modifiers(modifier_state)); |
456 | + } |
457 | + |
458 | + return *accumulated_touch_event; |
459 | +} |
460 | + |
461 | +void mie::LibInputDevice::add_touch_down_event(libinput_event_touch* touch) |
462 | +{ |
463 | + std::chrono::nanoseconds const time = std::chrono::microseconds(libinput_event_touch_get_time_usec(touch)); |
464 | + auto& event = get_accumulated_touch_event(time); |
465 | + |
466 | + MirTouchId const id = libinput_event_touch_get_slot(touch); |
467 | + auto const action = mir_touch_action_down; |
468 | + // TODO make libinput indicate tool type |
469 | + auto const tool = mir_touch_tooltype_finger; |
470 | + float const pressure = libinput_event_touch_get_pressure(touch); |
471 | + auto const screen = sink->bounding_rectangle(); |
472 | + uint32_t const width = screen.size.width.as_int(); |
473 | + uint32_t const height = screen.size.height.as_int(); |
474 | + float const x = libinput_event_touch_get_x_transformed(touch, width); |
475 | + float const y = libinput_event_touch_get_y_transformed(touch, height); |
476 | + float const major = libinput_event_touch_get_major_transformed(touch, width, height); |
477 | + float const minor = libinput_event_touch_get_minor_transformed(touch, width, height); |
478 | + // TODO why do we send size to clients? |
479 | + float const size = std::max(major, minor); |
480 | + |
481 | + // TODO extend for touch screens that provide orientation |
482 | + builder->add_touch(event, id, action, tool, x, y, pressure, major, minor, size); |
483 | +} |
484 | + |
485 | +void mie::LibInputDevice::add_touch_up_event(libinput_event_touch* touch) |
486 | +{ |
487 | + std::chrono::nanoseconds const time = std::chrono::microseconds(libinput_event_touch_get_time_usec(touch)); |
488 | + auto& event = get_accumulated_touch_event(time); |
489 | + MirTouchId const id = libinput_event_touch_get_slot(touch); |
490 | + auto const action = mir_touch_action_up; |
491 | + auto const tool = mir_touch_tooltype_finger; // TODO make libinput indicate tool type |
492 | + |
493 | + float const pressure = 0.0f; |
494 | + float const major = 0.0f; |
495 | + float const minor = 0.0f; |
496 | + float const size = 0.0f; |
497 | + // TODO extend for touch screens that provide orientation and major/minor |
498 | + builder->add_touch(event, id, action, tool, libinput_event_touch_get_x(touch), libinput_event_touch_get_y(touch), |
499 | + pressure, major, minor, size); |
500 | +} |
501 | + |
502 | +void mie::LibInputDevice::add_touch_motion_event(libinput_event_touch* touch) |
503 | +{ |
504 | + std::chrono::nanoseconds const time = std::chrono::microseconds(libinput_event_touch_get_time_usec(touch)); |
505 | + auto& event = get_accumulated_touch_event(time); |
506 | + |
507 | + MirTouchId const id = libinput_event_touch_get_slot(touch); |
508 | + auto const action = mir_touch_action_change; |
509 | + auto const tool = mir_touch_tooltype_finger; // TODO make libinput indicate tool type |
510 | + float const pressure = libinput_event_touch_get_pressure(touch); |
511 | + auto const screen = sink->bounding_rectangle(); |
512 | + uint32_t const width = screen.size.width.as_int(); |
513 | + uint32_t const height = screen.size.height.as_int(); |
514 | + float const x = libinput_event_touch_get_x_transformed(touch, width); |
515 | + float const y = libinput_event_touch_get_y_transformed(touch, height); |
516 | + float const major = libinput_event_touch_get_major_transformed(touch, width, height); |
517 | + float const minor = libinput_event_touch_get_minor_transformed(touch, width, height); |
518 | + // TODO why do we send size to clients? |
519 | + float const size = std::max(major, minor); |
520 | + |
521 | + // TODO extend for touch screens that provide orientation |
522 | + builder->add_touch(event, id, action, tool, x, y, pressure, major, minor, size); |
523 | +} |
524 | + |
525 | +mi::InputDeviceInfo mie::LibInputDevice::get_device_info() |
526 | +{ |
527 | + auto dev = device(); |
528 | + std::string name = libinput_device_get_name(dev); |
529 | + std::stringstream unique_id(name); |
530 | + unique_id << '-' << libinput_device_get_sysname(dev) << '-' << |
531 | + libinput_device_get_id_vendor(dev) << '-' << |
532 | + libinput_device_get_id_product(dev); |
533 | + mi::DeviceCapabilities caps; |
534 | + |
535 | + for (auto const& path : paths) |
536 | + caps |= mie::detect_device_capabilities(path.c_str()); |
537 | + |
538 | + return mi::InputDeviceInfo{0, name, unique_id.str(), caps}; |
539 | +} |
540 | + |
541 | +libinput_device_group* mie::LibInputDevice::group() |
542 | +{ |
543 | + return libinput_device_get_device_group(device()); |
544 | +} |
545 | + |
546 | +libinput_device* mie::LibInputDevice::device() |
547 | +{ |
548 | + return devices.front().get(); |
549 | +} |
550 | + |
551 | |
552 | === added file 'src/platforms/evdev/libinput_device.h' |
553 | --- src/platforms/evdev/libinput_device.h 1970-01-01 00:00:00 +0000 |
554 | +++ src/platforms/evdev/libinput_device.h 2015-09-18 10:27:31 +0000 |
555 | @@ -0,0 +1,90 @@ |
556 | +/* |
557 | + * Copyright © 2015 Canonical Ltd. |
558 | + * |
559 | + * This program is free software: you can redistribute it and/or modify it |
560 | + * under the terms of the GNU Lesser General Public License version 3, |
561 | + * as published by the Free Software Foundation. |
562 | + * |
563 | + * This program is distributed in the hope that it will be useful, |
564 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
565 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
566 | + * GNU Lesser General Public License for more details. |
567 | + * |
568 | + * You should have received a copy of the GNU Lesser General Public License |
569 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
570 | + * |
571 | + * Authored by: Andreas Pokorny <andreas.pokorny@canonical.com> |
572 | + */ |
573 | + |
574 | +#ifndef MIR_INPUT_EVDEV_LIBINPUT_DEVICE_H_ |
575 | +#define MIR_INPUT_EVDEV_LIBINPUT_DEVICE_H_ |
576 | + |
577 | +#include "libinput_ptr.h" |
578 | +#include "libinput_device_ptr.h" |
579 | + |
580 | +#include "mir/input/event_builder.h" |
581 | +#include "mir/input/input_device.h" |
582 | +#include "mir/geometry/point.h" |
583 | + |
584 | +#include <vector> |
585 | + |
586 | +struct libinput_event; |
587 | +struct libinput_event_keyboard; |
588 | +struct libinput_event_touch; |
589 | +struct libinput_event_pointer; |
590 | +struct libinput_device_group; |
591 | + |
592 | +namespace mir |
593 | +{ |
594 | +namespace input |
595 | +{ |
596 | +class InputReport; |
597 | +namespace evdev |
598 | +{ |
599 | +struct PointerState; |
600 | +struct KeyboardState; |
601 | + |
602 | +class LibInputDevice : public input::InputDevice |
603 | +{ |
604 | +public: |
605 | + LibInputDevice(std::shared_ptr<InputReport> const& report, char const* path, LibInputDevicePtr dev); |
606 | + ~LibInputDevice(); |
607 | + void start(InputSink* sink, EventBuilder* builder) override; |
608 | + void stop() override; |
609 | + virtual InputDeviceInfo get_device_info() override; |
610 | + |
611 | + void process_event(libinput_event* event); |
612 | + ::libinput_device* device(); |
613 | + ::libinput_device_group* group(); |
614 | + void add_device_of_group(char const* path, LibInputDevicePtr ptr); |
615 | + bool is_in_group(char const* path); |
616 | +private: |
617 | + EventUPtr convert_event(libinput_event_keyboard* keyboard); |
618 | + EventUPtr convert_button_event(libinput_event_pointer* pointer); |
619 | + EventUPtr convert_motion_event(libinput_event_pointer* pointer); |
620 | + EventUPtr convert_absolute_motion_event(libinput_event_pointer* pointer); |
621 | + EventUPtr convert_axis_event(libinput_event_pointer* pointer); |
622 | + void add_touch_down_event(libinput_event_touch* touch); |
623 | + void add_touch_up_event(libinput_event_touch* touch); |
624 | + void add_touch_motion_event(libinput_event_touch* touch); |
625 | + MirEvent& get_accumulated_touch_event(std::chrono::nanoseconds timestamp); |
626 | + |
627 | + std::shared_ptr<InputReport> report; |
628 | + std::shared_ptr<::libinput> lib; |
629 | + std::vector<std::string> paths; |
630 | + std::vector<LibInputDevicePtr> devices; |
631 | + std::shared_ptr<dispatch::Dispatchable> dispatchable_fd; |
632 | + |
633 | + InputSink* sink{nullptr}; |
634 | + EventBuilder* builder{nullptr}; |
635 | + EventUPtr accumulated_touch_event; |
636 | + |
637 | + mir::geometry::Point pointer_pos; |
638 | + MirInputEventModifiers modifier_state; |
639 | + MirPointerButtons button_state; |
640 | +}; |
641 | +} |
642 | +} |
643 | +} |
644 | + |
645 | +#endif |
646 | |
647 | === added file 'src/platforms/evdev/libinput_device_ptr.cpp' |
648 | --- src/platforms/evdev/libinput_device_ptr.cpp 1970-01-01 00:00:00 +0000 |
649 | +++ src/platforms/evdev/libinput_device_ptr.cpp 2015-09-18 10:27:31 +0000 |
650 | @@ -0,0 +1,30 @@ |
651 | +/* |
652 | + * Copyright © 2015 Canonical Ltd. |
653 | + * |
654 | + * This program is free software: you can redistribute it and/or modify it |
655 | + * under the terms of the GNU Lesser General Public License version 3, |
656 | + * as published by the Free Software Foundation. |
657 | + * |
658 | + * This program is distributed in the hope that it will be useful, |
659 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
660 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
661 | + * GNU Lesser General Public License for more details. |
662 | + * |
663 | + * You should have received a copy of the GNU Lesser General Public License |
664 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
665 | + * |
666 | + * Authored by: Andreas Pokorny <andreas.pokorny@canonical.com> |
667 | + */ |
668 | + |
669 | +#include "libinput.h" |
670 | +#include "libinput_device_ptr.h" |
671 | + |
672 | +namespace mie = mir::input::evdev; |
673 | + |
674 | +mie::LibInputDevicePtr mie::make_libinput_device(libinput* lib, char const* path) |
675 | +{ |
676 | + auto ret = mie::LibInputDevicePtr(::libinput_path_add_device(lib, path), libinput_device_unref); |
677 | + if (ret) |
678 | + libinput_device_ref(ret.get()); |
679 | + return ret; |
680 | +} |
681 | |
682 | === added file 'src/platforms/evdev/libinput_device_ptr.h' |
683 | --- src/platforms/evdev/libinput_device_ptr.h 1970-01-01 00:00:00 +0000 |
684 | +++ src/platforms/evdev/libinput_device_ptr.h 2015-09-18 10:27:31 +0000 |
685 | @@ -0,0 +1,40 @@ |
686 | +/* |
687 | + * Copyright © 2015 Canonical Ltd. |
688 | + * |
689 | + * This program is free software: you can redistribute it and/or modify it |
690 | + * under the terms of the GNU Lesser General Public License version 3, |
691 | + * as published by the Free Software Foundation. |
692 | + * |
693 | + * This program is distributed in the hope that it will be useful, |
694 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
695 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
696 | + * GNU Lesser General Public License for more details. |
697 | + * |
698 | + * You should have received a copy of the GNU Lesser General Public License |
699 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
700 | + * |
701 | + * Authored by: Andreas Pokorny <andreas.pokorny@canonical.com> |
702 | + */ |
703 | + |
704 | +#ifndef MIR_INPUT_EVDEV_LIBINPUT_DEVICE_PTR_H_ |
705 | +#define MIR_INPUT_EVDEV_LIBINPUT_DEVICE_PTR_H_ |
706 | + |
707 | +#include <memory> |
708 | + |
709 | +struct libinput_device; |
710 | +struct libinput; |
711 | + |
712 | +namespace mir |
713 | +{ |
714 | +namespace input |
715 | +{ |
716 | +namespace evdev |
717 | +{ |
718 | +using LibInputDevicePtr = std::unique_ptr<libinput_device, libinput_device*(*)(libinput_device*)>; |
719 | + |
720 | +LibInputDevicePtr make_libinput_device(libinput* lib, char const* path); |
721 | +} |
722 | +} |
723 | +} |
724 | + |
725 | +#endif |
726 | |
727 | === added file 'src/platforms/evdev/libinput_ptr.cpp' |
728 | --- src/platforms/evdev/libinput_ptr.cpp 1970-01-01 00:00:00 +0000 |
729 | +++ src/platforms/evdev/libinput_ptr.cpp 2015-09-18 10:27:31 +0000 |
730 | @@ -0,0 +1,47 @@ |
731 | +/* |
732 | + * Copyright © 2015 Canonical Ltd. |
733 | + * |
734 | + * This program is free software: you can redistribute it and/or modify it |
735 | + * under the terms of the GNU Lesser General Public License version 3, |
736 | + * as published by the Free Software Foundation. |
737 | + * |
738 | + * This program is distributed in the hope that it will be useful, |
739 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
740 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
741 | + * GNU Lesser General Public License for more details. |
742 | + * |
743 | + * You should have received a copy of the GNU Lesser General Public License |
744 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
745 | + * |
746 | + * Authored by: Andreas Pokorny <andreas.pokorny@canonical.com> |
747 | + */ |
748 | + |
749 | +#include "libinput.h" |
750 | +#include "libinput_ptr.h" |
751 | + |
752 | +#include <sys/types.h> |
753 | +#include <sys/stat.h> |
754 | +#include <fcntl.h> |
755 | +#include <unistd.h> |
756 | + |
757 | +namespace mie = mir::input::evdev; |
758 | + |
759 | +namespace |
760 | +{ |
761 | +int fd_open(const char* path, int flags, void* /*userdata*/) |
762 | +{ |
763 | + return ::open(path, flags); |
764 | +} |
765 | + |
766 | +void fd_close(int fd, void* /*userdata*/) |
767 | +{ |
768 | + ::close(fd); |
769 | +} |
770 | + |
771 | +const libinput_interface fd_ops = {fd_open, fd_close}; |
772 | +} |
773 | + |
774 | +mie::LibInputPtr mie::make_libinput() |
775 | +{ |
776 | + return mie::LibInputPtr{libinput_path_create_context(&fd_ops, nullptr),libinput_unref}; |
777 | +} |
778 | |
779 | === added file 'src/platforms/evdev/libinput_ptr.h' |
780 | --- src/platforms/evdev/libinput_ptr.h 1970-01-01 00:00:00 +0000 |
781 | +++ src/platforms/evdev/libinput_ptr.h 2015-09-18 10:27:31 +0000 |
782 | @@ -0,0 +1,42 @@ |
783 | +/* |
784 | + * Copyright © 2015 Canonical Ltd. |
785 | + * |
786 | + * This program is free software: you can redistribute it and/or modify it |
787 | + * under the terms of the GNU Lesser General Public License version 3, |
788 | + * as published by the Free Software Foundation. |
789 | + * |
790 | + * This program is distributed in the hope that it will be useful, |
791 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
792 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
793 | + * GNU Lesser General Public License for more details. |
794 | + * |
795 | + * You should have received a copy of the GNU Lesser General Public License |
796 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
797 | + * |
798 | + * Authored by: Andreas Pokorny <andreas.pokorny@canonical.com> |
799 | + */ |
800 | + |
801 | +#ifndef MIR_INPUT_EVDEV_LIBINPUT_PTR_H_ |
802 | +#define MIR_INPUT_EVDEV_LIBINPUT_PTR_H_ |
803 | + |
804 | +#include "mir_toolkit/event.h" |
805 | + |
806 | +#include <memory> |
807 | +#include <list> |
808 | + |
809 | +struct libinput; |
810 | + |
811 | +namespace mir |
812 | +{ |
813 | +namespace input |
814 | +{ |
815 | +namespace evdev |
816 | +{ |
817 | +using LibInputPtr = std::unique_ptr<libinput, libinput*(*)(libinput*)>; |
818 | + |
819 | +LibInputPtr make_libinput(); |
820 | +} |
821 | +} |
822 | +} |
823 | + |
824 | +#endif |
825 | |
826 | === added file 'src/platforms/evdev/platform.cpp' |
827 | --- src/platforms/evdev/platform.cpp 1970-01-01 00:00:00 +0000 |
828 | +++ src/platforms/evdev/platform.cpp 2015-09-18 10:27:31 +0000 |
829 | @@ -0,0 +1,238 @@ |
830 | +/* |
831 | + * Copyright © 2015 Canonical Ltd. |
832 | + * |
833 | + * This program is free software: you can redistribute it and/or modify it |
834 | + * under the terms of the GNU Lesser General Public License version 3, |
835 | + * as published by the Free Software Foundation. |
836 | + * |
837 | + * This program is distributed in the hope that it will be useful, |
838 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
839 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
840 | + * GNU Lesser General Public License for more details. |
841 | + * |
842 | + * You should have received a copy of the GNU Lesser General Public License |
843 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
844 | + * |
845 | + * Authored by: Andreas Pokorny <andreas.pokorny@canonical.com> |
846 | + */ |
847 | + |
848 | +#include "platform.h" |
849 | +#include "libinput_device.h" |
850 | +#include "libinput_ptr.h" |
851 | +#include "mir/udev/wrapper.h" |
852 | +#include "mir/dispatch/dispatchable.h" |
853 | +#include "mir/dispatch/readable_fd.h" |
854 | +#include "mir/dispatch/multiplexing_dispatchable.h" |
855 | +#include "mir/module_properties.h" |
856 | + |
857 | +#include "mir/input/input_device_registry.h" |
858 | +#include "mir/input/input_device.h" |
859 | +#include "mir/input/input_report.h" |
860 | +#include "mir/fd.h" |
861 | + |
862 | +#define MIR_LOG_COMPONENT "evdev-input" |
863 | +#include "mir/log.h" |
864 | + |
865 | +#include <boost/exception/errinfo_errno.hpp> |
866 | +#include <boost/throw_exception.hpp> |
867 | + |
868 | +#include <libinput.h> |
869 | + |
870 | +namespace mi = mir::input; |
871 | +namespace md = mir::dispatch; |
872 | +namespace mu = mir::udev; |
873 | +namespace mie = mi::evdev; |
874 | + |
875 | +mie::Platform::Platform(std::shared_ptr<InputDeviceRegistry> const& registry, |
876 | + std::shared_ptr<InputReport> const& report, |
877 | + std::unique_ptr<udev::Context>&& udev_context, |
878 | + std::unique_ptr<udev::Monitor>&& monitor) |
879 | + : report(report), udev_context(std::move(udev_context)), monitor(std::move(monitor)), |
880 | + input_device_registry(registry), |
881 | + platform_dispatchable{std::make_shared<md::MultiplexingDispatchable>()}, |
882 | + monitor_dispatchable{ |
883 | + std::make_shared<md::ReadableFd>( |
884 | + Fd{IntOwnedFd{this->monitor->fd()}}, |
885 | + [this](){process_changes();} |
886 | + )}, |
887 | + lib{make_libinput()}, |
888 | + libinput_dispatchable{ |
889 | + std::make_shared<md::ReadableFd>( |
890 | + Fd{IntOwnedFd{libinput_get_fd(lib.get())}}, |
891 | + [this](){process_input_events();} |
892 | + )} |
893 | +{ |
894 | + this->monitor->filter_by_subsystem("input"); |
895 | + this->monitor->enable(); |
896 | + |
897 | +} |
898 | + |
899 | +std::shared_ptr<mir::dispatch::Dispatchable> mie::Platform::dispatchable() |
900 | +{ |
901 | + return platform_dispatchable; |
902 | +} |
903 | + |
904 | +void mie::Platform::start() |
905 | +{ |
906 | + platform_dispatchable->add_watch(monitor_dispatchable); |
907 | + platform_dispatchable->add_watch(libinput_dispatchable); |
908 | + scan_for_devices(); |
909 | +} |
910 | + |
911 | +void mie::Platform::process_input_events() |
912 | +{ |
913 | + int status = libinput_dispatch(lib.get()); |
914 | + if (status != 0) |
915 | + BOOST_THROW_EXCEPTION(boost::enable_error_info(std::runtime_error("libinput_dispatch_failed")) |
916 | + << boost::errinfo_errno(-status)); |
917 | + |
918 | + using EventType = std::unique_ptr<libinput_event,void(*)(libinput_event*)>; |
919 | + auto next_event = [lilib=lib.get()] |
920 | + { |
921 | + return EventType(libinput_get_event(lilib), libinput_event_destroy); |
922 | + }; |
923 | + |
924 | + while(auto ev = next_event()) |
925 | + { |
926 | + auto dev = find_device( |
927 | + libinput_device_get_device_group( |
928 | + libinput_event_get_device(ev.get()) |
929 | + )); |
930 | + if (dev != end(devices)) |
931 | + (*dev)->process_event(ev.get()); |
932 | + } |
933 | +} |
934 | + |
935 | +void mie::Platform::process_changes() |
936 | +{ |
937 | + monitor->process_events( |
938 | + [this](mu::Monitor::EventType event, mu::Device const& dev) |
939 | + { |
940 | + if (!dev.devnode()) |
941 | + return; |
942 | + if (event == mu::Monitor::ADDED) |
943 | + { |
944 | + log_info("udev:device added %s", dev.devnode()); |
945 | + device_added(dev); |
946 | + } |
947 | + if (event == mu::Monitor::REMOVED) |
948 | + { |
949 | + log_info("udev:device removed %s", dev.devnode()); |
950 | + device_removed(dev); |
951 | + } |
952 | + if (event == mu::Monitor::CHANGED) |
953 | + { |
954 | + log_info("udev:device changed %s", dev.devnode()); |
955 | + device_changed(dev); |
956 | + } |
957 | + }); |
958 | +} |
959 | + |
960 | +void mie::Platform::scan_for_devices() |
961 | +{ |
962 | + mu::Enumerator input_enumerator{udev_context}; |
963 | + input_enumerator.match_subsystem("input"); |
964 | + input_enumerator.scan_devices(); |
965 | + |
966 | + for (auto& device : input_enumerator) |
967 | + { |
968 | + if (device.devnode() != nullptr) |
969 | + { |
970 | + log_info("udev:device added %s", device.devnode()); |
971 | + device_added(device); |
972 | + } |
973 | + } |
974 | +} |
975 | + |
976 | +void mie::Platform::device_added(mu::Device const& dev) |
977 | +{ |
978 | + if (end(devices) != find_device(dev.devnode())) |
979 | + return; |
980 | + |
981 | + auto device_ptr = make_libinput_device(lib.get(), dev.devnode()); |
982 | + |
983 | + // libinput might refuse to open certain devices nodes like /dev/input/mice |
984 | + // or ignore devices with odd evdev bits/capabilities set |
985 | + if (!device_ptr) |
986 | + { |
987 | + report->failed_to_open_input_device(dev.devnode(), "evdev-input"); |
988 | + log_info("libinput refused to open device %s", dev.devnode()); |
989 | + return; |
990 | + } |
991 | + |
992 | + auto device_it = find_device(libinput_device_get_device_group(device_ptr.get())); |
993 | + if (end(devices) != device_it) |
994 | + { |
995 | + (*device_it)->add_device_of_group(dev.devnode(), move(device_ptr)); |
996 | + log_debug("Device %s is part of an already opened device group", dev.devnode()); |
997 | + return; |
998 | + } |
999 | + |
1000 | + try |
1001 | + { |
1002 | + devices.emplace_back(std::make_shared<mie::LibInputDevice>(report, dev.devnode(), move(device_ptr))); |
1003 | + |
1004 | + input_device_registry->add_device(devices.back()); |
1005 | + |
1006 | + report->opened_input_device(dev.devnode(), "evdev-input"); |
1007 | + } catch(...) |
1008 | + { |
1009 | + mir::log_error("Failure opening device %s", dev.devnode()); |
1010 | + report->failed_to_open_input_device(dev.devnode(), "evdev-input"); |
1011 | + } |
1012 | +} |
1013 | + |
1014 | +void mie::Platform::device_removed(mu::Device const& dev) |
1015 | +{ |
1016 | + auto known_device_pos = find_device(dev.devnode()); |
1017 | + |
1018 | + if (known_device_pos == end(devices)) |
1019 | + return; |
1020 | + |
1021 | + input_device_registry->remove_device(*known_device_pos); |
1022 | + devices.erase(known_device_pos); |
1023 | +} |
1024 | + |
1025 | + |
1026 | +auto mie::Platform::find_device(char const* devnode) -> decltype(devices)::iterator |
1027 | +{ |
1028 | + return std::find_if( |
1029 | + begin(devices), |
1030 | + end(devices), |
1031 | + [devnode](auto const& item) |
1032 | + { |
1033 | + return item->is_in_group(devnode); |
1034 | + } |
1035 | + ); |
1036 | +} |
1037 | + |
1038 | +auto mie::Platform::find_device(libinput_device_group const* devgroup) -> decltype(devices)::iterator |
1039 | +{ |
1040 | + if (devgroup == nullptr) |
1041 | + return end(devices); |
1042 | + return std::find_if( |
1043 | + begin(devices), |
1044 | + end(devices), |
1045 | + [devgroup](auto const& item) |
1046 | + { |
1047 | + return devgroup == item->group(); |
1048 | + } |
1049 | + ); |
1050 | +} |
1051 | + |
1052 | +void mie::Platform::device_changed(mu::Device const& dev) |
1053 | +{ |
1054 | + device_removed(dev); |
1055 | + device_added(dev); |
1056 | +} |
1057 | + |
1058 | +void mie::Platform::stop() |
1059 | +{ |
1060 | + platform_dispatchable->remove_watch(monitor_dispatchable); |
1061 | + platform_dispatchable->remove_watch(libinput_dispatchable); |
1062 | + while (!devices.empty()) |
1063 | + { |
1064 | + input_device_registry->remove_device(devices.back()); |
1065 | + devices.pop_back(); |
1066 | + } |
1067 | +} |
1068 | |
1069 | === added file 'src/platforms/evdev/platform.h' |
1070 | --- src/platforms/evdev/platform.h 1970-01-01 00:00:00 +0000 |
1071 | +++ src/platforms/evdev/platform.h 2015-09-18 10:27:31 +0000 |
1072 | @@ -0,0 +1,94 @@ |
1073 | +/* |
1074 | + * Copyright © 2015 Canonical Ltd. |
1075 | + * |
1076 | + * This program is free software: you can redistribute it and/or modify it |
1077 | + * under the terms of the GNU Lesser General Public License version 3, |
1078 | + * as published by the Free Software Foundation. |
1079 | + * |
1080 | + * This program is distributed in the hope that it will be useful, |
1081 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
1082 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
1083 | + * GNU Lesser General Public License for more details. |
1084 | + * |
1085 | + * You should have received a copy of the GNU Lesser General Public License |
1086 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
1087 | + * |
1088 | + * Authored by: Andreas Pokorny <andreas.pokorny@canonical.com> |
1089 | + */ |
1090 | + |
1091 | +#ifndef MIR_INPUT_EVDEV_PLATFORM_H_ |
1092 | +#define MIR_INPUT_EVDEV_PLATFORM_H_ |
1093 | + |
1094 | +#include "libinput_ptr.h" |
1095 | +#include "libinput_device_ptr.h" |
1096 | + |
1097 | +#include "mir/input/platform.h" |
1098 | + |
1099 | +#include <vector> |
1100 | + |
1101 | +struct libinput_device_group; |
1102 | + |
1103 | +namespace mir |
1104 | +{ |
1105 | +namespace udev |
1106 | +{ |
1107 | +class Device; |
1108 | +class Monitor; |
1109 | +class Context; |
1110 | +} |
1111 | +namespace dispatch |
1112 | +{ |
1113 | +class MultiplexingDispatchable; |
1114 | +class ReadableFd; |
1115 | +} |
1116 | +namespace input |
1117 | +{ |
1118 | +class InputDeviceRegistry; |
1119 | +namespace evdev |
1120 | +{ |
1121 | + |
1122 | +struct MonitorDispatchable; |
1123 | +class LibInputDevice; |
1124 | + |
1125 | +class Platform : public input::Platform |
1126 | +{ |
1127 | +public: |
1128 | + Platform(std::shared_ptr<InputDeviceRegistry> const& registry, |
1129 | + std::shared_ptr<InputReport> const& report, |
1130 | + std::unique_ptr<udev::Context>&& udev_context, |
1131 | + std::unique_ptr<udev::Monitor>&& monitor); |
1132 | + std::shared_ptr<mir::dispatch::Dispatchable> dispatchable() override; |
1133 | + void start() override; |
1134 | + void stop() override; |
1135 | + |
1136 | +private: |
1137 | + void scan_for_devices(); |
1138 | + void process_changes(); |
1139 | + void device_added(udev::Device const& dev); |
1140 | + void device_removed(udev::Device const& dev); |
1141 | + void device_changed(udev::Device const& dev); |
1142 | + void process_input_events(); |
1143 | + |
1144 | + std::shared_ptr<LibInputDevice> create_device(udev::Device const& dev) const; |
1145 | + |
1146 | + std::shared_ptr<InputReport> const report; |
1147 | + std::shared_ptr<udev::Context> const udev_context; |
1148 | + std::unique_ptr<udev::Monitor> const monitor; |
1149 | + std::shared_ptr<InputDeviceRegistry> const input_device_registry; |
1150 | + std::shared_ptr<dispatch::MultiplexingDispatchable> const platform_dispatchable; |
1151 | + std::shared_ptr<dispatch::ReadableFd> const monitor_dispatchable; |
1152 | + std::shared_ptr<::libinput> const lib; |
1153 | + std::shared_ptr<dispatch::ReadableFd> const libinput_dispatchable; |
1154 | + |
1155 | + std::vector<std::shared_ptr<LibInputDevice>> devices; |
1156 | + auto find_device(char const* devnode) -> decltype(devices)::iterator; |
1157 | + auto find_device(libinput_device *) -> decltype(devices)::iterator; |
1158 | + auto find_device(libinput_device_group const* group) -> decltype(devices)::iterator; |
1159 | + |
1160 | + friend class MonitorDispatchable; |
1161 | +}; |
1162 | +} |
1163 | +} |
1164 | +} |
1165 | + |
1166 | +#endif |
1167 | |
1168 | === added file 'src/platforms/evdev/platform_factory.cpp' |
1169 | --- src/platforms/evdev/platform_factory.cpp 1970-01-01 00:00:00 +0000 |
1170 | +++ src/platforms/evdev/platform_factory.cpp 2015-09-18 10:27:31 +0000 |
1171 | @@ -0,0 +1,68 @@ |
1172 | +/* |
1173 | + * Copyright © 2015 Canonical Ltd. |
1174 | + * |
1175 | + * This program is free software: you can redistribute it and/or modify it |
1176 | + * under the terms of the GNU Lesser General Public License version 3, |
1177 | + * as published by the Free Software Foundation. |
1178 | + * |
1179 | + * This program is distributed in the hope that it will be useful, |
1180 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
1181 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
1182 | + * GNU Lesser General Public License for more details. |
1183 | + * |
1184 | + * You should have received a copy of the GNU Lesser General Public License |
1185 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
1186 | + * |
1187 | + * Authored by: Andreas Pokorny <andreas.pokorny@canonical.com> |
1188 | + */ |
1189 | + |
1190 | +#include "platform.h" |
1191 | +#include "mir/udev/wrapper.h" |
1192 | + |
1193 | +namespace mo = mir::options; |
1194 | +namespace mi = mir::input; |
1195 | +namespace mu = mir::udev; |
1196 | +namespace mie = mi::evdev; |
1197 | + |
1198 | +namespace |
1199 | +{ |
1200 | +char const* const host_socket_opt = "host-socket"; |
1201 | +mir::ModuleProperties const description = { |
1202 | + "evdev-input", |
1203 | + MIR_VERSION_MAJOR, |
1204 | + MIR_VERSION_MINOR, |
1205 | + MIR_VERSION_MICRO |
1206 | +}; |
1207 | +} |
1208 | + |
1209 | +mir::UniqueModulePtr<mi::Platform> create_input_platform( |
1210 | + std::shared_ptr<mo::Option> const& /*options*/, |
1211 | + std::shared_ptr<mir::EmergencyCleanupRegistry> const& /*emergency_cleanup_registry*/, |
1212 | + std::shared_ptr<mi::InputDeviceRegistry> const& input_device_registry, |
1213 | + std::shared_ptr<mi::InputReport> const& report) |
1214 | +{ |
1215 | + auto ctx = std::make_unique<mu::Context>(); |
1216 | + auto monitor = std::make_unique<mu::Monitor>(*ctx.get()); |
1217 | + return mir::make_module_ptr<mie::Platform>(input_device_registry, report, std::move(ctx), std::move(monitor)); |
1218 | +} |
1219 | + |
1220 | +void add_input_platform_options( |
1221 | + boost::program_options::options_description& /*config*/) |
1222 | +{ |
1223 | + // no options to add yet |
1224 | +} |
1225 | + |
1226 | +mi::PlatformPriority probe_input_platform( |
1227 | + mo::Option const& options) |
1228 | +{ |
1229 | + if (options.is_set(host_socket_opt)) |
1230 | + { |
1231 | + return mi::PlatformPriority::unsupported; |
1232 | + } |
1233 | + return mi::PlatformPriority::supported; |
1234 | +} |
1235 | + |
1236 | +mir::ModuleProperties const* describe_input_module() |
1237 | +{ |
1238 | + return &description; |
1239 | +} |
1240 | |
1241 | === renamed file 'tests/mir_test_framework/symbols-stub-input.map' => 'src/platforms/input_platform_symbols.map' |
1242 | === added file 'tests/include/mir/test/doubles/mock_libinput.h' |
1243 | --- tests/include/mir/test/doubles/mock_libinput.h 1970-01-01 00:00:00 +0000 |
1244 | +++ tests/include/mir/test/doubles/mock_libinput.h 2015-09-18 10:27:31 +0000 |
1245 | @@ -0,0 +1,110 @@ |
1246 | +/* |
1247 | + * Copyright © 2015 Canonical Ltd. |
1248 | + * |
1249 | + * This program is free software: you can redistribute it and/or modify |
1250 | + * it under the terms of the GNU General Public License version 3 as |
1251 | + * published by the Free Software Foundation. |
1252 | + * |
1253 | + * This program is distributed in the hope that it will be useful, |
1254 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
1255 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
1256 | + * GNU General Public License for more details. |
1257 | + * |
1258 | + * You should have received a copy of the GNU General Public License |
1259 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
1260 | + * |
1261 | + * Authored by: Andreas Pokorny <andreas.pokorny@canonical.com> |
1262 | + */ |
1263 | + |
1264 | +#ifndef MIR_TEST_DOUBLES_MOCK_LIBINPUT_H_ |
1265 | +#define MIR_TEST_DOUBLES_MOCK_LIBINPUT_H_ |
1266 | + |
1267 | +#include "mir/dispatch/action_queue.h" |
1268 | + |
1269 | +#include <gmock/gmock.h> |
1270 | + |
1271 | +#include <libinput.h> |
1272 | + |
1273 | +namespace mir |
1274 | +{ |
1275 | +namespace test |
1276 | +{ |
1277 | +namespace doubles |
1278 | +{ |
1279 | + |
1280 | +class MockLibInput |
1281 | +{ |
1282 | +public: |
1283 | + MockLibInput(); |
1284 | + ~MockLibInput() noexcept; |
1285 | + void wake(); |
1286 | + |
1287 | + MOCK_METHOD1(libinput_ref, libinput*(libinput*)); |
1288 | + MOCK_METHOD1(libinput_unref, libinput*(libinput*)); |
1289 | + MOCK_METHOD1(libinput_dispatch, int(libinput*)); |
1290 | + MOCK_METHOD1(libinput_get_fd, int(libinput*)); |
1291 | + MOCK_METHOD1(libinput_get_event, libinput_event*(libinput*)); |
1292 | + MOCK_METHOD1(libinput_event_get_type, libinput_event_type(libinput_event*)); |
1293 | + MOCK_METHOD1(libinput_event_destroy, void(libinput_event*)); |
1294 | + MOCK_METHOD1(libinput_event_get_device, libinput_device*(libinput_event*)); |
1295 | + MOCK_METHOD1(libinput_event_get_pointer_event, libinput_event_pointer*(libinput_event*)); |
1296 | + MOCK_METHOD1(libinput_event_get_keyboard_event, libinput_event_keyboard*(libinput_event*)); |
1297 | + MOCK_METHOD1(libinput_event_get_touch_event, libinput_event_touch*(libinput_event*)); |
1298 | + |
1299 | + MOCK_METHOD1(libinput_event_keyboard_get_time, uint32_t(libinput_event_keyboard*)); |
1300 | + MOCK_METHOD1(libinput_event_keyboard_get_time_usec, uint64_t(libinput_event_keyboard*)); |
1301 | + MOCK_METHOD1(libinput_event_keyboard_get_key, uint32_t(libinput_event_keyboard*)); |
1302 | + MOCK_METHOD1(libinput_event_keyboard_get_key_state, libinput_key_state(libinput_event_keyboard*)); |
1303 | + MOCK_METHOD1(libinput_event_keyboard_get_seat_key_count, uint32_t(libinput_event_keyboard*)); |
1304 | + |
1305 | + MOCK_METHOD1(libinput_event_pointer_get_time, uint32_t(libinput_event_pointer*)); |
1306 | + MOCK_METHOD1(libinput_event_pointer_get_time_usec, uint64_t(libinput_event_pointer*)); |
1307 | + MOCK_METHOD1(libinput_event_pointer_get_dx, double(libinput_event_pointer*)); |
1308 | + MOCK_METHOD1(libinput_event_pointer_get_dy, double(libinput_event_pointer*)); |
1309 | + MOCK_METHOD1(libinput_event_pointer_get_absolute_x, double(libinput_event_pointer*)); |
1310 | + MOCK_METHOD1(libinput_event_pointer_get_absolute_y, double(libinput_event_pointer*)); |
1311 | + MOCK_METHOD2(libinput_event_pointer_get_absolute_x_transformed, double(libinput_event_pointer*, uint32_t)); |
1312 | + MOCK_METHOD2(libinput_event_pointer_get_absolute_y_transformed, double(libinput_event_pointer*, uint32_t)); |
1313 | + MOCK_METHOD1(libinput_event_pointer_get_button, uint32_t(libinput_event_pointer*)); |
1314 | + MOCK_METHOD1(libinput_event_pointer_get_button_state, libinput_button_state(libinput_event_pointer*)); |
1315 | + MOCK_METHOD1(libinput_event_pointer_get_seat_button_count, uint32_t(libinput_event_pointer*)); |
1316 | + MOCK_METHOD1(libinput_event_pointer_get_axis, libinput_pointer_axis(libinput_event_pointer*)); |
1317 | + MOCK_METHOD2(libinput_event_pointer_get_axis_value, double(libinput_event_pointer*, libinput_pointer_axis)); |
1318 | + MOCK_METHOD2(libinput_event_pointer_has_axis,int(libinput_event_pointer *,libinput_pointer_axis)); |
1319 | + |
1320 | + MOCK_METHOD1(libinput_event_touch_get_time, uint32_t(libinput_event_touch*)); |
1321 | + MOCK_METHOD1(libinput_event_touch_get_time_usec, uint64_t(libinput_event_touch*)); |
1322 | + MOCK_METHOD1(libinput_event_touch_get_slot, int32_t(libinput_event_touch*)); |
1323 | + MOCK_METHOD1(libinput_event_touch_get_seat_slot, int32_t(libinput_event_touch*)); |
1324 | + MOCK_METHOD1(libinput_event_touch_get_x, double(libinput_event_touch*)); |
1325 | + MOCK_METHOD1(libinput_event_touch_get_y, double(libinput_event_touch*)); |
1326 | + MOCK_METHOD2(libinput_event_touch_get_x_transformed, double(libinput_event_touch*, uint32_t)); |
1327 | + MOCK_METHOD2(libinput_event_touch_get_y_transformed, double(libinput_event_touch*, uint32_t)); |
1328 | + MOCK_METHOD1(libinput_event_touch_get_pressure, double(libinput_event_touch*)); |
1329 | + MOCK_METHOD1(libinput_event_touch_get_minor, double(libinput_event_touch*)); |
1330 | + MOCK_METHOD3(libinput_event_touch_get_minor_transformed, double(libinput_event_touch*, uint32_t, uint32_t)); |
1331 | + MOCK_METHOD1(libinput_event_touch_get_major, double(libinput_event_touch*)); |
1332 | + MOCK_METHOD3(libinput_event_touch_get_major_transformed, double(libinput_event_touch*, uint32_t, uint32_t)); |
1333 | + MOCK_METHOD1(libinput_event_touch_get_orientation, double(libinput_event_touch*)); |
1334 | + |
1335 | + MOCK_METHOD2(libinput_path_create_context, libinput*(const libinput_interface *, void*)); |
1336 | + MOCK_METHOD2(libinput_path_add_device, libinput_device*(const libinput*, const char*)); |
1337 | + MOCK_METHOD1(libinput_path_remove_device, void(libinput_device*)); |
1338 | + |
1339 | + MOCK_METHOD1(libinput_device_unref, libinput_device*(libinput_device*)); |
1340 | + MOCK_METHOD1(libinput_device_ref, libinput_device*(libinput_device*)); |
1341 | + MOCK_METHOD1(libinput_device_get_name, char const*(libinput_device*)); |
1342 | + MOCK_METHOD1(libinput_device_get_id_product, unsigned int(libinput_device*)); |
1343 | + MOCK_METHOD1(libinput_device_get_id_vendor, unsigned int(libinput_device*)); |
1344 | + MOCK_METHOD1(libinput_device_get_sysname, char const*(libinput_device*)); |
1345 | + MOCK_METHOD1(libinput_device_get_device_group, libinput_device_group*(libinput_device*)); |
1346 | + |
1347 | +private: |
1348 | + dispatch::ActionQueue libinput_simulation_queue; |
1349 | +}; |
1350 | + |
1351 | +} |
1352 | +} |
1353 | +} |
1354 | + |
1355 | +#endif |
1356 | |
1357 | === modified file 'tests/mir_test_doubles/CMakeLists.txt' |
1358 | --- tests/mir_test_doubles/CMakeLists.txt 2015-08-26 22:28:45 +0000 |
1359 | +++ tests/mir_test_doubles/CMakeLists.txt 2015-09-18 10:27:31 +0000 |
1360 | @@ -25,6 +25,7 @@ |
1361 | set( |
1362 | MIR_TEST_DOUBLES_PLATFORM_SRCS |
1363 | |
1364 | + ${CMAKE_CURRENT_SOURCE_DIR}/mock_libinput.cpp |
1365 | ${CMAKE_CURRENT_SOURCE_DIR}/mock_egl.cpp |
1366 | ${CMAKE_CURRENT_SOURCE_DIR}/mock_gl.cpp |
1367 | ) |
1368 | |
1369 | === added file 'tests/mir_test_doubles/mock_libinput.cpp' |
1370 | --- tests/mir_test_doubles/mock_libinput.cpp 1970-01-01 00:00:00 +0000 |
1371 | +++ tests/mir_test_doubles/mock_libinput.cpp 2015-09-18 10:27:31 +0000 |
1372 | @@ -0,0 +1,316 @@ |
1373 | +/* |
1374 | + * Copyright © 2015 Canonical Ltd. |
1375 | + * |
1376 | + * This program is free software: you can redistribute it and/or modify |
1377 | + * it under the terms of the GNU General Public License version 3 as |
1378 | + * published by the Free Software Foundation. |
1379 | + * |
1380 | + * This program is distributed in the hope that it will be useful, |
1381 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
1382 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
1383 | + * GNU General Public License for more details. |
1384 | + * |
1385 | + * You should have received a copy of the GNU General Public License |
1386 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
1387 | + * |
1388 | + * Authored by: Andreas Pokorny <andreas.pokorny@canonical.com> |
1389 | + */ |
1390 | + |
1391 | +#include "mir/test/doubles/mock_libinput.h" |
1392 | + |
1393 | +namespace mtd = mir::test::doubles; |
1394 | + |
1395 | +namespace |
1396 | +{ |
1397 | +mtd::MockLibInput* global_libinput = nullptr; |
1398 | +} |
1399 | + |
1400 | +mtd::MockLibInput::MockLibInput() |
1401 | +{ |
1402 | + using namespace testing; |
1403 | + assert(global_libinput == NULL && "Only one mock object per process is allowed"); |
1404 | + global_libinput = this; |
1405 | + |
1406 | + ON_CALL(*this, libinput_device_ref(_)).WillByDefault(ReturnArg<0>()); |
1407 | + ON_CALL(*this, libinput_get_fd(_)).WillByDefault(Return(int(libinput_simulation_queue.watch_fd()))); |
1408 | +} |
1409 | + |
1410 | +void mtd::MockLibInput::wake() |
1411 | +{ |
1412 | + libinput_simulation_queue.enqueue([]{}); |
1413 | +} |
1414 | + |
1415 | +mtd::MockLibInput::~MockLibInput() noexcept |
1416 | +{ |
1417 | + global_libinput = nullptr; |
1418 | +} |
1419 | + |
1420 | +void libinput_event_destroy(libinput_event* event) |
1421 | +{ |
1422 | + global_libinput->libinput_event_destroy(event); |
1423 | +} |
1424 | + |
1425 | +libinput_event_type libinput_event_get_type(libinput_event* event) |
1426 | +{ |
1427 | + return global_libinput->libinput_event_get_type(event); |
1428 | +} |
1429 | + |
1430 | +libinput_device* libinput_event_get_device(libinput_event* event) |
1431 | +{ |
1432 | + return global_libinput->libinput_event_get_device(event); |
1433 | +} |
1434 | + |
1435 | +libinput_event_pointer* libinput_event_get_pointer_event(libinput_event* event) |
1436 | +{ |
1437 | + return global_libinput->libinput_event_get_pointer_event(event); |
1438 | +} |
1439 | + |
1440 | +libinput_event_keyboard* libinput_event_get_keyboard_event(libinput_event* event) |
1441 | +{ |
1442 | + return global_libinput->libinput_event_get_keyboard_event(event); |
1443 | +} |
1444 | + |
1445 | +libinput_event_touch* libinput_event_get_touch_event(libinput_event* event) |
1446 | +{ |
1447 | + return global_libinput->libinput_event_get_touch_event(event); |
1448 | +} |
1449 | + |
1450 | +uint32_t libinput_event_keyboard_get_time(libinput_event_keyboard* event) |
1451 | +{ |
1452 | + return global_libinput->libinput_event_keyboard_get_time(event); |
1453 | +} |
1454 | + |
1455 | +uint64_t libinput_event_keyboard_get_time_usec(libinput_event_keyboard* event) |
1456 | +{ |
1457 | + return global_libinput->libinput_event_keyboard_get_time_usec(event); |
1458 | +} |
1459 | + |
1460 | +uint32_t libinput_event_keyboard_get_key(libinput_event_keyboard* event) |
1461 | +{ |
1462 | + return global_libinput->libinput_event_keyboard_get_key(event); |
1463 | +} |
1464 | + |
1465 | +libinput_key_state libinput_event_keyboard_get_key_state(libinput_event_keyboard* event) |
1466 | +{ |
1467 | + return global_libinput->libinput_event_keyboard_get_key_state(event); |
1468 | +} |
1469 | + |
1470 | +uint32_t libinput_event_keyboard_get_seat_key_count(libinput_event_keyboard* event) |
1471 | +{ |
1472 | + return global_libinput->libinput_event_keyboard_get_seat_key_count(event); |
1473 | +} |
1474 | + |
1475 | +uint32_t libinput_event_pointer_get_time(libinput_event_pointer* event) |
1476 | +{ |
1477 | + return global_libinput->libinput_event_pointer_get_time(event); |
1478 | +} |
1479 | + |
1480 | +uint64_t libinput_event_pointer_get_time_usec(libinput_event_pointer* event) |
1481 | +{ |
1482 | + return global_libinput->libinput_event_pointer_get_time_usec(event); |
1483 | +} |
1484 | + |
1485 | +double libinput_event_pointer_get_dx(libinput_event_pointer* event) |
1486 | +{ |
1487 | + return global_libinput->libinput_event_pointer_get_dx(event); |
1488 | +} |
1489 | + |
1490 | +double libinput_event_pointer_get_dy(libinput_event_pointer* event) |
1491 | +{ |
1492 | + return global_libinput->libinput_event_pointer_get_dy(event); |
1493 | +} |
1494 | + |
1495 | +double libinput_event_pointer_get_absolute_x(libinput_event_pointer* event) |
1496 | +{ |
1497 | + return global_libinput->libinput_event_pointer_get_absolute_x(event); |
1498 | +} |
1499 | + |
1500 | +double libinput_event_pointer_get_absolute_y(libinput_event_pointer* event) |
1501 | +{ |
1502 | + return global_libinput->libinput_event_pointer_get_absolute_y(event); |
1503 | +} |
1504 | + |
1505 | +double libinput_event_pointer_get_absolute_x_transformed(libinput_event_pointer* event, uint32_t width) |
1506 | +{ |
1507 | + return global_libinput->libinput_event_pointer_get_absolute_x_transformed(event, width); |
1508 | +} |
1509 | + |
1510 | +double libinput_event_pointer_get_absolute_y_transformed(libinput_event_pointer* event, uint32_t height) |
1511 | +{ |
1512 | + return global_libinput->libinput_event_pointer_get_absolute_y_transformed(event, height); |
1513 | +} |
1514 | + |
1515 | +uint32_t libinput_event_pointer_get_button(libinput_event_pointer* event) |
1516 | +{ |
1517 | + return global_libinput->libinput_event_pointer_get_button(event); |
1518 | +} |
1519 | + |
1520 | +libinput_button_state libinput_event_pointer_get_button_state(libinput_event_pointer* event) |
1521 | +{ |
1522 | + return global_libinput->libinput_event_pointer_get_button_state(event); |
1523 | +} |
1524 | + |
1525 | +uint32_t libinput_event_pointer_get_seat_button_count(libinput_event_pointer* event) |
1526 | +{ |
1527 | + return global_libinput->libinput_event_pointer_get_seat_button_count(event); |
1528 | +} |
1529 | + |
1530 | +libinput_pointer_axis libinput_event_pointer_get_axis(libinput_event_pointer* event) |
1531 | +{ |
1532 | + return global_libinput->libinput_event_pointer_get_axis(event); |
1533 | +} |
1534 | + |
1535 | +double libinput_event_pointer_get_axis_value(libinput_event_pointer* event, libinput_pointer_axis axis) |
1536 | +{ |
1537 | + return global_libinput->libinput_event_pointer_get_axis_value(event, axis); |
1538 | +} |
1539 | + |
1540 | +int libinput_event_pointer_has_axis(libinput_event_pointer* event, libinput_pointer_axis axis) |
1541 | +{ |
1542 | + return global_libinput->libinput_event_pointer_has_axis(event, axis); |
1543 | +} |
1544 | + |
1545 | +uint32_t libinput_event_touch_get_time(libinput_event_touch* event) |
1546 | +{ |
1547 | + return global_libinput->libinput_event_touch_get_time(event); |
1548 | +} |
1549 | + |
1550 | +uint64_t libinput_event_touch_get_time_usec(libinput_event_touch* event) |
1551 | +{ |
1552 | + return global_libinput->libinput_event_touch_get_time_usec(event); |
1553 | +} |
1554 | + |
1555 | +int32_t libinput_event_touch_get_slot(libinput_event_touch* event) |
1556 | +{ |
1557 | + return global_libinput->libinput_event_touch_get_slot(event); |
1558 | +} |
1559 | + |
1560 | +int32_t libinput_event_touch_get_seat_slot(libinput_event_touch* event) |
1561 | +{ |
1562 | + return global_libinput->libinput_event_touch_get_seat_slot(event); |
1563 | +} |
1564 | + |
1565 | +double libinput_event_touch_get_x(libinput_event_touch* event) |
1566 | +{ |
1567 | + return global_libinput->libinput_event_touch_get_x(event); |
1568 | +} |
1569 | + |
1570 | +double libinput_event_touch_get_y(libinput_event_touch* event) |
1571 | +{ |
1572 | + return global_libinput->libinput_event_touch_get_y(event); |
1573 | +} |
1574 | + |
1575 | +double libinput_event_touch_get_x_transformed(libinput_event_touch* event, uint32_t width) |
1576 | +{ |
1577 | + return global_libinput->libinput_event_touch_get_x_transformed(event, width); |
1578 | +} |
1579 | + |
1580 | +double libinput_event_touch_get_y_transformed(libinput_event_touch* event, uint32_t height) |
1581 | +{ |
1582 | + return global_libinput->libinput_event_touch_get_y_transformed(event, height); |
1583 | +} |
1584 | + |
1585 | +double libinput_event_touch_get_major(libinput_event_touch* event) |
1586 | +{ |
1587 | + return global_libinput->libinput_event_touch_get_major(event); |
1588 | +} |
1589 | + |
1590 | +double libinput_event_touch_get_minor(libinput_event_touch* event) |
1591 | +{ |
1592 | + return global_libinput->libinput_event_touch_get_minor(event); |
1593 | +} |
1594 | + |
1595 | +double libinput_event_touch_get_major_transformed(libinput_event_touch* event, uint32_t width, uint32_t height) |
1596 | +{ |
1597 | + return global_libinput->libinput_event_touch_get_major_transformed(event, width, height); |
1598 | +} |
1599 | + |
1600 | +double libinput_event_touch_get_minor_transformed(libinput_event_touch* event, uint32_t width, uint32_t height) |
1601 | +{ |
1602 | + return global_libinput->libinput_event_touch_get_minor_transformed(event, width, height); |
1603 | +} |
1604 | + |
1605 | +double libinput_event_touch_get_pressure(libinput_event_touch* event) |
1606 | +{ |
1607 | + return global_libinput->libinput_event_touch_get_pressure(event); |
1608 | +} |
1609 | + |
1610 | +double libinput_event_touch_get_orientation(libinput_event_touch* event) |
1611 | +{ |
1612 | + return global_libinput->libinput_event_touch_get_orientation(event); |
1613 | +} |
1614 | + |
1615 | +libinput* libinput_path_create_context(const libinput_interface* interface, void* user_data) |
1616 | +{ |
1617 | + return global_libinput->libinput_path_create_context(interface, user_data); |
1618 | +} |
1619 | + |
1620 | +libinput_device* libinput_path_add_device(libinput* libinput, const char* path) |
1621 | +{ |
1622 | + return global_libinput->libinput_path_add_device(libinput, path); |
1623 | +} |
1624 | + |
1625 | +void libinput_path_remove_device(libinput_device* device) |
1626 | +{ |
1627 | + return global_libinput->libinput_path_remove_device(device); |
1628 | +} |
1629 | + |
1630 | +int libinput_get_fd(libinput* libinput) |
1631 | +{ |
1632 | + return global_libinput->libinput_get_fd(libinput); |
1633 | +} |
1634 | + |
1635 | +int libinput_dispatch(libinput* libinput) |
1636 | +{ |
1637 | + return global_libinput->libinput_dispatch(libinput); |
1638 | +} |
1639 | + |
1640 | +libinput_event* libinput_get_event(libinput* libinput) |
1641 | +{ |
1642 | + return global_libinput->libinput_get_event(libinput); |
1643 | +} |
1644 | + |
1645 | +libinput* libinput_ref(libinput* libinput) |
1646 | +{ |
1647 | + return global_libinput->libinput_ref(libinput); |
1648 | +} |
1649 | + |
1650 | +libinput* libinput_unref(libinput* libinput) |
1651 | +{ |
1652 | + return global_libinput->libinput_unref(libinput); |
1653 | +} |
1654 | + |
1655 | +libinput_device* libinput_device_ref(libinput_device* device) |
1656 | +{ |
1657 | + return global_libinput->libinput_device_ref(device); |
1658 | +} |
1659 | + |
1660 | +libinput_device* libinput_device_unref(libinput_device* device) |
1661 | +{ |
1662 | + return global_libinput->libinput_device_unref(device); |
1663 | +} |
1664 | + |
1665 | +char const* libinput_device_get_name(libinput_device* device) |
1666 | +{ |
1667 | + return global_libinput->libinput_device_get_name(device); |
1668 | +} |
1669 | + |
1670 | +unsigned int libinput_device_get_id_vendor(libinput_device* device) |
1671 | +{ |
1672 | + return global_libinput->libinput_device_get_id_vendor(device); |
1673 | +} |
1674 | + |
1675 | +unsigned int libinput_device_get_id_product(libinput_device* device) |
1676 | +{ |
1677 | + return global_libinput->libinput_device_get_id_product(device); |
1678 | +} |
1679 | + |
1680 | +char const* libinput_device_get_sysname(libinput_device* device) |
1681 | +{ |
1682 | + return global_libinput->libinput_device_get_sysname(device); |
1683 | +} |
1684 | + |
1685 | +libinput_device_group* libinput_device_get_device_group(libinput_device* device) |
1686 | +{ |
1687 | + return global_libinput->libinput_device_get_device_group(device); |
1688 | +} |
1689 | |
1690 | === modified file 'tests/mir_test_framework/CMakeLists.txt' |
1691 | --- tests/mir_test_framework/CMakeLists.txt 2015-09-16 21:04:57 +0000 |
1692 | +++ tests/mir_test_framework/CMakeLists.txt 2015-09-18 10:27:31 +0000 |
1693 | @@ -115,7 +115,7 @@ |
1694 | LIBRARY_OUTPUT_DIRECTORY ${CMAKE_LIBRARY_OUTPUT_DIRECTORY}/server-modules |
1695 | OUTPUT_NAME input-stub |
1696 | PREFIX "" |
1697 | - LINK_FLAGS "-Wl,--version-script,${CMAKE_CURRENT_SOURCE_DIR}/symbols-stub-input.map" |
1698 | + LINK_FLAGS "-Wl,--version-script,${MIR_INPUT_PLATFORM_VERSION_SCRIPT}" |
1699 | ) |
1700 | |
1701 | install(TARGETS mirplatforminputstub LIBRARY DESTINATION ${MIR_SERVER_PLATFORM_PATH}) |
1702 | |
1703 | === modified file 'tests/mir_test_framework/fake_input_device_impl.cpp' |
1704 | --- tests/mir_test_framework/fake_input_device_impl.cpp 2015-09-01 07:41:29 +0000 |
1705 | +++ tests/mir_test_framework/fake_input_device_impl.cpp 2015-09-18 10:27:31 +0000 |
1706 | @@ -104,9 +104,9 @@ |
1707 | auto key_event = builder->key_event(event_time, input_action, key_code, key_params.scancode, event_modifiers); |
1708 | |
1709 | if (key_params.action == synthesis::EventAction::Down) |
1710 | - modifiers |= mie::to_modifier(key_params.scancode); |
1711 | + modifiers |= mie::to_modifiers(key_params.scancode); |
1712 | else |
1713 | - modifiers &= ~mie::to_modifier(key_params.scancode); |
1714 | + modifiers &= ~mie::to_modifiers(key_params.scancode); |
1715 | |
1716 | if (!sink) |
1717 | BOOST_THROW_EXCEPTION(std::runtime_error("Device is not started.")); |
1718 | |
1719 | === modified file 'tests/unit-tests/input/evdev/CMakeLists.txt' |
1720 | --- tests/unit-tests/input/evdev/CMakeLists.txt 2015-09-02 13:10:33 +0000 |
1721 | +++ tests/unit-tests/input/evdev/CMakeLists.txt 2015-09-18 10:27:31 +0000 |
1722 | @@ -1,6 +1,9 @@ |
1723 | list(APPEND UNIT_TEST_SOURCES |
1724 | ${CMAKE_CURRENT_SOURCE_DIR}/test_evdev_device_detection.cpp |
1725 | + ${CMAKE_CURRENT_SOURCE_DIR}/test_evdev_input_platform.cpp |
1726 | + ${CMAKE_CURRENT_SOURCE_DIR}/test_libinput_device.cpp |
1727 | $<TARGET_OBJECTS:mirevdevutilsobjects> |
1728 | + $<TARGET_OBJECTS:mirplatforminputevdevobjects> |
1729 | ) |
1730 | |
1731 | set( |
1732 | |
1733 | === added file 'tests/unit-tests/input/evdev/test_evdev_input_platform.cpp' |
1734 | --- tests/unit-tests/input/evdev/test_evdev_input_platform.cpp 1970-01-01 00:00:00 +0000 |
1735 | +++ tests/unit-tests/input/evdev/test_evdev_input_platform.cpp 2015-09-18 10:27:31 +0000 |
1736 | @@ -0,0 +1,264 @@ |
1737 | +/* |
1738 | + * Copyright © 2015 Canonical Ltd. |
1739 | + * |
1740 | + * This program is free software: you can redistribute it and/or modify it |
1741 | + * under the terms of the GNU General Public License version 3, |
1742 | + * as published by the Free Software Foundation. |
1743 | + * |
1744 | + * This program is distributed in the hope that it will be useful, |
1745 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
1746 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
1747 | + * GNU General Public License for more details. |
1748 | + * |
1749 | + * You should have received a copy of the GNU General Public License |
1750 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
1751 | + * |
1752 | + * Authored by: Andreas Pokorny <andreas.pokorny@canonical.com> |
1753 | + */ |
1754 | + |
1755 | +#include "src/platforms/evdev/platform.h" |
1756 | +#include "src/server/report/null_report_factory.h" |
1757 | + |
1758 | +#include "mir/input/input_device_registry.h" |
1759 | +#include "mir/dispatch/dispatchable.h" |
1760 | + |
1761 | +#include "mir/udev/wrapper.h" |
1762 | +#include "mir_test_framework/udev_environment.h" |
1763 | +#include "mir/test/fake_shared.h" |
1764 | +#include "mir/test/doubles/mock_libinput.h" |
1765 | + |
1766 | +#include <gtest/gtest.h> |
1767 | +#include <gmock/gmock.h> |
1768 | + |
1769 | +#include <umockdev.h> |
1770 | +#include <memory> |
1771 | +#include <vector> |
1772 | +#include <initializer_list> |
1773 | + |
1774 | +namespace mi = mir::input; |
1775 | +namespace mie = mi::evdev; |
1776 | +namespace mr = mir::report; |
1777 | +namespace mu = mir::udev; |
1778 | +namespace mt = mir::test; |
1779 | +namespace mtd = mt::doubles; |
1780 | + |
1781 | +using ::testing::_; |
1782 | +namespace |
1783 | +{ |
1784 | + |
1785 | +struct MockInputDeviceRegistry : public mi::InputDeviceRegistry |
1786 | +{ |
1787 | + MOCK_METHOD1(add_device, void(std::shared_ptr<mi::InputDevice> const&)); |
1788 | + MOCK_METHOD1(remove_device, void(std::shared_ptr<mi::InputDevice> const&)); |
1789 | +}; |
1790 | + |
1791 | +struct EvdevInputPlatform : public ::testing::TestWithParam<std::string> |
1792 | +{ |
1793 | + mir_test_framework::UdevEnvironment env; |
1794 | + testing::NiceMock<mtd::MockLibInput> mock_libinput; |
1795 | + testing::NiceMock<MockInputDeviceRegistry> mock_registry; |
1796 | + libinput *li_context{reinterpret_cast<libinput*>(0xFEBA)}; |
1797 | + |
1798 | + std::vector<std::pair<std::string, libinput_device*>> devices; |
1799 | + std::vector<std::pair<libinput_device_group*, std::vector<libinput_device*>>> groups; |
1800 | + |
1801 | + EvdevInputPlatform() |
1802 | + { |
1803 | + using namespace testing; |
1804 | + ON_CALL(mock_libinput, libinput_path_create_context(_,_)) |
1805 | + .WillByDefault(Return(li_context)); |
1806 | + ON_CALL(mock_libinput, libinput_path_add_device(li_context,_)) |
1807 | + .WillByDefault(Invoke( |
1808 | + [this](libinput const*, char const* path) -> libinput_device* |
1809 | + { |
1810 | + return open_device_from_path(path); |
1811 | + } |
1812 | + )); |
1813 | + ON_CALL(mock_libinput, libinput_device_get_device_group(_)) |
1814 | + .WillByDefault(Invoke( |
1815 | + [this](libinput_device *dev) |
1816 | + { |
1817 | + return get_device_group(dev); |
1818 | + })); |
1819 | + } |
1820 | + |
1821 | + auto get_device_group(libinput_device *dev) -> libinput_device_group* |
1822 | + { |
1823 | + auto it = find_if(begin(groups), |
1824 | + end(groups), |
1825 | + [dev] (auto const& item) |
1826 | + { |
1827 | + return end(item.second) != find(begin(item.second), end(item.second), dev); |
1828 | + }); |
1829 | + if (end(groups) == it) |
1830 | + { |
1831 | + groups.emplace_back(get_next_fake_ptr<libinput_device_group*>(groups), std::vector<libinput_device*>{dev}); |
1832 | + return groups.back().first; |
1833 | + } |
1834 | + |
1835 | + return it->first; |
1836 | + } |
1837 | + |
1838 | + |
1839 | + template<typename PtrT> |
1840 | + PtrT to_fake_ptr(unsigned int number) |
1841 | + { |
1842 | + return reinterpret_cast<PtrT>(number); |
1843 | + } |
1844 | + |
1845 | + template<typename PtrT, typename Container> |
1846 | + PtrT get_next_fake_ptr(Container const& container) |
1847 | + { |
1848 | + return to_fake_ptr<PtrT>(container.size()+1); |
1849 | + } |
1850 | + |
1851 | + void setup_groupped_devices(std::initializer_list<libinput_device*> devices) |
1852 | + { |
1853 | + groups.emplace_back(get_next_fake_ptr<libinput_device_group*>(groups), devices); |
1854 | + } |
1855 | + |
1856 | + auto open_device_from_path(char const* path) -> libinput_device* |
1857 | + { |
1858 | + auto it = find_if(begin(devices), |
1859 | + end(devices), |
1860 | + [path] (auto const& item) |
1861 | + { |
1862 | + return item.first == path; |
1863 | + }); |
1864 | + if (end(devices) == it) |
1865 | + { |
1866 | + devices.emplace_back(path, get_next_fake_ptr<libinput_device*>(devices)); |
1867 | + return devices.back().second; |
1868 | + } |
1869 | + |
1870 | + return it->second; |
1871 | + } |
1872 | + |
1873 | + auto create_input_platform() |
1874 | + { |
1875 | + auto ctx = std::make_unique<mu::Context>(); |
1876 | + auto monitor = std::make_unique<mu::Monitor>(*ctx.get()); |
1877 | + return std::make_unique<mie::Platform>(mt::fake_shared(mock_registry), mr::null_input_report(), std::move(ctx), |
1878 | + std::move(monitor)); |
1879 | + } |
1880 | + |
1881 | + void remove_devices() |
1882 | + { |
1883 | + mir::udev::Enumerator devices{std::make_shared<mir::udev::Context>()}; |
1884 | + devices.scan_devices(); |
1885 | + |
1886 | + for (auto& device : devices) |
1887 | + { |
1888 | + /* |
1889 | + * Remove just the device providing dev/input/event* |
1890 | + * If we remove more, it's possible that we'll remove the parent of the |
1891 | + * /dev/input device, and umockdev will not generate a remove event |
1892 | + * in that case. |
1893 | + */ |
1894 | + if (device.devnode() && (std::string(device.devnode()).find("input/event") != std::string::npos)) |
1895 | + { |
1896 | + env.remove_device((std::string("/sys") + device.devpath()).c_str()); |
1897 | + } |
1898 | + } |
1899 | + } |
1900 | +}; |
1901 | + |
1902 | +} |
1903 | + |
1904 | +inline void run_dispatchable( mir::input::Platform& platform) |
1905 | +{ |
1906 | + platform.dispatchable()->dispatch(mir::dispatch::FdEvent::readable); |
1907 | +} |
1908 | + |
1909 | +TEST_P(EvdevInputPlatform, scans_on_start) |
1910 | +{ |
1911 | + env.add_standard_device(GetParam()); |
1912 | + |
1913 | + using namespace ::testing; |
1914 | + auto platform = create_input_platform(); |
1915 | + |
1916 | + EXPECT_CALL(mock_registry, add_device(_)); |
1917 | + |
1918 | + platform->start(); |
1919 | +} |
1920 | + |
1921 | +TEST_P(EvdevInputPlatform, detects_on_hotplug) |
1922 | +{ |
1923 | + using namespace ::testing; |
1924 | + auto platform = create_input_platform(); |
1925 | + |
1926 | + platform->start(); |
1927 | + |
1928 | + { |
1929 | + EXPECT_CALL(mock_registry, add_device(_)); |
1930 | + env.add_standard_device(GetParam()); |
1931 | + |
1932 | + run_dispatchable(*platform); |
1933 | + } |
1934 | +} |
1935 | + |
1936 | +TEST_P(EvdevInputPlatform, detects_hot_removal) |
1937 | +{ |
1938 | + using namespace ::testing; |
1939 | + auto platform = create_input_platform(); |
1940 | + |
1941 | + platform->start(); |
1942 | + |
1943 | + { |
1944 | + EXPECT_CALL(mock_registry, add_device(_)); |
1945 | + EXPECT_CALL(mock_registry, remove_device(_)); |
1946 | + |
1947 | + env.add_standard_device(GetParam()); |
1948 | + run_dispatchable(*platform); |
1949 | + remove_devices(); |
1950 | + run_dispatchable(*platform); |
1951 | + } |
1952 | +} |
1953 | + |
1954 | +TEST_P(EvdevInputPlatform, removes_devices_on_stop) |
1955 | +{ |
1956 | + using namespace ::testing; |
1957 | + auto platform = create_input_platform(); |
1958 | + |
1959 | + env.add_standard_device(GetParam()); |
1960 | + platform->start(); |
1961 | + |
1962 | + EXPECT_CALL(mock_registry, remove_device(_)); |
1963 | + platform->stop(); |
1964 | +} |
1965 | + |
1966 | +INSTANTIATE_TEST_CASE_P(DeviceHandling, |
1967 | + EvdevInputPlatform, |
1968 | + ::testing::Values(std::string("synaptics-touchpad"), |
1969 | + std::string("usb-keyboard"), |
1970 | + std::string("usb-mouse"), |
1971 | + std::string("laptop-keyboard"), |
1972 | + std::string("bluetooth-magic-trackpad"))); |
1973 | + |
1974 | + |
1975 | + |
1976 | +TEST_F(EvdevInputPlatform, register_ungrouped_devices) |
1977 | +{ |
1978 | + auto platform = create_input_platform(); |
1979 | + platform->start(); |
1980 | + |
1981 | + EXPECT_CALL(mock_registry, add_device(_)).Times(2); |
1982 | + |
1983 | + env.add_standard_device("synaptics-touchpad"); |
1984 | + env.add_standard_device("usb-keyboard"); |
1985 | + run_dispatchable(*platform); |
1986 | +} |
1987 | + |
1988 | +TEST_F(EvdevInputPlatform, ignore_devices_from_same_group) |
1989 | +{ |
1990 | + auto platform = create_input_platform(); |
1991 | + platform->start(); |
1992 | + |
1993 | + EXPECT_CALL(mock_registry, add_device(_)).Times(1); |
1994 | + |
1995 | + setup_groupped_devices({to_fake_ptr<libinput_device*>(1), to_fake_ptr<libinput_device*>(2)}); |
1996 | + |
1997 | + env.add_standard_device("synaptics-touchpad"); |
1998 | + env.add_standard_device("usb-keyboard"); |
1999 | + run_dispatchable(*platform); |
2000 | +} |
2001 | |
2002 | === added file 'tests/unit-tests/input/evdev/test_libinput_device.cpp' |
2003 | --- tests/unit-tests/input/evdev/test_libinput_device.cpp 1970-01-01 00:00:00 +0000 |
2004 | +++ tests/unit-tests/input/evdev/test_libinput_device.cpp 2015-09-18 10:27:31 +0000 |
2005 | @@ -0,0 +1,498 @@ |
2006 | +/* |
2007 | + * Copyright © 2015 Canonical Ltd. |
2008 | + * |
2009 | + * This program is free software: you can redistribute it and/or modify it |
2010 | + * under the terms of the GNU General Public License version 3, |
2011 | + * as published by the Free Software Foundation. |
2012 | + * |
2013 | + * This program is distributed in the hope that it will be useful, |
2014 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
2015 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
2016 | + * GNU General Public License for more details. |
2017 | + * |
2018 | + * You should have received a copy of the GNU General Public License |
2019 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
2020 | + * |
2021 | + * Authored by: Andreas Pokorny <andreas.pokorny@canonical.com> |
2022 | + */ |
2023 | + |
2024 | +#include "src/platforms/evdev/libinput_device.h" |
2025 | +#include "src/server/report/null_report_factory.h" |
2026 | +#include "src/server/input/default_event_builder.h" |
2027 | + |
2028 | +#include "mir/input/input_device_registry.h" |
2029 | +#include "mir/input/input_sink.h" |
2030 | +#include "mir/geometry/point.h" |
2031 | +#include "mir/geometry/rectangle.h" |
2032 | +#include "mir/test/event_matchers.h" |
2033 | +#include "mir/test/doubles/mock_libinput.h" |
2034 | +#include "mir/test/gmock_fixes.h" |
2035 | + |
2036 | +#include <gmock/gmock.h> |
2037 | +#include <gtest/gtest.h> |
2038 | +#include <linux/input.h> |
2039 | + |
2040 | +#include <chrono> |
2041 | + |
2042 | +namespace mi = mir::input; |
2043 | +namespace mie = mi::evdev; |
2044 | +namespace mt = mir::test; |
2045 | +namespace mtd = mt::doubles; |
2046 | +namespace geom = mir::geometry; |
2047 | + |
2048 | +namespace |
2049 | +{ |
2050 | + |
2051 | +class StubInputDeviceRegistry : public mi::InputDeviceRegistry |
2052 | +{ |
2053 | +public: |
2054 | + void add_device(std::shared_ptr<mi::InputDevice> const&) override {} |
2055 | + void remove_device(std::shared_ptr<mi::InputDevice> const&) override {} |
2056 | +}; |
2057 | + |
2058 | +using namespace ::testing; |
2059 | + |
2060 | +struct MockInputSink : mi::InputSink |
2061 | +{ |
2062 | + MockInputSink() |
2063 | + { |
2064 | + ON_CALL(*this, bounding_rectangle()) |
2065 | + .WillByDefault(Return(geom::Rectangle({0,0}, {100,100}))); |
2066 | + } |
2067 | + MOCK_METHOD1(handle_input,void(MirEvent &)); |
2068 | + MOCK_METHOD1(confine_pointer, void(geom::Point&)); |
2069 | + MOCK_CONST_METHOD0(bounding_rectangle, geom::Rectangle()); |
2070 | +}; |
2071 | + |
2072 | +struct MockEventBuilder : mi::EventBuilder |
2073 | +{ |
2074 | + mi::DefaultEventBuilder builder{MirInputDeviceId{3}}; |
2075 | + MockEventBuilder() |
2076 | + { |
2077 | + ON_CALL(*this, key_event(_,_,_,_,_)) |
2078 | + .WillByDefault(Invoke([this](Timestamp time, MirKeyboardAction action, xkb_keysym_t key, int scan_code, |
2079 | + MirInputEventModifiers modifier) |
2080 | + { |
2081 | + return builder.key_event(time, action, key, scan_code, modifier); |
2082 | + })); |
2083 | + ON_CALL(*this, touch_event(_,_)) |
2084 | + .WillByDefault(Invoke([this](Timestamp time, MirInputEventModifiers modifier) |
2085 | + { |
2086 | + return builder.touch_event(time, modifier); |
2087 | + })); |
2088 | + ON_CALL(*this, add_touch(_,_,_,_,_,_,_,_,_,_)) |
2089 | + .WillByDefault(Invoke([this](MirEvent& event, MirTouchId id, MirTouchAction action, |
2090 | + MirTouchTooltype tooltype, float x, float y, float major, float minor, |
2091 | + float pressure, float size) |
2092 | + { |
2093 | + return builder.add_touch(event, id, action, tooltype, x, y, major, minor, |
2094 | + pressure, size); |
2095 | + })); |
2096 | + ON_CALL(*this, pointer_event(_,_,_,_,_,_,_,_,_,_)) |
2097 | + .WillByDefault(Invoke([this](Timestamp time, MirInputEventModifiers modifier, MirPointerAction action, |
2098 | + MirPointerButtons buttons, float x, float y, float hscroll, float vscroll, |
2099 | + float relative_x, float relative_y) |
2100 | + { |
2101 | + return builder.pointer_event(time, modifier, action, buttons, x, y, hscroll, |
2102 | + vscroll, relative_x, relative_y); |
2103 | + })); |
2104 | + ON_CALL(*this, configuration_event(_,_)) |
2105 | + .WillByDefault(Invoke([this](Timestamp time, MirInputConfigurationAction action) |
2106 | + { |
2107 | + return builder.configuration_event(time, action); |
2108 | + })); |
2109 | + } |
2110 | + using EventBuilder::Timestamp; |
2111 | + MOCK_METHOD5(key_event, mir::EventUPtr(Timestamp, MirKeyboardAction, xkb_keysym_t, int, MirInputEventModifiers)); |
2112 | + |
2113 | + MOCK_METHOD2(touch_event, mir::EventUPtr(Timestamp, MirInputEventModifiers)); |
2114 | + MOCK_METHOD10(add_touch, void(MirEvent&, MirTouchId, MirTouchAction, MirTouchTooltype, float, float, float, float, |
2115 | + float, float)); |
2116 | + |
2117 | + MOCK_METHOD10(pointer_event, mir::EventUPtr(Timestamp, MirInputEventModifiers, MirPointerAction, MirPointerButtons, |
2118 | + float, float, float, float, float, float)); |
2119 | + MOCK_METHOD2(configuration_event, mir::EventUPtr(Timestamp, MirInputConfigurationAction)); |
2120 | +}; |
2121 | + |
2122 | +struct LibInputDevice : public ::testing::Test |
2123 | +{ |
2124 | + ::testing::NiceMock<mir::test::doubles::MockLibInput> mock_libinput; |
2125 | + ::testing::NiceMock<MockInputSink> mock_sink; |
2126 | + ::testing::NiceMock<MockEventBuilder> mock_builder; |
2127 | + |
2128 | + libinput* fake_input = reinterpret_cast<libinput*>(0xF4C3); |
2129 | + libinput_device* fake_device = reinterpret_cast<libinput_device*>(0xF4C4); |
2130 | + libinput_event* fake_event_1 = reinterpret_cast<libinput_event*>(0xF4C5); |
2131 | + libinput_event* fake_event_2 = reinterpret_cast<libinput_event*>(0xF4C6); |
2132 | + libinput_event* fake_event_3 = reinterpret_cast<libinput_event*>(0xF4C7); |
2133 | + libinput_event* fake_event_4 = reinterpret_cast<libinput_event*>(0xF4C8); |
2134 | + libinput_device* second_fake_device = reinterpret_cast<libinput_device*>(0xF4C9); |
2135 | + |
2136 | + const uint64_t event_time_1 = 1000; |
2137 | + const mi::EventBuilder::Timestamp time_stamp_1{std::chrono::microseconds{event_time_1}}; |
2138 | + const uint64_t event_time_2 = 2000; |
2139 | + const mi::EventBuilder::Timestamp time_stamp_2{std::chrono::microseconds{event_time_2}}; |
2140 | + const uint64_t event_time_3 = 3000; |
2141 | + const mi::EventBuilder::Timestamp time_stamp_3{std::chrono::microseconds{event_time_3}}; |
2142 | + const uint64_t event_time_4 = 4000; |
2143 | + const mi::EventBuilder::Timestamp time_stamp_4{std::chrono::microseconds{event_time_4}}; |
2144 | + |
2145 | + char const* path = "/path/to/dev"; |
2146 | + |
2147 | + LibInputDevice() |
2148 | + { |
2149 | + ON_CALL(mock_libinput, libinput_path_create_context(_,_)) |
2150 | + .WillByDefault(Return(fake_input)); |
2151 | + ON_CALL(mock_libinput, libinput_path_add_device(fake_input,_)) |
2152 | + .WillByDefault(Return(fake_device)); |
2153 | + ON_CALL(mock_libinput, libinput_device_ref(fake_device)) |
2154 | + .WillByDefault(Return(fake_device)); |
2155 | + ON_CALL(mock_libinput, libinput_device_unref(fake_device)) |
2156 | + .WillByDefault(Return(nullptr)); |
2157 | + } |
2158 | + |
2159 | + void setup_key_event(libinput_event* event, uint64_t event_time, uint32_t key, libinput_key_state state) |
2160 | + { |
2161 | + auto key_event = reinterpret_cast<libinput_event_keyboard*>(event); |
2162 | + |
2163 | + EXPECT_CALL(mock_libinput, libinput_event_get_type(event)) |
2164 | + .WillRepeatedly(Return(LIBINPUT_EVENT_KEYBOARD_KEY)); |
2165 | + EXPECT_CALL(mock_libinput, libinput_event_get_keyboard_event(event)) |
2166 | + .WillRepeatedly(Return(key_event)); |
2167 | + EXPECT_CALL(mock_libinput, libinput_event_keyboard_get_time_usec(key_event)) |
2168 | + .WillRepeatedly(Return(event_time)); |
2169 | + EXPECT_CALL(mock_libinput, libinput_event_keyboard_get_key(key_event)) |
2170 | + .WillRepeatedly(Return(key)); |
2171 | + EXPECT_CALL(mock_libinput, libinput_event_keyboard_get_key_state(key_event)) |
2172 | + .WillRepeatedly(Return(state)); |
2173 | + } |
2174 | + |
2175 | + void setup_pointer_event(libinput_event* event, uint64_t event_time, float relatve_x, float relatve_y) |
2176 | + { |
2177 | + auto pointer_event = reinterpret_cast<libinput_event_pointer*>(event); |
2178 | + |
2179 | + EXPECT_CALL(mock_libinput, libinput_event_get_type(event)) |
2180 | + .WillRepeatedly(Return(LIBINPUT_EVENT_POINTER_MOTION)); |
2181 | + EXPECT_CALL(mock_libinput, libinput_event_get_pointer_event(event)) |
2182 | + .WillRepeatedly(Return(pointer_event)); |
2183 | + EXPECT_CALL(mock_libinput, libinput_event_pointer_get_time_usec(pointer_event)) |
2184 | + .WillRepeatedly(Return(event_time)); |
2185 | + EXPECT_CALL(mock_libinput, libinput_event_pointer_get_dx(pointer_event)) |
2186 | + .WillRepeatedly(Return(relatve_x)); |
2187 | + EXPECT_CALL(mock_libinput, libinput_event_pointer_get_dy(pointer_event)) |
2188 | + .WillRepeatedly(Return(relatve_y)); |
2189 | + } |
2190 | + |
2191 | + void setup_button_event(libinput_event* event, uint64_t event_time, int button, libinput_button_state state) |
2192 | + { |
2193 | + auto pointer_event = reinterpret_cast<libinput_event_pointer*>(event); |
2194 | + |
2195 | + EXPECT_CALL(mock_libinput, libinput_event_get_type(event)) |
2196 | + .WillRepeatedly(Return(LIBINPUT_EVENT_POINTER_BUTTON)); |
2197 | + EXPECT_CALL(mock_libinput, libinput_event_get_pointer_event(event)) |
2198 | + .WillRepeatedly(Return(pointer_event)); |
2199 | + EXPECT_CALL(mock_libinput, libinput_event_pointer_get_time_usec(pointer_event)) |
2200 | + .WillRepeatedly(Return(event_time)); |
2201 | + EXPECT_CALL(mock_libinput, libinput_event_pointer_get_button(pointer_event)) |
2202 | + .WillRepeatedly(Return(button)); |
2203 | + EXPECT_CALL(mock_libinput, libinput_event_pointer_get_button_state(pointer_event)) |
2204 | + .WillRepeatedly(Return(state)); |
2205 | + } |
2206 | + |
2207 | + void setup_axis_event(libinput_event* event, uint64_t event_time, double horizontal, double vertical) |
2208 | + { |
2209 | + auto pointer_event = reinterpret_cast<libinput_event_pointer*>(event); |
2210 | + |
2211 | + EXPECT_CALL(mock_libinput, libinput_event_get_type(event)) |
2212 | + .WillRepeatedly(Return(LIBINPUT_EVENT_POINTER_AXIS)); |
2213 | + EXPECT_CALL(mock_libinput, libinput_event_get_pointer_event(event)) |
2214 | + .WillRepeatedly(Return(pointer_event)); |
2215 | + EXPECT_CALL(mock_libinput, libinput_event_pointer_get_time_usec(pointer_event)) |
2216 | + .WillRepeatedly(Return(event_time)); |
2217 | + EXPECT_CALL(mock_libinput, libinput_event_pointer_has_axis(pointer_event, LIBINPUT_POINTER_AXIS_SCROLL_HORIZONTAL)) |
2218 | + .WillRepeatedly(Return(horizontal!=0.0)); |
2219 | + EXPECT_CALL(mock_libinput, libinput_event_pointer_has_axis(pointer_event, LIBINPUT_POINTER_AXIS_SCROLL_VERTICAL)) |
2220 | + .WillRepeatedly(Return(vertical!=0.0)); |
2221 | + EXPECT_CALL(mock_libinput, libinput_event_pointer_get_axis_value(pointer_event, LIBINPUT_POINTER_AXIS_SCROLL_VERTICAL)) |
2222 | + .WillRepeatedly(Return(vertical)); |
2223 | + EXPECT_CALL(mock_libinput, libinput_event_pointer_get_axis_value(pointer_event, LIBINPUT_POINTER_AXIS_SCROLL_HORIZONTAL)) |
2224 | + .WillRepeatedly(Return(horizontal)); |
2225 | + } |
2226 | + |
2227 | + void setup_touch_event(libinput_event* event, libinput_event_type type, uint64_t event_time, int slot, float x, |
2228 | + float y, float major, float minor, float pressure) |
2229 | + { |
2230 | + auto touch_event = reinterpret_cast<libinput_event_touch*>(event); |
2231 | + |
2232 | + EXPECT_CALL(mock_libinput, libinput_event_get_type(event)) |
2233 | + .WillRepeatedly(Return(type)); |
2234 | + EXPECT_CALL(mock_libinput, libinput_event_get_touch_event(event)) |
2235 | + .WillRepeatedly(Return(touch_event)); |
2236 | + EXPECT_CALL(mock_libinput, libinput_event_touch_get_slot(touch_event)) |
2237 | + .WillRepeatedly(Return(slot)); |
2238 | + EXPECT_CALL(mock_libinput, libinput_event_touch_get_x_transformed(touch_event, _)) |
2239 | + .WillRepeatedly(Return(x)); |
2240 | + EXPECT_CALL(mock_libinput, libinput_event_touch_get_y_transformed(touch_event, _)) |
2241 | + .WillRepeatedly(Return(y)); |
2242 | + EXPECT_CALL(mock_libinput, libinput_event_touch_get_time_usec(touch_event)) |
2243 | + .WillRepeatedly(Return(event_time)); |
2244 | + EXPECT_CALL(mock_libinput, libinput_event_touch_get_major_transformed(touch_event, _, _)) |
2245 | + .WillRepeatedly(Return(major)); |
2246 | + EXPECT_CALL(mock_libinput, libinput_event_touch_get_minor_transformed(touch_event, _, _)) |
2247 | + .WillRepeatedly(Return(minor)); |
2248 | + EXPECT_CALL(mock_libinput, libinput_event_touch_get_pressure(touch_event)) |
2249 | + .WillRepeatedly(Return(pressure)); |
2250 | + |
2251 | + } |
2252 | + |
2253 | + void setup_touch_frame(libinput_event* event) |
2254 | + { |
2255 | + EXPECT_CALL(mock_libinput, libinput_event_get_type(event)) |
2256 | + .WillRepeatedly(Return(LIBINPUT_EVENT_TOUCH_FRAME)); |
2257 | + } |
2258 | +}; |
2259 | + |
2260 | +} |
2261 | + |
2262 | +TEST_F(LibInputDevice, start_creates_and_unrefs_libinput_device_from_path) |
2263 | +{ |
2264 | + EXPECT_CALL(mock_libinput, libinput_path_add_device(fake_input,StrEq(path))) |
2265 | + .Times(1); |
2266 | + // according to manual libinput_path_add_device creates a temporary device with a ref count 0. |
2267 | + // hence it needs a manual ref call |
2268 | + EXPECT_CALL(mock_libinput, libinput_device_ref(fake_device)) |
2269 | + .Times(1); |
2270 | + std::shared_ptr<libinput> lib = mie::make_libinput(); |
2271 | + mie::LibInputDevice dev(mir::report::null_input_report(), |
2272 | + path, |
2273 | + mie::make_libinput_device(lib.get(), path)); |
2274 | + dev.start(&mock_sink, &mock_builder); |
2275 | +} |
2276 | + |
2277 | +TEST_F(LibInputDevice, open_device_of_group) |
2278 | +{ |
2279 | + char const* first_dev = "/path/to/dev1"; |
2280 | + char const* second_dev = "/path/to/dev2"; |
2281 | + std::shared_ptr<libinput> lib = mie::make_libinput(); |
2282 | + |
2283 | + InSequence seq; |
2284 | + EXPECT_CALL(mock_libinput, libinput_path_add_device(fake_input,StrEq(first_dev))); |
2285 | + // according to manual libinput_path_add_device creates a temporary device with a ref count 0. |
2286 | + // hence it needs a manual ref call |
2287 | + EXPECT_CALL(mock_libinput, libinput_device_ref(fake_device)); |
2288 | + EXPECT_CALL(mock_libinput, libinput_path_add_device(fake_input,StrEq(second_dev))) |
2289 | + .WillOnce(Return(second_fake_device)); |
2290 | + EXPECT_CALL(mock_libinput, libinput_device_ref(second_fake_device)); |
2291 | + |
2292 | + mie::LibInputDevice dev(mir::report::null_input_report(), |
2293 | + first_dev, |
2294 | + mie::make_libinput_device(lib.get(), first_dev)); |
2295 | + dev.add_device_of_group(second_dev, mie::make_libinput_device(lib.get(), second_dev)); |
2296 | + dev.start(&mock_sink, &mock_builder); |
2297 | +} |
2298 | + |
2299 | +TEST_F(LibInputDevice, removal_unrefs_libinput_device) |
2300 | +{ |
2301 | + std::shared_ptr<libinput> lib = mie::make_libinput(); |
2302 | + |
2303 | + EXPECT_CALL(mock_libinput, libinput_device_unref(fake_device)) |
2304 | + .Times(1); |
2305 | + |
2306 | + mie::LibInputDevice dev(mir::report::null_input_report(), path, mie::make_libinput_device(lib.get(), path)); |
2307 | +} |
2308 | + |
2309 | + |
2310 | +TEST_F(LibInputDevice, process_event_converts_key_event) |
2311 | +{ |
2312 | + std::shared_ptr<libinput> lib = mie::make_libinput(); |
2313 | + mie::LibInputDevice dev(mir::report::null_input_report(), path, mie::make_libinput_device(lib.get(), path)); |
2314 | + |
2315 | + setup_key_event(fake_event_1, event_time_1, KEY_A, LIBINPUT_KEY_STATE_PRESSED); |
2316 | + setup_key_event(fake_event_2, event_time_2, KEY_A, LIBINPUT_KEY_STATE_RELEASED); |
2317 | + |
2318 | + EXPECT_CALL(mock_builder, key_event(time_stamp_1, mir_keyboard_action_down, _, KEY_A, mir_input_event_modifier_none)); |
2319 | + EXPECT_CALL(mock_sink, handle_input(AllOf(mt::KeyOfScanCode(KEY_A),mt::KeyDownEvent()))); |
2320 | + EXPECT_CALL(mock_builder, key_event(time_stamp_2, mir_keyboard_action_up, _, KEY_A, mir_input_event_modifier_none)); |
2321 | + EXPECT_CALL(mock_sink, handle_input(AllOf(mt::KeyOfScanCode(KEY_A),mt::KeyUpEvent()))); |
2322 | + |
2323 | + dev.start(&mock_sink, &mock_builder); |
2324 | + dev.process_event(fake_event_1); |
2325 | + dev.process_event(fake_event_2); |
2326 | +} |
2327 | + |
2328 | +TEST_F(LibInputDevice, process_event_accumulates_key_state) |
2329 | +{ |
2330 | + std::shared_ptr<libinput> lib = mie::make_libinput(); |
2331 | + mie::LibInputDevice dev(mir::report::null_input_report(), path, mie::make_libinput_device(lib.get(), path)); |
2332 | + |
2333 | + |
2334 | + setup_key_event(fake_event_1, event_time_1, KEY_C, LIBINPUT_KEY_STATE_PRESSED); |
2335 | + setup_key_event(fake_event_2, event_time_2, KEY_LEFTALT, LIBINPUT_KEY_STATE_PRESSED); |
2336 | + setup_key_event(fake_event_3, event_time_3, KEY_C, LIBINPUT_KEY_STATE_RELEASED); |
2337 | + |
2338 | + InSequence seq; |
2339 | + EXPECT_CALL(mock_builder, key_event(time_stamp_1, mir_keyboard_action_down, _, KEY_C, mir_input_event_modifier_none)); |
2340 | + EXPECT_CALL(mock_sink, handle_input(AllOf(mt::KeyOfScanCode(KEY_C),mt::KeyDownEvent()))); |
2341 | + EXPECT_CALL(mock_builder, key_event(time_stamp_2, mir_keyboard_action_down, _, KEY_LEFTALT, mir_input_event_modifier_none)); |
2342 | + EXPECT_CALL(mock_sink, handle_input(AllOf(mt::KeyOfScanCode(KEY_LEFTALT),mt::KeyDownEvent()))); |
2343 | + EXPECT_CALL(mock_builder, key_event(time_stamp_3, mir_keyboard_action_up, _, KEY_C, mir_input_event_modifier_alt|mir_input_event_modifier_alt_left)); |
2344 | + EXPECT_CALL(mock_sink, handle_input(AllOf(mt::KeyOfScanCode(KEY_C), |
2345 | + mt::KeyWithModifiers( |
2346 | + MirInputEventModifiers{ |
2347 | + mir_input_event_modifier_alt| |
2348 | + mir_input_event_modifier_alt_left |
2349 | + }), |
2350 | + mt::KeyUpEvent()))); |
2351 | + |
2352 | + dev.start(&mock_sink, &mock_builder); |
2353 | + dev.process_event(fake_event_1); |
2354 | + dev.process_event(fake_event_2); |
2355 | + dev.process_event(fake_event_3); |
2356 | +} |
2357 | + |
2358 | +TEST_F(LibInputDevice, process_event_converts_pointer_event) |
2359 | +{ |
2360 | + std::shared_ptr<libinput> lib = mie::make_libinput(); |
2361 | + mie::LibInputDevice dev(mir::report::null_input_report(), path, mie::make_libinput_device(lib.get(), path)); |
2362 | + |
2363 | + float x = 15; |
2364 | + float y = 17; |
2365 | + setup_pointer_event(fake_event_1, event_time_1, x, y); |
2366 | + |
2367 | + EXPECT_CALL(mock_sink, handle_input(mt::PointerEventWithPosition(x,y))); |
2368 | + |
2369 | + dev.start(&mock_sink, &mock_builder); |
2370 | + dev.process_event(fake_event_1); |
2371 | +} |
2372 | + |
2373 | +TEST_F(LibInputDevice, process_event_provides_relative_coordinates) |
2374 | +{ |
2375 | + std::shared_ptr<libinput> lib = mie::make_libinput(); |
2376 | + mie::LibInputDevice dev(mir::report::null_input_report(), path, mie::make_libinput_device(lib.get(), path)); |
2377 | + |
2378 | + float x = -5; |
2379 | + float y = 20; |
2380 | + setup_pointer_event(fake_event_1, event_time_1, x, y); |
2381 | + |
2382 | + EXPECT_CALL(mock_sink, handle_input(mt::PointerEventWithDiff(x,y))); |
2383 | + |
2384 | + dev.start(&mock_sink, &mock_builder); |
2385 | + dev.process_event(fake_event_1); |
2386 | +} |
2387 | + |
2388 | +TEST_F(LibInputDevice, process_event_accumulates_pointer_movement) |
2389 | +{ |
2390 | + std::shared_ptr<libinput> lib = mie::make_libinput(); |
2391 | + mie::LibInputDevice dev(mir::report::null_input_report(), path, mie::make_libinput_device(lib.get(), path)); |
2392 | + |
2393 | + float x1 = 15, x2 = 23; |
2394 | + float y1 = 17, y2 = 21; |
2395 | + |
2396 | + setup_pointer_event(fake_event_1, event_time_1, x1, y1); |
2397 | + setup_pointer_event(fake_event_2, event_time_2, x2, y2); |
2398 | + |
2399 | + EXPECT_CALL(mock_sink, handle_input(mt::PointerEventWithPosition(x1,y1))); |
2400 | + EXPECT_CALL(mock_sink, handle_input(mt::PointerEventWithPosition(x1+x2,y1+y2))); |
2401 | + |
2402 | + dev.start(&mock_sink, &mock_builder); |
2403 | + dev.process_event(fake_event_1); |
2404 | + dev.process_event(fake_event_2); |
2405 | +} |
2406 | + |
2407 | +TEST_F(LibInputDevice, process_event_handles_press_and_release) |
2408 | +{ |
2409 | + std::shared_ptr<libinput> lib = mie::make_libinput(); |
2410 | + mie::LibInputDevice dev(mir::report::null_input_report(), path, mie::make_libinput_device(lib.get(), path)); |
2411 | + float const x = 0; |
2412 | + float const y = 0; |
2413 | + geom::Point const pos{x,y}; |
2414 | + |
2415 | + setup_button_event(fake_event_1, event_time_1, BTN_LEFT, LIBINPUT_BUTTON_STATE_PRESSED); |
2416 | + setup_button_event(fake_event_2, event_time_2, BTN_RIGHT, LIBINPUT_BUTTON_STATE_PRESSED); |
2417 | + setup_button_event(fake_event_3, event_time_3, BTN_RIGHT, LIBINPUT_BUTTON_STATE_RELEASED); |
2418 | + setup_button_event(fake_event_4, event_time_4, BTN_LEFT, LIBINPUT_BUTTON_STATE_RELEASED); |
2419 | + |
2420 | + InSequence seq; |
2421 | + EXPECT_CALL(mock_sink, handle_input(mt::ButtonDownEventWithButton(pos, mir_pointer_button_primary))); |
2422 | + EXPECT_CALL(mock_sink, handle_input(mt::ButtonDownEventWithButton(pos, mir_pointer_button_secondary))); |
2423 | + EXPECT_CALL(mock_sink, handle_input(mt::ButtonUpEventWithButton(pos, mir_pointer_button_secondary))); |
2424 | + EXPECT_CALL(mock_sink, handle_input(mt::ButtonUpEventWithButton(pos, mir_pointer_button_primary))); |
2425 | + |
2426 | + dev.start(&mock_sink, &mock_builder); |
2427 | + dev.process_event(fake_event_1); |
2428 | + dev.process_event(fake_event_2); |
2429 | + dev.process_event(fake_event_3); |
2430 | + dev.process_event(fake_event_4); |
2431 | +} |
2432 | + |
2433 | +TEST_F(LibInputDevice, process_event_handles_scroll) |
2434 | +{ |
2435 | + std::shared_ptr<libinput> lib = mie::make_libinput(); |
2436 | + mie::LibInputDevice dev(mir::report::null_input_report(), path, mie::make_libinput_device(lib.get(), path)); |
2437 | + |
2438 | + setup_axis_event(fake_event_1, event_time_1, 0.0, 20.0); |
2439 | + setup_axis_event(fake_event_2, event_time_2, 5.0, 0.0); |
2440 | + |
2441 | + InSequence seq; |
2442 | + // expect two scroll events.. |
2443 | + EXPECT_CALL(mock_builder, pointer_event(time_stamp_1, mir_input_event_modifier_none, mir_pointer_action_motion, 0, 0.0f, 0.0f, 0.0f, 20.0f, 0.0f, 0.0f)); |
2444 | + EXPECT_CALL(mock_sink, handle_input(mt::PointerAxisChange(mir_pointer_axis_vscroll, 20.0f))); |
2445 | + EXPECT_CALL(mock_builder, pointer_event(time_stamp_2, mir_input_event_modifier_none, mir_pointer_action_motion, 0, 0.0f, 0.0f, 5.0f, 0.0f, 0.0f, 0.0f)); |
2446 | + EXPECT_CALL(mock_sink, handle_input(mt::PointerAxisChange(mir_pointer_axis_hscroll, 5.0f))); |
2447 | + |
2448 | + dev.start(&mock_sink, &mock_builder); |
2449 | + dev.process_event(fake_event_1); |
2450 | + dev.process_event(fake_event_2); |
2451 | +} |
2452 | + |
2453 | +TEST_F(LibInputDevice, process_event_handles_touch_down_events) |
2454 | +{ |
2455 | + std::shared_ptr<libinput> lib = mie::make_libinput(); |
2456 | + mie::LibInputDevice dev(mir::report::null_input_report(), path, mie::make_libinput_device(lib.get(), path)); |
2457 | + |
2458 | + int slot = 0; |
2459 | + float major = 6; |
2460 | + float minor = 5; |
2461 | + float pressure = 0.6f; |
2462 | + float x = 100; |
2463 | + float y = 7; |
2464 | + |
2465 | + setup_touch_event(fake_event_1, LIBINPUT_EVENT_TOUCH_DOWN, event_time_1, slot, x, y, major, minor, pressure); |
2466 | + setup_touch_frame(fake_event_2); |
2467 | + |
2468 | + InSequence seq; |
2469 | + EXPECT_CALL(mock_builder, touch_event(time_stamp_1, mir_input_event_modifier_none)); |
2470 | + EXPECT_CALL(mock_builder, add_touch(_, MirTouchId{0}, mir_touch_action_down, mir_touch_tooltype_finger, x, y, |
2471 | + pressure, major, minor, major)); |
2472 | + EXPECT_CALL(mock_sink, handle_input(mt::TouchEvent(x,y))); |
2473 | + |
2474 | + dev.start(&mock_sink, &mock_builder); |
2475 | + dev.process_event(fake_event_1); |
2476 | + dev.process_event(fake_event_2); |
2477 | +} |
2478 | + |
2479 | +TEST_F(LibInputDevice, process_event_handles_touch_move_events) |
2480 | +{ |
2481 | + std::shared_ptr<libinput> lib = mie::make_libinput(); |
2482 | + mie::LibInputDevice dev(mir::report::null_input_report(), path, mie::make_libinput_device(lib.get(), path)); |
2483 | + |
2484 | + int slot = 0; |
2485 | + float major = 6; |
2486 | + float minor = 5; |
2487 | + float pressure = 0.6f; |
2488 | + float x = 100; |
2489 | + float y = 7; |
2490 | + |
2491 | + setup_touch_event(fake_event_1, LIBINPUT_EVENT_TOUCH_MOTION, event_time_1, slot, x, y, major, minor, pressure); |
2492 | + setup_touch_frame(fake_event_2); |
2493 | + |
2494 | + InSequence seq; |
2495 | + EXPECT_CALL(mock_builder, touch_event(time_stamp_1, mir_input_event_modifier_none)); |
2496 | + EXPECT_CALL(mock_builder, add_touch(_, MirTouchId{0}, mir_touch_action_change, mir_touch_tooltype_finger, x, y, |
2497 | + pressure, major, minor, major)); |
2498 | + EXPECT_CALL(mock_sink, handle_input(mt::TouchMovementEvent())); |
2499 | + |
2500 | + dev.start(&mock_sink, &mock_builder); |
2501 | + dev.process_event(fake_event_1); |
2502 | + dev.process_event(fake_event_2); |
2503 | +} |
ok i just saw two more things I can split out..