Mir

Merge lp:~andreas-pokorny/mir/evdev-input-platform into lp:mir

Proposed by Andreas Pokorny
Status: Work in progress
Proposed branch: lp:~andreas-pokorny/mir/evdev-input-platform
Merge into: lp:mir
Diff against target: 3273 lines (+2839/-12)
54 files modified
include/platform/mir/input/device_capability.h (+50/-0)
include/platform/mir/input/input_device.h (+60/-0)
include/platform/mir/input/input_device_registry.h (+49/-0)
include/platform/mir/input/input_event_handler_register.h (+80/-0)
include/platform/mir/input/input_report.h (+8/-4)
include/platform/mir/input/input_sink.h (+43/-0)
include/platform/mir/input/platform.h (+128/-0)
platform-ABI-sha1sums (+7/-0)
server-ABI-sha1sums (+7/-0)
src/CMakeLists.txt (+4/-0)
src/include/common/mir/find_best.h (+67/-0)
src/include/common/mir/flags.h (+118/-0)
src/platform/CMakeLists.txt (+2/-0)
src/platforms/CMakeLists.txt (+13/-0)
src/platforms/evdev/CMakeLists.txt (+24/-0)
src/platforms/evdev/android_device_provider.cpp (+48/-0)
src/platforms/evdev/android_device_provider.h (+42/-0)
src/platforms/evdev/evdev_device_detection.cpp (+163/-0)
src/platforms/evdev/evdev_device_detection.h (+35/-0)
src/platforms/evdev/evdev_input_device_factory.cpp (+58/-0)
src/platforms/evdev/evdev_input_device_factory.h (+52/-0)
src/platforms/evdev/input_device_factory.h (+50/-0)
src/platforms/evdev/input_device_provider.h (+59/-0)
src/platforms/evdev/libinput_device_provider.cpp (+67/-0)
src/platforms/evdev/libinput_device_provider.h (+42/-0)
src/platforms/evdev/platform.cpp (+179/-0)
src/platforms/evdev/platform.h (+69/-0)
src/platforms/input-platform-symbols.map (+7/-0)
src/server/report/logging/input_report.cpp (+18/-0)
src/server/report/logging/input_report.h (+4/-0)
src/server/report/lttng/input_report.cpp (+10/-0)
src/server/report/lttng/input_report.h (+3/-0)
src/server/report/lttng/input_report_tp.h (+19/-1)
src/server/report/null/input_report.cpp (+8/-0)
src/server/report/null/input_report.h (+3/-0)
tests/include/mir_test_doubles/mock_input_device_registry.h (+46/-0)
tests/include/mir_test_doubles/mock_input_event_handler_register.h (+62/-0)
tests/include/mir_test_framework/executable_path.h (+2/-0)
tests/mir_test_framework/CMakeLists.txt (+6/-0)
tests/mir_test_framework/executable_path.cpp (+27/-0)
tests/mir_test_framework/udev_recordings/joystick-detection.ioctl (+25/-0)
tests/mir_test_framework/udev_recordings/joystick-detection.umockdev (+351/-0)
tests/mir_test_framework/udev_recordings/mt-screen-detection.ioctl (+28/-0)
tests/mir_test_framework/udev_recordings/mt-screen-detection.umockdev (+44/-0)
tests/mir_test_framework/udev_recordings/synaptics-touchpad.ioctl (+0/-7)
tests/unit-tests/CMakeLists.txt (+2/-0)
tests/unit-tests/input/CMakeLists.txt (+1/-0)
tests/unit-tests/input/evdev/CMakeLists.txt (+13/-0)
tests/unit-tests/input/evdev/test_android_device_provider.cpp (+83/-0)
tests/unit-tests/input/evdev/test_evdev_device_detection.cpp (+86/-0)
tests/unit-tests/input/evdev/test_evdev_input_device_factory.cpp (+106/-0)
tests/unit-tests/input/evdev/test_libinput_device_provider.cpp (+82/-0)
tests/unit-tests/input/evdev/test_platform.cpp (+207/-0)
tests/unit-tests/test_find_best.cpp (+72/-0)
To merge this branch: bzr merge lp:~andreas-pokorny/mir/evdev-input-platform
Reviewer Review Type Date Requested Status
Daniel van Vugt Needs Fixing
Cemil Azizoglu (community) Needs Resubmitting
PS Jenkins bot (community) continuous-integration Approve
Robert Carr (community) Needs Information
Kevin DuBois (community) Abstain
Review via email: mp+243806@code.launchpad.net

Commit message

Adds the first pieces of the evdev input platform.

Those include platform interfaces for dealing with added and removed devices, and sending input events into the system. Evdev device detection to decide which code base should be used for handling the event stream. The decision is made between the android input code already existing in mir and libinput. Many of the added tests make use of recorded umockdev files. This commit fixes empty ioctl return values from the recorded synaptic touch pad and adds a multi touch screen and a joystick to the devices.

The evdev input platform is not installed until the input parts of libmirserver are changed to make use of it.

Description of the change

This change adds the basic interfaces for having input platforms, and implements the framework for an evdev input platform. Several parts are still left out, and the input platform is not yet loaded by the DefaultServerConfiguration. See Follow up steps below.

Relevant Interfaces:
 * mir::input::Plaform - the entry point for the server to deal with a input platform
 * mir::input::Multiplexer an interface for the platform to enqeue actions and get triggered because of readable data in fds
 * mir::input::InputDeviceRegistry an interface to be used by the platforms to inform the server about existing or recently plugged in or removed devices..
 * mir::input::InputDevice an interface for the server to connect (and disconnect) input devices with the input handling
 * mir::input::EventSink interface for input devices to provide input events to the server..
   Those three interfaces above are part of the input mocking/stubbing story for acceptance testing the server or possible shells.

Follow up steps:
 * libinput integration through the LibInputDeviceProvider, which in this MP still provides empty shared_ptrs (still wip at:
   lp:~andreas-pokorny/mir/libinput-integration)
 * similar integration of the EventHub/InputReader code of the android input stack through the AndroidDeviceProvider and input platform loaded inside the server
 * Smaller cleanup of EventHub and InputReader

To post a comment you must log in.
Revision history for this message
Kevin DuBois (kdub) wrote :

64 +++ include/platform/mir/input/event_sink.h
this is the same interface as
src/client/event_sink.h

364 +extern "C" typedef std::unique_ptr<Platform>(*CreatePlatofrm)(
153 + // add devie info here..
typos

264 + std::initializer_list<int> fds,
Fds should be mir::Fd to better manage the lifetime of the FD.

145 +class InputDevice
class name doesnt make sense to me for what the group of functions is doing, but this might be a side effect of the "Multiplexer" naming comment.

349 + * The \a input_device_registry should be informed about input device changes using the MainLoop \a loop.
350 + */
351 + virtual void start_monitor_devices(Multiplexer& loop, std::shared_ptr<InputDeviceRegistry> const& input_device_registry) = 0;
Does the comment need updating? MainLoop doesn't seem related

review: Needs Fixing
2106. By Andreas Pokorny

typos

2107. By Andreas Pokorny

typo

2108. By Andreas Pokorny

renamed Multiplexer to InputEventHandlerRegister

2109. By Andreas Pokorny

last round of method renamings

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

>
> 364 +extern "C" typedef std::unique_ptr<Platform>(*CreatePlatofrm)(
> 153 + // add devie info here..
> typos
>
> 264 + std::initializer_list<int> fds,
> Fds should be mir::Fd to better manage the lifetime of the FD.
>
> 145 +class InputDevice
> class name doesnt make sense to me for what the group of functions is doing,
> but this might be a side effect of the "Multiplexer" naming comment.
>
> 349 + * The \a input_device_registry should be informed about input device
> changes using the MainLoop \a loop.
> 350 + */
> 351 + virtual void start_monitor_devices(Multiplexer& loop,
> std::shared_ptr<InputDeviceRegistry> const& input_device_registry) = 0;
> Does the comment need updating? MainLoop doesn't seem related

done - is the new naming good enough?

Revision history for this message
Cemil Azizoglu (cemil-azizoglu) wrote :

Here's a preliminary review. I'll have to re-review at some point more thoroughly.

33 +enum class DeviceClass : uint32_t
34 +{
35 + unknown = 0,
36 + cursor = 1<<1,
37 + keyboard = 1<<2,
38 + touchpad = 1<<3,
39 + touchscreen = 1<<4,
40 + gamepad = 1<<5,
41 + joystick = 1<<6,
42 + switch_ = 1<<7, // better name needed
43 + multitouch = 1<<8, // multitouch capable
44 + alpha_numeric = 1<<9 // enough keys for text entry
45 +};

This class is a bit strange in the sense that it includes both device class (keyboard, joystick, etc) and capability (multitouch, alpha_numeric, etc) entries. Not sure if it might cause problems later.
-----------------------------------------
161 + virtual void stop(InputEventHandlerRegister& registry) = 0;

Does this implicitly unregister the sink?
-----------------------------------------
279 + * \param owner a distinct value to identify the caller

perhaps s/distinct/unique? There are other instances.
-----------------------------------------
368 + * openning new device and register them at the servers InputDeviceRegistry.

s/openning/opening, s/servers/server's
-----------------------------------------
569 + return Priority::supported;

Do we really support all the devices except touchpad under Android, or is this supposed to be "Priority::unsupported"?

-----------------------------------------
754 +
755 +

superfluous blank line.
-----------------------------------------
1123 + return Priority::supported;

Ditto for libinput. According to the code we support everything but joystick, touchscreen and gamepad.
-----------------------------------------
1318 +void mie::Platform::device_changed(mu::Device const& /*dev*/)
1319 +{
1320 +}

Should we at least print a warning?
-----------------------------------------
1459 +
1460 +

superfluous blank lines.

review: Needs Fixing
Revision history for this message
Kevin DuBois (kdub) wrote :

Typos/names look addressed, still these though:
>
> 64 +++ include/platform/mir/input/event_sink.h
> this is the same interface as
> src/client/event_sink.h
>
> 264 + std::initializer_list<int> fds,
> Fds should be mir::Fd to better manage the lifetime of the FD.

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

> Typos/names look addressed, still these though:
> >
> > 64 +++ include/platform/mir/input/event_sink.h
> > this is the same interface as
> > src/client/event_sink.h

We paused our discussion with unifying both interfaces to a single mir::EventSink vs mir::input::EventSink.

> >
> > 264 + std::initializer_list<int> fds,
> > Fds should be mir::Fd to better manage the lifetime of the FD.

I would like to do that, but I implement that interface with our glib MainLoop implementation which currently does not use mir::Fd. On the caller/libinput side I could just keep the mir::Fd to not close the fd before the libinput context falls out of scope, but on the callee side I would need to do additional tracking to fulfill that interface.

Can we settle with doing that in a separate MP?

2110. By Andreas Pokorny

reverted some additional white space noise. Adopted the naming and ABI settings from lp:~raof/mir/server-platfrom-probing.
Because of that the integration test now also loads the library from file system instead of statically linked

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

> Here's a preliminary review. I'll have to re-review at some point more
> thoroughly.
>
> 33 +enum class DeviceClass : uint32_t
> 34 +{
> 35 + unknown = 0,
> 36 + cursor = 1<<1,
> 37 + keyboard = 1<<2,
> 38 + touchpad = 1<<3,
> 39 + touchscreen = 1<<4,
> 40 + gamepad = 1<<5,
> 41 + joystick = 1<<6,
> 42 + switch_ = 1<<7, // better name needed
> 43 + multitouch = 1<<8, // multitouch capable
> 44 + alpha_numeric = 1<<9 // enough keys for text entry
> 45 +};
>
> This class is a bit strange in the sense that it includes both device class
> (keyboard, joystick, etc) and capability (multitouch, alpha_numeric, etc)
> entries. Not sure if it might cause problems later.

I took those value from android, they are supposed to replace the device detection code that currently lives inside eventhub.cpp. Maybe splitting those entries makes them more reasonable?

> -----------------------------------------
> 161 + virtual void stop(InputEventHandlerRegister& registry) = 0;
>
> Does this implicitly unregister the sink?

it expects the callee to no longer use the sink.

> -----------------------------------------
> 279 + * \param owner a distinct value to identify the caller
>
> perhaps s/distinct/unique? There are other instances.
> -----------------------------------------
> 368 + * openning new device and register them at the servers
> InputDeviceRegistry.
>
> s/openning/opening, s/servers/server's
> -----------------------------------------
> 569 + return Priority::supported;
>
> Do we really support all the devices except touchpad under Android, or is this
> supposed to be "Priority::unsupported"?

Thats the impression i took from the input mappers. MirEvent on the other hand isnt that complete, which MirEvent-2 hopefully resolves.

> -----------------------------------------
> 754 +
> 755 +
>
> superfluous blank line.
> -----------------------------------------
> 1123 + return Priority::supported;
>
> Ditto for libinput. According to the code we support everything but joystick,
> touchscreen and gamepad.

After you pointed that out I reconsidered and took a more conservative approach. The event model inside libinput only supports those cursor/keyboard/touchpad and x-y joysticks and touch screens in a restricted form.

> -----------------------------------------
> 1318 +void mie::Platform::device_changed(mu::Device const& /*dev*/)
> 1319 +{
> 1320 +}
>
> Should we at least print a warning?

I am not sure yet about the semantics of that udev event.

Revision history for this message
Kevin DuBois (kdub) wrote :

> > Typos/names look addressed, still these though:
> > >
> > > 64 +++ include/platform/mir/input/event_sink.h
> > > this is the same interface as
> > > src/client/event_sink.h
>
> We paused our discussion with unifying both interfaces to a single
> mir::EventSink vs mir::input::EventSink.

Abstaining until we figure out why we need the 3rd interface named EventSink in the codebase :)

> > > 264 + std::initializer_list<int> fds,
> > > Fds should be mir::Fd to better manage the lifetime of the FD.
>
> I would like to do that, but I implement that interface with our glib MainLoop
> implementation which currently does not use mir::Fd. On the caller/libinput
> side I could just keep the mir::Fd to not close the fd before the libinput
> context falls out of scope, but on the callee side I would need to do
> additional tracking to fulfill that interface.
>
> Can we settle with doing that in a separate MP?

sure, although a comment or wishlist-bug would help us remember to do it later

review: Abstain
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
Robert Carr (robertcarr) wrote :

InputEventHandlerRegistrar is hard to understand as a parameter to InputDevice::start, what is an event sink vs. an event handler? perhaps PollProvider or something would be a better name.

I'm a little surprised by InputDevice::start(sink) and Platform::start(sink) since afaict we mostly use the opposite pattern. How did you arrive at this design?

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

> InputEventHandlerRegistrar is hard to understand as a parameter to
> InputDevice::start, what is an event sink vs. an event handler? perhaps
> PollProvider or something would be a better name.

But does it provide polling just because there might be epoll underneath?
It is an interface to register handlers for specific events - those events are currently: there is something to read at fd, and I just woke up (because you requested it)

> I'm a little surprised by InputDevice::start(sink) and Platform::start(sink)
> since afaict we mostly use the opposite pattern. How did you arrive at this
> design?

Passing that via the contructor and that means through the creation method of the factory would have worked too. I found the approach presented here works similar and is more explicit since now the expectations of what an implementation should behave and use are connected to its interface. That is : use that interface to handle wakeups, provide the events through that interface...

2111. By Andreas Pokorny

merged lp:mir

2112. By Andreas Pokorny

Add input_ to the platform ABI

Otherwise it collides with the graphics platform symbols. Additional this change extracts a find_best algorithm and adds two reports.

2113. By Andreas Pokorny

* New upstream release 0.10.0 (https://launchpad.net/mir/+milestone/0.10.0)
  - Enhancements:
    . Added support for Android HWC 1.3 devices.
    . Reduced build dependencies.
    . Client API: Added version macros.
    . demo-shell: Added desktop zoom feature (Super + mouse wheel).
    . TODO - more
  - ABI summary: Servers need rebuilding, but clients do not;
    . Mirclient ABI unchanged at 8
    . Mircommon ABI unchanged at 3
    . Mirplatform ABI bumped to 5
    . Mirserver ABI bumped to 28
  - Bug fixes:
    . TODO - fill this in just before release

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
Robert Carr (robertcarr) wrote :

I'm having trouble reviewing this since as it stands the bits aren't wired together...it would be nice if there were some minimum feature that could be come up with to make a test...or if we could come up with a testing input platform to replace usage of FakeEventHub...the requirements on such a platform may be able to prove the interfaces are sound.

Nonetheless mental model is starting to come together and ill try and finish review tomorrow.

2114. By Andreas Pokorny

merge lp:mir

2115. By Andreas Pokorny

moved evdev platform to platforms

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
2116. By Andreas Pokorny

[ Daniel van Vugt ]
. Plumbing/preparation to support external displays on Android devices.
. Began work on automatic driver probing, to intelligently choose the
best driver for you.
. Demo shell (mir_proving_server): Added desktop zoom feature using
Supermouse wheel.
. Demo renamed: mir_demo_server_shell -> mir_proving_server
. Other demo servers merged into -> mir_demo_server
. Wider support for display buffer pixel formats in the mesa driver, for
wider hardware support.
. Performance: On mesa/desktop at least; only hold compositor buffers
for the duration of the render, instead of the duration of the frame.
Following this change the compositor report can now finally report
render time instead of frame time.
. Mir now starts reliably when a TV is connected by HDMI, and up to
4K resolution (2160p) is known to work.
. Plenty more enhancements logged in the bugs list below.
. [regression] Mir servers (since 0.9) randomly crash in malloc due to
heap corruption (LP: #1401488)
. USCmouse cursor on AMD graphics is drawing incorrectly
(LP: #1391975)
. Mir fails to start when a TV is connected by HDMI
[std::exception::what: Invalid or inconsistent display configuration]
(LP: #1395405)
. Input/event driven clients may freeze indefinitely (LP: #1396006)
. Mir server crashes with "std::exception::what: Failed to get front
buffer object" when trying to fullscreen a surface (LP: #1398296)
. Switching windows with a Trusted Prompt Session active loses the
trusted prompt session (LP: #1355173)
. CI test failure in multiple tests (LP: #1401364)
. dh_install: usr/bin/mir_demo_server exists in debian/tmp but is not
installed to anywhere (LP: #1401365)
. [regression] demo-shell: Instead of moving surfaces they now fly
off-screen (LP: #1403702)
. [regression] Binaries are no longer runnable on other machines (or in
other directories) (LP: #1406073)
. [i865] unity-system-compositor fails to start: Failed to choose ARGB
EGL config (LP: #1212753)
. Mir's compositor holds buffers (blocking clients) for the duration of
the frame, even when not necessary. (LP: #1264934)
. Screen goes blank (black) briefly during display config changes which
don't affect the display mode (LP: #1274359)
. [enhancement] There should be a quit signal sent to sessions instead
of killing them directly (LP: #1304257)
. MirMotionEvent.action needs stronger typing (to MirMotionAction etc)
(LP: #1311699)
. CompositorReport as used by DefaultDisplayBufferCompositor can't
measure render time (LP: #1350716)
. Full screen (bypassed) surfaces (e.g. GLMark2Test) are missing frames
and appear to freeze or judder with swap interval 0 (LP: #1379685)
. Trusted prompts need to be part of the lifecycle (LP: #1384950)
. [testfail] BasicThreadPool.recycles_threads in CI (LP: #1391488)
. acceptance_tests are too chatty (LP: #1394221)
. mir_connection_create_surface callback is sometimes called twice on
error (LP: #1394873)
. File descriptor leaks in tests using UsingStubClientPlatform
(LP: #1395762)
. DisplayLayout resizes a surface to 1x1 if you ask it to fullscreen a
surface that's partially offscreen (LP: #1398294)
. Surfaces can consume input events before they're visible.
(LP: #1400218)
. dpkg-shlibdeps: Lots of warnings about libmirplatformstub.so
(LP: #1401373)
. Leaks in death tests can cause subsequent tests in the same process to
fail (LP: #1402160)
. [regression] lintian: E: mir-demos: binary-or-shlib-defines-rpath ...
(LP: #1406098)
. [regression] Mir utils can't run from the build tree any more
(LP: #1407557)
. fd reception code is not exeception-safe when unexpected numbers of
fds are received (LP: #1394362)
. Mir reports vertical refresh rates slightly inaccurately (LP: #1407558)
. [Enhancement] Add an API to lock surface orientation (LP: #1382209)
. Bootloop with system language Turkish on the Nexus 4 (LP: #1398984)
. Remove the implicit assumption that there every surface can be mapped
to an input handle. (LP: #1216727)
. When revealing hidden surfaces wait for them to become exposed before
sending events which we expect them to receive (LP: #1407783)
[ Ubuntu daily release ]
New rebuild forced

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
2117. By Andreas Pokorny

* New upstream release 0.11.0 (https://launchpad.net/mir/+milestone/0.11.0)
  - Enhancements:
    . Lots more major plumbing in the Android code, on the path to supporting
      external displays.
    . Performance: Use optimally efficient fragment shading when possible.
    . Performance: (Desktop) Composite using double buffering instead of
      triple to reduce visible lag.
    . TODO fill me in more
  - ABI summary: Servers (will?) need rebuilding, but clients do not;
    . Mirclient ABI unchanged at 8
    . Mircommon ABI unchanged at 3
    . Mirplatform ABI bumped to 6
    . Mirserver ABI unchanged at 28 (expect 29 before release)
  - Bug fixes:
    . TODO fill me in at release

2118. By Andreas Pokorny

borrowed path resolution functions from lp:server-platform-probing.
input-evdev is as an intermediate step only installed with mir-test-tools

2119. By Andreas Pokorny

deactivating keyboard support for now - in later mps this would interfere
with cross-device modifier handling, which is currently burried inside EventHub
and needs lifting to a more central location.

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
2120. By Andreas Pokorny

install evdev recordings for integration tests

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
2121. By Andreas Pokorny

install to install

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
2122. By Andreas Pokorny

reame EventSink to the more specific InputSink

2123. By Andreas Pokorny

add flags template and rename DeviceClass enumeration

2124. By Andreas Pokorny

merge lp:mir

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
2125. By Andreas Pokorny

Temporary move the evdev platform test to unit-tests until we have a better solution for running umockdev tests

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
2126. By Andreas Pokorny

do not install evdev platform yet

2127. By Andreas Pokorny

merge sha1sums conflicts

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
Revision history for this message
Cemil Azizoglu (cemil-azizoglu) wrote :

I am having a bit of a problem since this branch is not called from anywhere.

It'd be much less overwhelming to understand and review if some plumbing were introduced
first with a stub/fake input platform/devices, along with some acceptance tests, separating out
the android and libinput bits to subsequent followup branches.

The organization of the files/directories is very sensible and I think it'd be quite simple
to do that at this point since not very many people have reviewed it yet.

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

Please kill mir::Flags :)

It will confuse debuggers and developers alike if you force invalid enum values into a variable. A set of bits is just an int. For a better example see:
http://bazaar.launchpad.net/~mir-team/mir/development-branch/revision/2235#include/common/mir_toolkit/events/input/input_event.h

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

> Please kill mir::Flags :)
>
> It will confuse debuggers and developers alike if you force invalid enum
> values into a variable. A set of bits is just an int. For a better example
> see:
> http://bazaar.launchpad.net/~mir-team/mir/development-
> branch/revision/2235#include/common/mir_toolkit/events/input/input_event.h

There is no force involved an no invalid enums.

Revision history for this message
Chris Halse Rogers (raof) wrote :

I like the idea of mir::Flags; a set of flags is *not* just an int, because an int will be able to represent lots of invalid values (unless you have 32 separate flags, I guess).

I'm not sure if mir::Flags, as it currently stands, is worth it. I tried using it in add-dispatchable, and it doesn't handle some common idioms. It's also not clear to me how to improve it to support that, other than going the whole hog and doing class generation with a MIR_DEFINE_FLAGS() macro (which I'd gladly use, but am not volunteering to write ☺).

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

Oh I see you're using std::underlying_type. That should provide you with some kind of integer and allow you to remove the casts. If it doesn't then you can still change value_type to "unsigned int" and remove the casts.

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

It might also help to remove "uint32_t":
36 +enum class DeviceCapability : uint32_t

A simple "enum DeviceCapability" will work.

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

> Oh I see you're using std::underlying_type. That should provide you with some
> kind of integer and allow you to remove the casts. If it doesn't then you can
> still change value_type to "unsigned int" and remove the casts.

The casts inside Flags iteself are needed because it has to support both scoped and non-scoped enums. For scoped those are absolutely necessary and behave as intended. With c++11 enums can be forward declared since the standard now defines the underlying type to default to int32_t (iirc) - and allows manual specification in forward declaration (only for scoped..). Additionally the trait was added to resolve manually specified underlying types. I am sorry there is nothing to fix there.... just to add but more on that on monday i guess.

Unmerged revisions

2127. By Andreas Pokorny

merge sha1sums conflicts

2126. By Andreas Pokorny

do not install evdev platform yet

2125. By Andreas Pokorny

Temporary move the evdev platform test to unit-tests until we have a better solution for running umockdev tests

2124. By Andreas Pokorny

merge lp:mir

2123. By Andreas Pokorny

add flags template and rename DeviceClass enumeration

2122. By Andreas Pokorny

reame EventSink to the more specific InputSink

2121. By Andreas Pokorny

install to install

2120. By Andreas Pokorny

install evdev recordings for integration tests

2119. By Andreas Pokorny

deactivating keyboard support for now - in later mps this would interfere
with cross-device modifier handling, which is currently burried inside EventHub
and needs lifting to a more central location.

2118. By Andreas Pokorny

borrowed path resolution functions from lp:server-platform-probing.
input-evdev is as an intermediate step only installed with mir-test-tools

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== added directory 'include/platform/mir/input'
2=== added file 'include/platform/mir/input/device_capability.h'
3--- include/platform/mir/input/device_capability.h 1970-01-01 00:00:00 +0000
4+++ include/platform/mir/input/device_capability.h 2015-01-21 10:33:12 +0000
5@@ -0,0 +1,50 @@
6+/*
7+ * Copyright © 2014 Canonical Ltd.
8+ *
9+ * This program is free software: you can redistribute it and/or modify it
10+ * under the terms of the GNU Lesser General Public License version 3,
11+ * as published by the Free Software Foundation.
12+ *
13+ * This program is distributed in the hope that it will be useful,
14+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
15+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16+ * GNU Lesser General Public License for more details.
17+ *
18+ * You should have received a copy of the GNU Lesser General Public License
19+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
20+ *
21+ * Authored by: Andreas Pokorny <andreas.pokorny@canonical.com>
22+ */
23+
24+#ifndef MIR_INPUT_DEVICE_CAPABILITY_H_
25+#define MIR_INPUT_DEVICE_CAPABILITY_H_
26+
27+#include "mir/flags.h"
28+
29+#include <cstdint>
30+
31+namespace mir
32+{
33+namespace input
34+{
35+
36+enum class DeviceCapability : uint32_t
37+{
38+ unknown = 0,
39+ pointer = 1<<1,
40+ keyboard = 1<<2,
41+ touchpad = 1<<3,
42+ touchscreen = 1<<4,
43+ gamepad = 1<<5,
44+ joystick = 1<<6,
45+ switch_ = 1<<7,
46+ multitouch = 1<<8, // multitouch capable
47+ alpha_numeric = 1<<9 // enough keys for text entry
48+};
49+
50+using DeviceCapabilities = mir::Flags<DeviceCapability>;
51+
52+}
53+}
54+
55+#endif
56
57=== added file 'include/platform/mir/input/input_device.h'
58--- include/platform/mir/input/input_device.h 1970-01-01 00:00:00 +0000
59+++ include/platform/mir/input/input_device.h 2015-01-21 10:33:12 +0000
60@@ -0,0 +1,60 @@
61+/*
62+ * Copyright © 2014 Canonical Ltd.
63+ *
64+ * This program is free software: you can redistribute it and/or modify it
65+ * under the terms of the GNU Lesser General Public License version 3,
66+ * as published by the Free Software Foundation.
67+ *
68+ * This program is distributed in the hope that it will be useful,
69+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
70+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
71+ * GNU Lesser General Public License for more details.
72+ *
73+ * You should have received a copy of the GNU Lesser General Public License
74+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
75+ *
76+ * Authored by:
77+ * Andreas Pokorny <andreas.pokorny@canonical.com>
78+ */
79+
80+#ifndef MIR_INPUT_INPUT_DEVICE_H_
81+#define MIR_INPUT_INPUT_DEVICE_H_
82+
83+#include <memory>
84+
85+namespace mir
86+{
87+namespace input
88+{
89+class InputEventHandlerRegister;
90+class InputSink;
91+
92+/**
93+ * Represents an input device.
94+ */
95+class InputDevice
96+{
97+public:
98+ InputDevice() = default;
99+ virtual ~InputDevice() = default;
100+
101+ /*!
102+ * Allow the input device to provide its input events to the given InputSink
103+ */
104+ virtual void start(InputEventHandlerRegister& registry, InputSink& destination) = 0;
105+ /*!
106+ * Stop the input device from sending input events, to the InputSink.
107+ */
108+ virtual void stop(InputEventHandlerRegister& registry) = 0;
109+
110+ // TODO methods to query device description
111+protected:
112+ InputDevice(InputDevice const&) = delete;
113+ InputDevice& operator=(InputDevice const&) = delete;
114+};
115+
116+}
117+}
118+
119+#endif
120+
121
122=== added file 'include/platform/mir/input/input_device_registry.h'
123--- include/platform/mir/input/input_device_registry.h 1970-01-01 00:00:00 +0000
124+++ include/platform/mir/input/input_device_registry.h 2015-01-21 10:33:12 +0000
125@@ -0,0 +1,49 @@
126+/*
127+ * Copyright © 2014 Canonical Ltd.
128+ *
129+ * This program is free software: you can redistribute it and/or modify it
130+ * under the terms of the GNU Lesser General Public License version 3,
131+ * as published by the Free Software Foundation.
132+ *
133+ * This program is distributed in the hope that it will be useful,
134+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
135+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
136+ * GNU Lesser General Public License for more details.
137+ *
138+ * You should have received a copy of the GNU Lesser General Public License
139+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
140+ *
141+ * Authored by:
142+ * Andreas Pokorny <andreas.pokorny@canonical.com>
143+ */
144+
145+#ifndef MIR_INPUT_INPUT_DEVICE_REGISTRY_H_
146+#define MIR_INPUT_INPUT_DEVICE_REGISTRY_H_
147+
148+#include <memory>
149+
150+namespace mir
151+{
152+namespace input
153+{
154+class InputDevice;
155+
156+class InputDeviceRegistry
157+{
158+public:
159+ InputDeviceRegistry() = default;
160+ virtual ~InputDeviceRegistry() = default;
161+
162+ virtual void add_device(std::shared_ptr<InputDevice> const& device) = 0;
163+ virtual void remove_device(std::shared_ptr<InputDevice> const& device) = 0;
164+protected:
165+ InputDeviceRegistry(InputDeviceRegistry const&) = delete;
166+ InputDeviceRegistry& operator=(InputDeviceRegistry const&) = delete;
167+
168+};
169+
170+}
171+}
172+
173+#endif
174+
175
176=== added file 'include/platform/mir/input/input_event_handler_register.h'
177--- include/platform/mir/input/input_event_handler_register.h 1970-01-01 00:00:00 +0000
178+++ include/platform/mir/input/input_event_handler_register.h 2015-01-21 10:33:12 +0000
179@@ -0,0 +1,80 @@
180+/*
181+ * Copyright © 2014 Canonical Ltd.
182+ *
183+ * This program is free software: you can redistribute it and/or modify it
184+ * under the terms of the GNU Lesser General Public License version 3,
185+ * as published by the Free Software Foundation.
186+ *
187+ * This program is distributed in the hope that it will be useful,
188+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
189+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
190+ * GNU Lesser General Public License for more details.
191+ *
192+ * You should have received a copy of the GNU Lesser General Public License
193+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
194+ *
195+ * Authored by:
196+ * Andreas Pokorny <andreas.pokorny@canonical.com>
197+ */
198+
199+#ifndef MIR_INPUT_INPUT_EVENT_HANDLER_REGISTER_H_
200+#define MIR_INPUT_INPUT_EVENT_HANDLER_REGISTER_H_
201+
202+#include <functional>
203+#include <initializer_list>
204+
205+namespace mir
206+{
207+namespace input
208+{
209+
210+/**
211+ * InputEventHandler Register shall be used register handlers for different
212+ * input event or input device sources. All handlers are guaranteed to be executed in the same
213+ * thread.
214+ */
215+class InputEventHandlerRegister
216+{
217+public:
218+ InputEventHandlerRegister() = default;
219+
220+ /**
221+ * Registers a read handler for the given set of fds.
222+ *
223+ * This call does not transfer ownership of the file descriptors
224+ * in \a fds. The caller is still responsible to close when necessary.
225+ *
226+ * \param owner a distinct value to identify the caller
227+ */
228+ virtual void register_fd_handler(
229+ std::initializer_list<int> fds,
230+ void const* owner,
231+ std::function<void(int)> const&& handler) = 0;
232+
233+ /**
234+ * Unregisters the file descriptors and read handlers associated with \a
235+ * owner.
236+ *
237+ * \param owner a distinct value to identify the caller
238+ */
239+ virtual void unregister_fd_handler(void const* owner) = 0;
240+
241+ /**
242+ * Wakes the thread to execute the given \a handler once.
243+ *
244+ * This method should be used when no file descriptor is available to
245+ * indicate available input events or device changes.
246+ */
247+ virtual void register_handler(std::function<void()> const&& handler) = 0;
248+
249+protected:
250+ virtual ~InputEventHandlerRegister() = default;
251+ InputEventHandlerRegister(InputEventHandlerRegister const&) = delete;
252+ InputEventHandlerRegister& operator=(InputEventHandlerRegister const&) = delete;
253+
254+};
255+}
256+}
257+
258+#endif
259+
260
261=== renamed file 'src/include/server/mir/input/input_report.h' => 'include/platform/mir/input/input_report.h'
262--- src/include/server/mir/input/input_report.h 2015-01-14 06:39:13 +0000
263+++ include/platform/mir/input/input_report.h 2015-01-21 10:33:12 +0000
264@@ -1,16 +1,16 @@
265 /*
266- * Copyright © 2013 Canonical Ltd.
267+ * Copyright © 2013-2014 Canonical Ltd.
268 *
269 * This program is free software: you can redistribute it and/or modify it
270- * under the terms of the GNU General Public License version 3,
271+ * under the terms of the GNU Lesser General Public License version 3,
272 * as published by the Free Software Foundation.
273 *
274 * This program is distributed in the hope that it will be useful,
275 * but WITHOUT ANY WARRANTY; without even the implied warranty of
276 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
277- * GNU General Public License for more details.
278+ * GNU Lesser General Public License for more details.
279 *
280- * You should have received a copy of the GNU General Public License
281+ * You should have received a copy of the GNU Lesser General Public License
282 * along with this program. If not, see <http://www.gnu.org/licenses/>.
283 *
284 * Authored by: Alan Griffiths <alan@octopull.co.uk>
285@@ -32,6 +32,10 @@
286 public:
287 virtual ~InputReport() = default;
288
289+ virtual void open_input_device(char const* device_node) = 0;
290+
291+ virtual void failure_opening_input_device(char const* device_node) = 0;
292+
293 virtual void received_event_from_kernel(int64_t when, int type, int code, int value) = 0;
294
295 virtual void published_key_event(int dest_fd, uint32_t seq_id, int64_t event_time) = 0;
296
297=== added file 'include/platform/mir/input/input_sink.h'
298--- include/platform/mir/input/input_sink.h 1970-01-01 00:00:00 +0000
299+++ include/platform/mir/input/input_sink.h 2015-01-21 10:33:12 +0000
300@@ -0,0 +1,43 @@
301+/*
302+ * Copyright © 2014 Canonical Ltd.
303+ *
304+ * This program is free software: you can redistribute it and/or modify it
305+ * under the terms of the GNU Lesser General Public License version 3,
306+ * as published by the Free Software Foundation.
307+ *
308+ * This program is distributed in the hope that it will be useful,
309+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
310+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
311+ * GNU Lesser General Public License for more details.
312+ *
313+ * You should have received a copy of the GNU Lesser General Public License
314+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
315+ *
316+ * Authored by:
317+ * Andreas Pokorny <andreas.pokorny@canonical.com>
318+ */
319+
320+#ifndef MIR_INPUT_INPUT_SINK_H_
321+#define MIR_INPUT_INPUT_SINK_H_
322+
323+#include "mir_toolkit/event.h"
324+
325+namespace mir
326+{
327+namespace input
328+{
329+class InputSink
330+{
331+public:
332+ InputSink() = default;
333+ virtual ~InputSink() = default;
334+ // TODO change to the new mir input event
335+ virtual void handle_input(MirEvent const& event) = 0;
336+private:
337+ InputSink(InputSink const&) = delete;
338+ InputSink& operator=(InputSink const&) = delete;
339+};
340+}
341+}
342+
343+#endif
344
345=== added file 'include/platform/mir/input/platform.h'
346--- include/platform/mir/input/platform.h 1970-01-01 00:00:00 +0000
347+++ include/platform/mir/input/platform.h 2015-01-21 10:33:12 +0000
348@@ -0,0 +1,128 @@
349+/*
350+ * Copyright © 2014 Canonical Ltd.
351+ *
352+ * This program is free software: you can redistribute it and/or modify it
353+ * under the terms of the GNU Lesser General Public License version 3,
354+ * as published by the Free Software Foundation.
355+ *
356+ * This program is distributed in the hope that it will be useful,
357+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
358+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
359+ * GNU Lesser General Public License for more details.
360+ *
361+ * You should have received a copy of the GNU Lesser General Public License
362+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
363+ *
364+ * Authored by:
365+ * Andreas Pokorny <andreas.pokorny@canonical.com>
366+ */
367+
368+#ifndef MIR_INPUT_PLATFORM_H_
369+#define MIR_INPUT_PLATFORM_H_
370+
371+#include <mir/options/option.h>
372+
373+#include <boost/program_options/options_description.hpp>
374+
375+#include <memory>
376+
377+namespace mir
378+{
379+class EmergencyCleanupRegistry;
380+
381+namespace input
382+{
383+class InputEventHandlerRegister;
384+class InputDevice;
385+class InputReport;
386+class InputDeviceRegistry;
387+
388+enum class PlatformPriority : uint32_t
389+{
390+ unsupported = 0,
391+ supported = 128,
392+ best = 256,
393+};
394+
395+/**
396+ * Input Platform is used to discover and access available input devices.
397+ *
398+ * A platform implementation is supposed to handle device occurance events by
399+ * opening new device and register them at the server's InputDeviceRegistry.
400+ * Likewise the InputDeviceRegistry shall be informed about removed input devices.
401+ *
402+ * The actual processing of events is controlled through the mir::input::InputDevice interface.
403+ */
404+class Platform
405+{
406+public:
407+ Platform() = default;
408+ virtual ~Platform() = default;
409+
410+ /*!
411+ * Request the platform to start monitoring for devices.
412+ *
413+ * \param input_device_registry should be informed about available input devices
414+ * \param trigger_registry should be used to register event sources that may indicate a changes of the available devices
415+ */
416+ virtual void start(InputEventHandlerRegister& trigger_registry, std::shared_ptr<InputDeviceRegistry> const& input_device_registry) = 0;
417+ /*!
418+ * Request the platform to stop monitoring for devices.
419+ */
420+ virtual void stop(InputEventHandlerRegister& trigger_registry) = 0;
421+
422+private:
423+ Platform(Platform const&) = delete;
424+ Platform& operator=(Platform const&) = delete;
425+};
426+
427+extern "C" typedef std::unique_ptr<Platform>(*CreatePlatform)(
428+ std::shared_ptr<options::Option> const& options,
429+ std::shared_ptr<EmergencyCleanupRegistry> const& emergency_cleanup_registry,
430+ std::shared_ptr<InputReport> const& report);
431+/**
432+ * Function used to initialize an input platform.
433+ *
434+ * \param [in] options options to use for this platform
435+ * \param [in] emergency_cleanup_registry object to register emergency shutdown handlers with
436+ * \param [in] report the object to use to report interesting events from the input subsystem
437+ *
438+ * This factory function needs to be implemented by each platform.
439+ *
440+ * \ingroup platform_enablement
441+ */
442+extern "C" std::unique_ptr<Platform> create_input_platform(
443+ std::shared_ptr<options::Option> const& options,
444+ std::shared_ptr<EmergencyCleanupRegistry> const& emergency_cleanup_registry,
445+ std::shared_ptr<InputReport> const& report);
446+extern "C" typedef void(*AddPlatformOptions)(
447+ boost::program_options::options_description& config);
448+/**
449+ * Function used to add additional configuration options
450+ *
451+ * \param [in] config program option description that the platform may extend
452+ *
453+ * This function needs to be implemented by each platform.
454+ *
455+ * \ingroup platform_enablement
456+ */
457+extern "C" void add_input_platform_options(
458+ boost::program_options::options_description& config);
459+extern "C" typedef PlatformPriority(*ProbePlatform)(
460+ options::Option const& options);
461+/**
462+ * probe_platform should indicate whether the platform is able to work within
463+ * the current environment.
464+ *
465+ * \param [in] options program options of the mir server
466+ *
467+ * This function needs to be implemented by each platform.
468+ *
469+ * \ingroup platform_enablement
470+ */
471+extern "C" PlatformPriority probe_input_platform(
472+ options::Option const& options);
473+}
474+}
475+
476+#endif // MIR_INPUT_PLATFORM_H_
477
478=== modified file 'platform-ABI-sha1sums'
479--- platform-ABI-sha1sums 2015-01-20 03:21:20 +0000
480+++ platform-ABI-sha1sums 2015-01-21 10:33:12 +0000
481@@ -54,4 +54,11 @@
482 1b77fb3290af00dc7d1c11dcc5388972dacb9ec3 include/platform/mir/graphics/platform_ipc_package.h
483 f0db0484b8ccc9091e73c80a2a200cb436b48bfb include/platform/mir/graphics/platform_operation_message.h
484 f18876766861e5d4f5ca999dbd176fe1fc520594 include/platform/mir/graphics/renderable.h
485+ab9801389eba1c35fcfb021fca667279244c26ac include/platform/mir/input/device_capability.h
486+12ff36cfe9fd3e99614e9e315845a63156d2798a include/platform/mir/input/input_device.h
487+4f17d5e7b69448ececbc07dee3653a1f0f4dfc89 include/platform/mir/input/input_device_registry.h
488+b59d7132b9f4360ef4cf5af4ed0255c00f897dc7 include/platform/mir/input/input_event_handler_register.h
489+4e502d4a5fdff4ed1a65ba1f0183113f787285ab include/platform/mir/input/input_report.h
490+00a7d63dcd22107590497b57877c1893eed24d32 include/platform/mir/input/input_sink.h
491+897648fdf3531bd57830454f8e9c775a6b53aa0d include/platform/mir/input/platform.h
492 b45f14082c4f8b29efaa1b13de795dcb29deb738 include/platform/mir/options/option.h
493
494=== modified file 'server-ABI-sha1sums'
495--- server-ABI-sha1sums 2015-01-21 08:38:18 +0000
496+++ server-ABI-sha1sums 2015-01-21 10:33:12 +0000
497@@ -54,6 +54,13 @@
498 1b77fb3290af00dc7d1c11dcc5388972dacb9ec3 include/platform/mir/graphics/platform_ipc_package.h
499 f0db0484b8ccc9091e73c80a2a200cb436b48bfb include/platform/mir/graphics/platform_operation_message.h
500 f18876766861e5d4f5ca999dbd176fe1fc520594 include/platform/mir/graphics/renderable.h
501+ab9801389eba1c35fcfb021fca667279244c26ac include/platform/mir/input/device_capability.h
502+12ff36cfe9fd3e99614e9e315845a63156d2798a include/platform/mir/input/input_device.h
503+4f17d5e7b69448ececbc07dee3653a1f0f4dfc89 include/platform/mir/input/input_device_registry.h
504+b59d7132b9f4360ef4cf5af4ed0255c00f897dc7 include/platform/mir/input/input_event_handler_register.h
505+4e502d4a5fdff4ed1a65ba1f0183113f787285ab include/platform/mir/input/input_report.h
506+00a7d63dcd22107590497b57877c1893eed24d32 include/platform/mir/input/input_sink.h
507+897648fdf3531bd57830454f8e9c775a6b53aa0d include/platform/mir/input/platform.h
508 b45f14082c4f8b29efaa1b13de795dcb29deb738 include/platform/mir/options/option.h
509 f4030e400baf8baa9c38e7c6ec6b4a5ad7134aeb include/server/mir/compositor/compositor.h
510 a9f284ba4b05d58fd3eeb628d1f56fe4ac188526 include/server/mir/compositor/compositor_id.h
511
512=== modified file 'src/CMakeLists.txt'
513--- src/CMakeLists.txt 2015-01-14 06:39:13 +0000
514+++ src/CMakeLists.txt 2015-01-21 10:33:12 +0000
515@@ -2,6 +2,8 @@
516 # and the platform implementations.
517 set(MIRPLATFORM_ABI 6)
518
519+set(MIR_SERVER_INPUT_PLATFORM_VERSION "MIR_INPUT_PLATFORM_1")
520+
521 set(PLATFORM_DRIVER platform${MIRPLATFORM_ABI}driver)
522 set(MIR_PLATFORM_DRIVER mir${PLATFORM_DRIVER})
523 set(MIR_PLATFORM_DRIVER_BINARY lib${MIR_PLATFORM_DRIVER}.so
524@@ -40,4 +42,6 @@
525 set(MIR_PLATFORM_REFERENCES ${MIR_PLATFORM_REFERENCES} PARENT_SCOPE)
526 set(MIR_COMMON_OBJECTS ${MIR_COMMON_OBJECTS} PARENT_SCOPE)
527 set(MIR_COMMON_REFERENCES ${MIR_COMMON_REFERENCES} PARENT_SCOPE)
528+set(MIR_SERVER_INPUT_PLATFORM_VERSION ${MIR_SERVER_INPUT_PLATFORM_VERSION} PARENT_SCOPE)
529 set(MIR_CLIENT_PLATFORM_PATH ${MIR_CLIENT_PLATFORM_PATH} PARENT_SCOPE)
530+set(MIR_SERVER_PLATFORM_PATH ${MIR_SERVER_PLATFORM_PATH} PARENT_SCOPE)
531
532=== added file 'src/include/common/mir/find_best.h'
533--- src/include/common/mir/find_best.h 1970-01-01 00:00:00 +0000
534+++ src/include/common/mir/find_best.h 2015-01-21 10:33:12 +0000
535@@ -0,0 +1,67 @@
536+/*
537+ * Copyright © 2014 Canonical Ltd.
538+ *
539+ * This program is free software: you can redistribute it and/or modify it
540+ * under the terms of the GNU Lesser General Public License version 3,
541+ * as published by the Free Software Foundation.
542+ *
543+ * This program is distributed in the hope that it will be useful,
544+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
545+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
546+ * GNU Lesser General Public License for more details.
547+ *
548+ * You should have received a copy of the GNU Lesser General Public License
549+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
550+ *
551+ * Authored by: Andeas Pokorny <andreas.pokorny@canonical.com>
552+ */
553+
554+#ifndef MIR_FIND_BEST_H_
555+#define MIR_FIND_BEST_H_
556+
557+#include <functional>
558+
559+namespace mir
560+{
561+
562+struct Greater // replace in favor of std::greater<> when we switch to c++14
563+{
564+ template<typename T>
565+ bool operator()(T const& l, T const& r) const
566+ {
567+ return l > r;
568+ }
569+};
570+
571+/**
572+ * \brief Range based algorithm to find the best suited item.
573+ *
574+ * Use this instead of std::max_element or std::min_element, when
575+ * the comparision involves a costly test, as it caches the test result
576+ * of the individual best candidate. To acchieve that the predicate is
577+ * split in a predicate and a transformation.
578+ */
579+template<typename Container, typename Transform, typename Predicate = Greater>
580+auto find_best(Container const& items, Transform const& transform,
581+ decltype(transform(*items.begin())) const& initial_best,
582+ Predicate const& pred = Greater{})
583+-> decltype(begin(items))
584+{
585+ auto current_best_it = end(items);
586+ auto current_best = initial_best;
587+ for (auto it = begin(items), e = end(items);
588+ it != e; ++it)
589+ {
590+ auto item_transformed = transform(*it);
591+
592+ if (pred(item_transformed, current_best))
593+ {
594+ current_best = item_transformed;
595+ current_best_it = it;
596+ }
597+ }
598+ return current_best_it;
599+}
600+}
601+
602+#endif
603
604=== added file 'src/include/common/mir/flags.h'
605--- src/include/common/mir/flags.h 1970-01-01 00:00:00 +0000
606+++ src/include/common/mir/flags.h 2015-01-21 10:33:12 +0000
607@@ -0,0 +1,118 @@
608+/*
609+ * Copyright © 2015 Canonical Ltd.
610+ *
611+ * This program is free software: you can redistribute it and/or modify it
612+ * under the terms of the GNU Lesser General Public License version 3,
613+ * as published by the Free Software Foundation.
614+ *
615+ * This program is distributed in the hope that it will be useful,
616+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
617+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
618+ * GNU Lesser General Public License for more details.
619+ *
620+ * You should have received a copy of the GNU Lesser General Public License
621+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
622+ *
623+ * Authored By: Andreas Pokorny <andreas.pokorny@canonical.com>
624+ */
625+
626+#ifndef MIR_FLAGS_H_
627+#define MIR_FLAGS_H_
628+
629+#include <type_traits>
630+
631+namespace mir
632+{
633+
634+/*!
635+ * Treat an enumeration, scoped and unscoped, like a set of flags
636+ */
637+template<typename Enum>
638+struct Flags
639+{
640+ using value_type = typename std::underlying_type<Enum>::type;
641+ value_type value;
642+
643+ explicit constexpr Flags(value_type value = 0) noexcept
644+ : value{value} {}
645+ constexpr Flags(Enum value) noexcept
646+ : value{static_cast<value_type>(value)} {}
647+
648+ constexpr Flags<Enum> operator|(Flags<Enum> other) const noexcept
649+ {
650+ return Flags<Enum>(value|other.value);
651+ }
652+
653+ constexpr Flags<Enum> operator&(Flags<Enum> other) const noexcept
654+ {
655+ return Flags<Enum>(value & other.value);
656+ }
657+
658+#ifdef __clang__
659+#pragma clang diagnostic push
660+#pragma clang diagnostic ignored "-Wconstexpr-not-const"
661+#endif
662+ constexpr Flags<Enum>& operator|=(Flags<Enum> other) noexcept
663+ {
664+ return value |= other.value, *this;
665+ }
666+
667+ constexpr Flags<Enum> operator&=(Flags<Enum> other) noexcept
668+ {
669+ return value &= other.value, *this;
670+ }
671+#ifdef __clang__
672+#pragma clang diagnostic pop
673+#endif
674+
675+ constexpr bool operator==(Flags<Enum> other) const noexcept
676+ {
677+ return value == other.value;
678+ }
679+};
680+
681+template<typename Enum>
682+constexpr Flags<Enum> operator|(Flags<Enum> flags, Enum e) noexcept
683+{
684+ return Flags<Enum>(flags.value | static_cast<decltype(flags.value)>(e));
685+}
686+
687+template<typename Enum>
688+constexpr Flags<Enum> operator|(Enum e, Flags<Enum> flags) noexcept
689+{
690+ return Flags<Enum>(flags.value | static_cast<decltype(flags.value)>(e));
691+}
692+
693+template<typename Enum>
694+constexpr Enum operator&(Enum e, Flags<Enum> flags) noexcept
695+{
696+ return static_cast<Enum>(flags.value & static_cast<decltype(flags.value)>(e));
697+}
698+
699+template<typename Enum>
700+constexpr Enum operator&(Flags<Enum> flags, Enum e) noexcept
701+{
702+ return static_cast<Enum>(flags.value & static_cast<decltype(flags.value)>(e));
703+}
704+
705+template<typename Enum>
706+constexpr bool operator==(Flags<Enum> flags, Enum e) noexcept
707+{
708+ return e == static_cast<Enum>(flags.value);
709+}
710+
711+template<typename Enum>
712+constexpr bool operator==(Enum e, Flags<Enum> flags) noexcept
713+{
714+ return e == static_cast<Enum>(flags.value);
715+}
716+
717+template<typename Enum>
718+constexpr bool contains(Flags<Enum> flags, Enum e) noexcept
719+{
720+ return e == static_cast<Enum>(flags.value & static_cast<decltype(flags.value)>(e));
721+}
722+
723+}
724+
725+#endif
726
727=== modified file 'src/platform/CMakeLists.txt'
728--- src/platform/CMakeLists.txt 2015-01-14 06:39:13 +0000
729+++ src/platform/CMakeLists.txt 2015-01-21 10:33:12 +0000
730@@ -44,6 +44,8 @@
731
732 install(TARGETS mirplatform LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR})
733
734+add_definitions(-DMIR_SERVER_INPUT_PLATFORM_VERSION="${MIR_SERVER_INPUT_PLATFORM_VERSION}")
735+
736 add_subdirectory(graphics/)
737 add_subdirectory(options)
738 add_subdirectory(fatal)
739
740=== modified file 'src/platforms/CMakeLists.txt'
741--- src/platforms/CMakeLists.txt 2014-12-12 17:56:20 +0000
742+++ src/platforms/CMakeLists.txt 2015-01-21 10:33:12 +0000
743@@ -1,3 +1,11 @@
744+set(MIR_SERVER_PLATFORM_PATH
745+ ${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_LIBDIR}/mir/server-platform
746+)
747+set(MIR_SERVER_PLATFORM_PATH
748+ ${MIR_SERVER_PLATFORM_PATH}
749+ PARENT_SCOPE
750+)
751+
752 include_directories(
753 ${PROJECT_SOURCE_DIR}/include/platform
754 )
755@@ -9,6 +17,7 @@
756 )
757
758 set(symbol_map ${CMAKE_CURRENT_SOURCE_DIR}/symbols.map)
759+set(input_platform_symbol_map ${CMAKE_CURRENT_SOURCE_DIR}/input-platform-symbols.map)
760
761 if (MIR_BUILD_PLATFORM_MESA)
762 add_subdirectory(mesa/)
763@@ -17,3 +26,7 @@
764 if (MIR_BUILD_PLATFORM_ANDROID)
765 add_subdirectory(android/)
766 endif()
767+
768+add_definitions(-DMIR_SERVER_INPUT_PLATFORM_VERSION="${MIR_SERVER_INPUT_PLATFORM_VERSION}")
769+
770+add_subdirectory(evdev/)
771
772=== added directory 'src/platforms/evdev'
773=== added file 'src/platforms/evdev/CMakeLists.txt'
774--- src/platforms/evdev/CMakeLists.txt 1970-01-01 00:00:00 +0000
775+++ src/platforms/evdev/CMakeLists.txt 2015-01-21 10:33:12 +0000
776@@ -0,0 +1,24 @@
777+add_library(mirplatforminputevdevobjects OBJECT
778+ android_device_provider.cpp
779+ evdev_device_detection.cpp
780+ evdev_input_device_factory.cpp
781+ libinput_device_provider.cpp
782+ )
783+
784+add_library(mirplatforminputevdev SHARED
785+ platform.cpp
786+ $<TARGET_OBJECTS:mirplatforminputevdevobjects>
787+)
788+
789+set_target_properties(
790+ mirplatforminputevdev PROPERTIES
791+ OUTPUT_NAME input-evdev
792+ LIBRARY_OUTPUT_DIRECTORY ${LIBRARY_OUTPUT_PATH}/server-modules
793+ PREFIX ""
794+ LINK_FLAGS "-Wl,--exclude-libs=ALL -Wl,--version-script,${input_platform_symbol_map}"
795+)
796+
797+target_link_libraries(mirplatforminputevdev
798+ mirplatform
799+ ${Boost_PROGRAM_OPTIONS_LIBRARY}
800+)
801
802=== added file 'src/platforms/evdev/android_device_provider.cpp'
803--- src/platforms/evdev/android_device_provider.cpp 1970-01-01 00:00:00 +0000
804+++ src/platforms/evdev/android_device_provider.cpp 2015-01-21 10:33:12 +0000
805@@ -0,0 +1,48 @@
806+/*
807+ * Copyright © 2014 Canonical Ltd.
808+ *
809+ * This program is free software: you can redistribute it and/or modify it
810+ * under the terms of the GNU Lesser General Public License version 3,
811+ * as published by the Free Software Foundation.
812+ *
813+ * This program is distributed in the hope that it will be useful,
814+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
815+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
816+ * GNU Lesser General Public License for more details.
817+ *
818+ * You should have received a copy of the GNU Lesser General Public License
819+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
820+ *
821+ * Authored by: Andreas Pokorny <andreas.pokorny@canonical.com>
822+ */
823+
824+#include "android_device_provider.h"
825+#include "evdev_device_detection.h"
826+
827+#include "mir/input/device_capability.h"
828+#include "mir/input/input_device.h"
829+
830+namespace mi = mir::input;
831+namespace mie = mi::evdev;
832+
833+mie::Priority mie::AndroidDeviceProvider::probe_device(char const* device) const
834+{
835+ auto device_caps = detect_device_capabilities(device);
836+
837+ if (contains(device_caps, DeviceCapability::touchscreen))
838+ return Priority::best;
839+
840+ if (contains(device_caps, DeviceCapability::touchpad))
841+ return Priority::unsupported;
842+
843+ if (device_caps == DeviceCapability::unknown)
844+ return Priority::unsupported;
845+
846+ return Priority::supported;
847+}
848+
849+std::unique_ptr<mi::InputDevice> mie::AndroidDeviceProvider::create_device(char const* /*device*/) const
850+{
851+ return std::unique_ptr<mi::InputDevice>();
852+}
853+
854
855=== added file 'src/platforms/evdev/android_device_provider.h'
856--- src/platforms/evdev/android_device_provider.h 1970-01-01 00:00:00 +0000
857+++ src/platforms/evdev/android_device_provider.h 2015-01-21 10:33:12 +0000
858@@ -0,0 +1,42 @@
859+/*
860+ * Copyright © 2014 Canonical Ltd.
861+ *
862+ * This program is free software: you can redistribute it and/or modify it
863+ * under the terms of the GNU Lesser General Public License version 3,
864+ * as published by the Free Software Foundation.
865+ *
866+ * This program is distributed in the hope that it will be useful,
867+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
868+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
869+ * GNU Lesser General Public License for more details.
870+ *
871+ * You should have received a copy of the GNU Lesser General Public License
872+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
873+ *
874+ * Authored by: Andreas Pokorny <andreas.pokorny@canonical.com>
875+ */
876+
877+#ifndef MIR_INPUT_EVDEV_ANDROID_DEVICE_PROVIDER_H_
878+#define MIR_INPUT_EVDEV_ANDROID_DEVICE_PROVIDER_H_
879+
880+#include "input_device_provider.h"
881+
882+namespace mir
883+{
884+namespace input
885+{
886+namespace evdev
887+{
888+
889+class AndroidDeviceProvider : public InputDeviceProvider
890+{
891+public:
892+ Priority probe_device(char const* path) const override;
893+ std::unique_ptr<InputDevice> create_device(char const* path) const override;
894+};
895+
896+}
897+}
898+}
899+
900+#endif // MIR_INPUT_EVDEV_ANDROID_DEVICE_PROVIDER_H_
901
902=== added file 'src/platforms/evdev/evdev_device_detection.cpp'
903--- src/platforms/evdev/evdev_device_detection.cpp 1970-01-01 00:00:00 +0000
904+++ src/platforms/evdev/evdev_device_detection.cpp 2015-01-21 10:33:12 +0000
905@@ -0,0 +1,163 @@
906+/*
907+ * Copyright © 2014 Canonical Ltd.
908+ *
909+ * This program is free software: you can redistribute it and/or modify it
910+ * under the terms of the GNU Lesser General Public License version 3,
911+ * as published by the Free Software Foundation.
912+ *
913+ * This program is distributed in the hope that it will be useful,
914+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
915+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
916+ * GNU Lesser General Public License for more details.
917+ *
918+ * You should have received a copy of the GNU Lesser General Public License
919+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
920+ *
921+ * Authored by: Andreas Pokorny <andreas.pokorny@canonical.com>
922+ */
923+
924+#include "evdev_device_detection.h"
925+#include "mir/fd.h"
926+
927+#include <boost/exception/errinfo_errno.hpp>
928+#include <boost/exception/errinfo_file_name.hpp>
929+#include <boost/throw_exception.hpp>
930+
931+#include <linux/input.h>
932+
933+#include <sys/types.h>
934+#include <sys/stat.h>
935+#include <fcntl.h>
936+
937+#include <cstring>
938+#include <system_error>
939+
940+namespace mi = mir::input;
941+namespace mie = mi::evdev;
942+
943+namespace
944+{
945+
946+struct DeviceInfo
947+{
948+ uint8_t key_bit_mask[(KEY_MAX+1)/8];
949+ uint8_t abs_bit_mask[(ABS_MAX+1)/8];
950+ uint8_t rel_bit_mask[(REL_MAX+1)/8];
951+ uint8_t sw_bit_mask[(SW_MAX+1)/8];
952+ uint8_t property_bit_mask[(INPUT_PROP_MAX+1)/8];
953+};
954+
955+void fill_device_info(DeviceInfo& info, int fd)
956+{
957+ std::memset(&info, 0, sizeof info);
958+
959+ auto const get_bitmask = [&](int bit, size_t size, uint8_t* buf) -> void
960+ {
961+ if(ioctl(fd, EVIOCGBIT(bit, size), buf) < 1)
962+ BOOST_THROW_EXCEPTION(
963+ std::system_error(std::error_code(errno, std::system_category()),
964+ "Failed to query input device"));
965+ };
966+ get_bitmask(EV_KEY, sizeof info.key_bit_mask, info.key_bit_mask);
967+ get_bitmask(EV_REL, sizeof info.rel_bit_mask, info.rel_bit_mask);
968+ get_bitmask(EV_ABS, sizeof info.abs_bit_mask, info.abs_bit_mask);
969+ get_bitmask(EV_SW, sizeof info.sw_bit_mask, info.sw_bit_mask);
970+
971+ if (ioctl(fd, EVIOCGPROP(sizeof info.property_bit_mask), info.property_bit_mask) < 1)
972+ BOOST_THROW_EXCEPTION(
973+ std::system_error(std::error_code(errno, std::system_category()),
974+ "Failed to query devices properties"));
975+
976+}
977+
978+constexpr size_t index_of_bit(size_t bit)
979+{
980+ return (bit + 7) / 8;
981+}
982+inline bool get_bit(uint8_t const* array, size_t bit)
983+{
984+ return array[bit/8] & (1<<(bit%8));
985+}
986+
987+inline size_t get_num_bits(uint8_t const* array, std::initializer_list<size_t> bits)
988+{
989+ size_t ret = 0;
990+ for( auto const bit : bits)
991+ ret += get_bit(array, bit);
992+ return ret;
993+}
994+
995+mi::DeviceCapabilities evaluate_device_capabilities(DeviceInfo const& info)
996+{
997+ mi::DeviceCapabilities caps;
998+
999+ auto const contains_non_zero = [](uint8_t const* array, int first, int last) -> bool
1000+ {
1001+ return std::any_of(array + first, array + last, [](uint8_t item) { return item!=0;});
1002+ };
1003+
1004+ bool const has_keys = contains_non_zero(info.key_bit_mask, 0, index_of_bit(BTN_MISC))
1005+ || contains_non_zero(info.key_bit_mask, index_of_bit(KEY_OK), sizeof info.key_bit_mask);
1006+
1007+ bool const has_gamepad_buttons =
1008+ contains_non_zero(info.key_bit_mask, index_of_bit(BTN_MISC), index_of_bit(BTN_MOUSE))
1009+ || contains_non_zero(info.key_bit_mask, index_of_bit(BTN_JOYSTICK), index_of_bit(BTN_DIGI));
1010+
1011+ bool const has_coordinates = get_bit(info.abs_bit_mask, ABS_X) &&
1012+ get_bit(info.abs_bit_mask, ABS_Y);
1013+
1014+ bool const has_mt_coordinates = get_bit(info.abs_bit_mask, ABS_MT_POSITION_X) &&
1015+ get_bit(info.abs_bit_mask, ABS_MT_POSITION_Y);
1016+
1017+ bool const is_direct = get_bit(info.property_bit_mask, INPUT_PROP_DIRECT);
1018+
1019+ bool const finger_but_no_pen = get_bit(info.key_bit_mask, BTN_TOOL_FINGER)
1020+ && !get_bit(info.key_bit_mask, BTN_TOOL_PEN);
1021+
1022+ bool const has_touch = get_bit(info.key_bit_mask, BTN_TOUCH);
1023+
1024+ bool const has_joystick_axis = 0 < get_num_bits(
1025+ info.abs_bit_mask, {ABS_Z,
1026+ ABS_RX, ABS_RY, ABS_RZ,
1027+ ABS_THROTTLE, ABS_RUDDER, ABS_WHEEL, ABS_GAS, ABS_BRAKE,
1028+ ABS_HAT0X, ABS_HAT0Y, ABS_HAT1X, ABS_HAT1Y, ABS_HAT2X, ABS_HAT2Y, ABS_HAT3X, ABS_HAT3Y,
1029+ ABS_TILT_X, ABS_TILT_Y
1030+ });
1031+
1032+ if (has_keys || has_gamepad_buttons)
1033+ caps = caps | mi::DeviceCapability::keyboard;
1034+
1035+ if (get_bit(info.key_bit_mask, BTN_MOUSE) && get_bit(info.rel_bit_mask, REL_X) && get_bit(info.rel_bit_mask, REL_Y))
1036+ caps = caps | mi::DeviceCapability::pointer;
1037+
1038+ if (finger_but_no_pen && !is_direct && (has_coordinates|| has_mt_coordinates))
1039+ caps = caps | mi::DeviceCapability::touchpad;
1040+ else if (has_touch && ((has_mt_coordinates && !has_gamepad_buttons)
1041+ || has_coordinates))
1042+ caps = caps | mi::DeviceCapability::touchscreen;
1043+
1044+ if (has_joystick_axis || (!has_touch && has_coordinates))
1045+ caps = caps | mi::DeviceCapability::joystick;
1046+
1047+ if (has_gamepad_buttons)
1048+ caps = caps | mi::DeviceCapability::gamepad;
1049+
1050+ return caps;
1051+}
1052+
1053+}
1054+
1055+mi::DeviceCapabilities mie::detect_device_capabilities(char const* device)
1056+{
1057+ mir::Fd input_device(::open(device, O_RDONLY|O_NONBLOCK));
1058+ if (input_device < 0)
1059+ BOOST_THROW_EXCEPTION(
1060+ std::system_error(std::error_code(errno, std::system_category()),
1061+ "Failed to open input device"));
1062+
1063+ DeviceInfo info;
1064+
1065+ fill_device_info(info, input_device);
1066+ return evaluate_device_capabilities(info);
1067+}
1068+
1069
1070=== added file 'src/platforms/evdev/evdev_device_detection.h'
1071--- src/platforms/evdev/evdev_device_detection.h 1970-01-01 00:00:00 +0000
1072+++ src/platforms/evdev/evdev_device_detection.h 2015-01-21 10:33:12 +0000
1073@@ -0,0 +1,35 @@
1074+/*
1075+ * Copyright © 2014 Canonical Ltd.
1076+ *
1077+ * This program is free software: you can redistribute it and/or modify it
1078+ * under the terms of the GNU Lesser General Public License version 3,
1079+ * as published by the Free Software Foundation.
1080+ *
1081+ * This program is distributed in the hope that it will be useful,
1082+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
1083+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1084+ * GNU Lesser General Public License for more details.
1085+ *
1086+ * You should have received a copy of the GNU Lesser General Public License
1087+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
1088+ *
1089+ * Authored by: Andreas Pokorny <andreas.pokorny@canonical.com>
1090+ */
1091+
1092+#ifndef MIR_INPUT_EVDEV_DEVICE_DETECTION_H_
1093+#define MIR_INPUT_EVDEV_DEVICE_DETECTION_H_
1094+
1095+#include "mir/input/device_capability.h"
1096+
1097+namespace mir
1098+{
1099+namespace input
1100+{
1101+namespace evdev
1102+{
1103+input::DeviceCapabilities detect_device_capabilities(char const* device);
1104+}
1105+}
1106+}
1107+
1108+#endif
1109
1110=== added file 'src/platforms/evdev/evdev_input_device_factory.cpp'
1111--- src/platforms/evdev/evdev_input_device_factory.cpp 1970-01-01 00:00:00 +0000
1112+++ src/platforms/evdev/evdev_input_device_factory.cpp 2015-01-21 10:33:12 +0000
1113@@ -0,0 +1,58 @@
1114+/*
1115+ * Copyright © 2013-2014 Canonical Ltd.
1116+ *
1117+ * This program is free software: you can redistribute it and/or modify
1118+ * it under the terms of the GNU Lesser General Public License version 3 as
1119+ * published by the Free Software Foundation.
1120+ *
1121+ * This program is distributed in the hope that it will be useful,
1122+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
1123+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1124+ * GNU Lesser General Public License for more details.
1125+ *
1126+ * You should have received a copy of the GNU Lesser General Public License
1127+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
1128+ *
1129+ * Authored by: Christopher Halse Rogers <christopher.halse.rogers@canonical.com>
1130+ * Andreas Pokorny <andreas.pokorny@canonical.com>
1131+ */
1132+
1133+#include "evdev_input_device_factory.h"
1134+#include "input_device_provider.h"
1135+
1136+#include "mir/find_best.h"
1137+#include "mir/input/input_device.h"
1138+
1139+#include <stdexcept>
1140+
1141+namespace mi = mir::input;
1142+namespace mie = mi::evdev;
1143+
1144+mie::EvdevInputDeviceFactory::EvdevInputDeviceFactory(std::initializer_list<std::shared_ptr<mie::InputDeviceProvider>> providers)
1145+ : providers(providers)
1146+{
1147+}
1148+
1149+std::unique_ptr<mi::InputDevice> mie::EvdevInputDeviceFactory::create_device(char const* device)
1150+{
1151+ auto best_provider = find_best(
1152+ providers,
1153+ [device](std::shared_ptr<InputDeviceProvider> const& provider) -> Priority
1154+ {
1155+ try
1156+ {
1157+ return provider->probe_device(device);
1158+ }
1159+ catch(...)
1160+ {
1161+ return Priority::unsupported;
1162+ }
1163+ },
1164+ Priority::unsupported
1165+ );
1166+
1167+ if (best_provider != end(providers))
1168+ return std::move((*best_provider)->create_device(device));
1169+
1170+ throw std::runtime_error("Failed to open input device");
1171+}
1172
1173=== added file 'src/platforms/evdev/evdev_input_device_factory.h'
1174--- src/platforms/evdev/evdev_input_device_factory.h 1970-01-01 00:00:00 +0000
1175+++ src/platforms/evdev/evdev_input_device_factory.h 2015-01-21 10:33:12 +0000
1176@@ -0,0 +1,52 @@
1177+/*
1178+ * Copyright © 2013-2014 Canonical Ltd.
1179+ *
1180+ * This program is free software: you can redistribute it and/or modify it
1181+ * under the terms of the GNU Lesser General Public License version 3,
1182+ * as published by the Free Software Foundation.
1183+ *
1184+ * This program is distributed in the hope that it will be useful,
1185+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
1186+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1187+ * GNU Lesser General Public License for more details.
1188+ *
1189+ * You should have received a copy of the GNU Lesser General Public License
1190+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
1191+ *
1192+ * Authored by: Christopher Halse Rogers <christopher.halse.rogers@canonical.com>
1193+ * Andreas Pokorny <andreas.pokorny@canonical.com>
1194+ */
1195+
1196+#ifndef MIR_INPUT_EVDEV_EVDEV_INPUT_DEVICE_FACTORY_H_
1197+#define MIR_INPUT_EVDEV_EVDEV_INPUT_DEVICE_FACTORY_H_
1198+
1199+#include "input_device_factory.h"
1200+
1201+#include <memory>
1202+#include <vector>
1203+#include <initializer_list>
1204+
1205+namespace mir
1206+{
1207+namespace input
1208+{
1209+namespace evdev
1210+{
1211+class InputDeviceProvider;
1212+
1213+class EvdevInputDeviceFactory : public InputDeviceFactory
1214+{
1215+public:
1216+ EvdevInputDeviceFactory(std::initializer_list<std::shared_ptr<InputDeviceProvider>> providers);
1217+
1218+ std::unique_ptr<InputDevice> create_device(char const* devcie_node) override;
1219+
1220+private:
1221+ std::vector<std::shared_ptr<InputDeviceProvider>> providers;
1222+};
1223+
1224+}
1225+}
1226+} // namespace mir
1227+
1228+#endif // MIR_INPUT_EVDEV_INPUT_DEVICE_FACTORY_H_
1229
1230=== added file 'src/platforms/evdev/input_device_factory.h'
1231--- src/platforms/evdev/input_device_factory.h 1970-01-01 00:00:00 +0000
1232+++ src/platforms/evdev/input_device_factory.h 2015-01-21 10:33:12 +0000
1233@@ -0,0 +1,50 @@
1234+/*
1235+ * Copyright © 2013-2014 Canonical Ltd.
1236+ *
1237+ * This program is free software: you can redistribute it and/or modify it
1238+ * under the terms of the GNU Lesser General Public License version 3,
1239+ * as published by the Free Software Foundation.
1240+ *
1241+ * This program is distributed in the hope that it will be useful,
1242+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
1243+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1244+ * GNU Lesser General Public License for more details.
1245+ *
1246+ * You should have received a copy of the GNU Lesser General Public License
1247+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
1248+ *
1249+ * Authored by: Christopher Halse Rogers <christopher.halse.rogers@canonical.com>
1250+ * Andreas Pokorny <andreas.pokorny@canonical.com>
1251+ */
1252+
1253+#ifndef MIR_INPUT_INPUT_DEVICE_FACTORY_H_
1254+#define MIR_INPUT_INPUT_DEVICE_FACTORY_H_
1255+
1256+#include <memory>
1257+
1258+namespace mir
1259+{
1260+namespace input
1261+{
1262+class InputDevice;
1263+namespace evdev
1264+{
1265+
1266+class InputDeviceFactory
1267+{
1268+public:
1269+ InputDeviceFactory() = default;
1270+ virtual ~InputDeviceFactory() = default;
1271+
1272+ virtual std::unique_ptr<InputDevice> create_device(char const* device_node) = 0;
1273+
1274+protected:
1275+ InputDeviceFactory(InputDeviceFactory const&) = delete;
1276+ InputDeviceFactory& operator=(InputDeviceFactory const&) = delete;
1277+};
1278+
1279+}
1280+}
1281+} // namespace mir
1282+
1283+#endif // MIR_INPUT_INPUT_DEVICE_FACTORY_H_
1284
1285=== added file 'src/platforms/evdev/input_device_provider.h'
1286--- src/platforms/evdev/input_device_provider.h 1970-01-01 00:00:00 +0000
1287+++ src/platforms/evdev/input_device_provider.h 2015-01-21 10:33:12 +0000
1288@@ -0,0 +1,59 @@
1289+/*
1290+ * Copyright © 2013-2014 Canonical Ltd.
1291+ *
1292+ * This program is free software: you can redistribute it and/or modify it
1293+ * under the terms of the GNU Lesser General Public License version 3,
1294+ * as published by the Free Software Foundation.
1295+ *
1296+ * This program is distributed in the hope that it will be useful,
1297+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
1298+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1299+ * GNU Lesser General Public License for more details.
1300+ *
1301+ * You should have received a copy of the GNU Lesser General Public License
1302+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
1303+ *
1304+ * Authored by: Christopher Halse Rogers <christopher.halse.rogers@canonical.com>
1305+ * Andreas Pokorny <andreas.pokorny@canonical.com>
1306+ */
1307+
1308+#ifndef MIR_INPUT_EVDEV_INPUT_DEVICE_PROVIDER_H_
1309+#define MIR_INPUT_EVDEV_INPUT_DEVICE_PROVIDER_H_
1310+
1311+#include <memory>
1312+
1313+namespace mir
1314+{
1315+namespace input
1316+{
1317+class InputDevice;
1318+
1319+namespace evdev
1320+{
1321+
1322+enum class Priority : uint32_t
1323+{
1324+ unsupported = 0,
1325+ supported = 100,
1326+ best = 255,
1327+};
1328+
1329+class InputDeviceProvider
1330+{
1331+public:
1332+ InputDeviceProvider() = default;
1333+ virtual ~InputDeviceProvider() = default;
1334+
1335+ virtual Priority probe_device(char const* node) const = 0;
1336+ virtual std::unique_ptr<InputDevice> create_device(char const* node) const = 0;
1337+
1338+protected:
1339+ InputDeviceProvider(InputDeviceProvider const& cp) = delete;
1340+ InputDeviceProvider& operator=(InputDeviceProvider const& cp) = delete;
1341+};
1342+
1343+}
1344+}
1345+} // namespace mir
1346+
1347+#endif // MIR_INPUT_EVDEV_INPUT_DEVICE_PROVIDER_H_
1348
1349=== added file 'src/platforms/evdev/libinput_device_provider.cpp'
1350--- src/platforms/evdev/libinput_device_provider.cpp 1970-01-01 00:00:00 +0000
1351+++ src/platforms/evdev/libinput_device_provider.cpp 2015-01-21 10:33:12 +0000
1352@@ -0,0 +1,67 @@
1353+/*
1354+ * Copyright © 2014 Canonical Ltd.
1355+ *
1356+ * This program is free software: you can redistribute it and/or modify it
1357+ * under the terms of the GNU Lesser General Public License version 3,
1358+ * as published by the Free Software Foundation.
1359+ *
1360+ * This program is distributed in the hope that it will be useful,
1361+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
1362+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1363+ * GNU Lesser General Public License for more details.
1364+ *
1365+ * You should have received a copy of the GNU Lesser General Public License
1366+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
1367+ *
1368+ * Authored by: Andreas Pokorny <andreas.pokorny@canonical.com>
1369+ */
1370+
1371+#include "libinput_device_provider.h"
1372+#include "evdev_device_detection.h"
1373+
1374+#include "mir/input/input_device.h"
1375+#include "mir/input/device_capability.h"
1376+
1377+#include <sys/types.h>
1378+#include <sys/stat.h>
1379+#include <fcntl.h>
1380+#include <unistd.h>
1381+#include <stdexcept>
1382+
1383+namespace mi = mir::input;
1384+namespace mie = mi::evdev;
1385+
1386+mie::Priority mie::LibInputDeviceProvider::probe_device(char const* device) const
1387+{
1388+ auto device_caps = detect_device_capabilities(device);
1389+
1390+ if (contains(device_caps, DeviceCapability::joystick))
1391+ return Priority::unsupported;
1392+
1393+ if (contains(device_caps, DeviceCapability::gamepad))
1394+ return Priority::unsupported;
1395+
1396+ if (contains(device_caps, DeviceCapability::touchscreen))
1397+ return Priority::unsupported;
1398+
1399+ if (contains(device_caps, DeviceCapability::touchpad))
1400+ return Priority::best;
1401+
1402+ if (device_caps == DeviceCapability::unknown)
1403+ return Priority::unsupported;
1404+
1405+ if (contains(device_caps, DeviceCapability::pointer))
1406+ return Priority::supported;
1407+
1408+ if (contains(device_caps, DeviceCapability::keyboard))
1409+ return Priority::unsupported;
1410+
1411+ return Priority::unsupported;
1412+}
1413+
1414+std::unique_ptr<mi::InputDevice> mie::LibInputDeviceProvider::create_device(char const* device) const
1415+{
1416+ (void)device;
1417+ return std::unique_ptr<mi::InputDevice>();
1418+}
1419+
1420
1421=== added file 'src/platforms/evdev/libinput_device_provider.h'
1422--- src/platforms/evdev/libinput_device_provider.h 1970-01-01 00:00:00 +0000
1423+++ src/platforms/evdev/libinput_device_provider.h 2015-01-21 10:33:12 +0000
1424@@ -0,0 +1,42 @@
1425+/*
1426+ * Copyright © 2014 Canonical Ltd.
1427+ *
1428+ * This program is free software: you can redistribute it and/or modify it
1429+ * under the terms of the GNU Lesser General Public License version 3,
1430+ * as published by the Free Software Foundation.
1431+ *
1432+ * This program is distributed in the hope that it will be useful,
1433+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
1434+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1435+ * GNU Lesser General Public License for more details.
1436+ *
1437+ * You should have received a copy of the GNU Lesser General Public License
1438+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
1439+ *
1440+ * Authored by: Andreas Pokorny <andreas.pokorny@canonical.com>
1441+ */
1442+
1443+#ifndef MIR_INPUT_EVDEV_LIBINPUT_DEVICE_PROVIDER_H_
1444+#define MIR_INPUT_EVDEV_LIBINPUT_DEVICE_PROVIDER_H_
1445+
1446+#include "input_device_provider.h"
1447+
1448+namespace mir
1449+{
1450+namespace input
1451+{
1452+namespace evdev
1453+{
1454+
1455+class LibInputDeviceProvider : public InputDeviceProvider
1456+{
1457+public:
1458+ Priority probe_device(char const* device) const override;
1459+ std::unique_ptr<InputDevice> create_device(char const* device) const override;
1460+};
1461+
1462+}
1463+}
1464+}
1465+
1466+#endif // MIR_INPUT_LIBINPUT_INPUT_DEVICE_PROVIDER_H_
1467
1468=== added file 'src/platforms/evdev/platform.cpp'
1469--- src/platforms/evdev/platform.cpp 1970-01-01 00:00:00 +0000
1470+++ src/platforms/evdev/platform.cpp 2015-01-21 10:33:12 +0000
1471@@ -0,0 +1,179 @@
1472+/*
1473+ * Copyright © 2014 Canonical Ltd.
1474+ *
1475+ * This program is free software: you can redistribute it and/or modify it
1476+ * under the terms of the GNU Lesser General Public License version 3,
1477+ * as published by the Free Software Foundation.
1478+ *
1479+ * This program is distributed in the hope that it will be useful,
1480+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
1481+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1482+ * GNU Lesser General Public License for more details.
1483+ *
1484+ * You should have received a copy of the GNU Lesser General Public License
1485+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
1486+ *
1487+ * Authored by: Andreas Pokorny <andreas.pokorny@canonical.com>
1488+ */
1489+
1490+#include "platform.h"
1491+#include "evdev_input_device_factory.h"
1492+#include "android_device_provider.h"
1493+#include "libinput_device_provider.h"
1494+#include "mir/udev/wrapper.h"
1495+
1496+#include "mir/input/input_event_handler_register.h"
1497+#include "mir/input/input_device_registry.h"
1498+#include "mir/input/input_device.h"
1499+#include "mir/input/input_report.h"
1500+
1501+namespace mi = mir::input;
1502+namespace mo = mir::options;
1503+namespace mu = mir::udev;
1504+namespace mie = mi::evdev;
1505+
1506+namespace
1507+{
1508+char const* const host_socket_opt = "host-socket";
1509+}
1510+
1511+mie::Platform::Platform(std::shared_ptr<InputReport> const& report,
1512+ std::unique_ptr<udev::Context> udev_context,
1513+ std::unique_ptr<udev::Monitor> monitor,
1514+ std::shared_ptr<mie::InputDeviceFactory> const& factory) :
1515+ report(report),
1516+ udev_context(std::move(udev_context)),
1517+ monitor(std::move(monitor)),
1518+ input_device_factory(factory)
1519+{
1520+ this->monitor->filter_by_subsystem("input");
1521+ this->monitor->enable();
1522+}
1523+
1524+void mie::Platform::start(mi::InputEventHandlerRegister& execution, std::shared_ptr<InputDeviceRegistry> const& input_device_registry)
1525+{
1526+ this->input_device_registry = input_device_registry;
1527+
1528+ execution.register_fd_handler(
1529+ {monitor->fd()},
1530+ this,
1531+ [this](int /*fd*/)
1532+ {
1533+ monitor->process_events(
1534+ [this](mu::Monitor::EventType event, mu::Device const& dev)
1535+ {
1536+ if (!dev.devnode())
1537+ return;
1538+ if (event == mu::Monitor::ADDED)
1539+ device_added(dev);
1540+ if (event == mu::Monitor::REMOVED)
1541+ device_removed(dev);
1542+ if (event == mu::Monitor::CHANGED)
1543+ device_changed(dev);
1544+ }
1545+ );
1546+ });
1547+
1548+ execution.register_handler([this](){ scan_for_devices();});
1549+}
1550+
1551+void mie::Platform::scan_for_devices()
1552+{
1553+ mu::Enumerator input_enumerator{udev_context};
1554+ input_enumerator.match_subsystem("input");
1555+ input_enumerator.scan_devices();
1556+
1557+ for (auto& device : input_enumerator)
1558+ {
1559+ if (device.devnode() != nullptr)
1560+ device_added(device);
1561+ }
1562+}
1563+
1564+void mie::Platform::device_added(mu::Device const& dev)
1565+{
1566+ if (end(devices) != find_device(dev.devnode()))
1567+ return;
1568+
1569+ std::shared_ptr<mi::InputDevice> input_dev;
1570+
1571+ try
1572+ {
1573+ input_dev = input_device_factory->create_device(dev.devnode());
1574+ report->open_input_device(dev.devnode());
1575+ input_device_registry->add_device(input_dev);
1576+ devices.emplace_back(dev.devnode(), input_dev);
1577+ } catch(...)
1578+ {
1579+ report->failure_opening_input_device(dev.devnode());
1580+ }
1581+
1582+}
1583+
1584+void mie::Platform::device_removed(mu::Device const& dev)
1585+{
1586+ auto known_device_pos = find_device(dev.devnode());
1587+
1588+ if (known_device_pos == end(devices))
1589+ return;
1590+
1591+ input_device_registry->remove_device(known_device_pos->second);
1592+ devices.erase(known_device_pos);
1593+}
1594+
1595+
1596+auto mie::Platform::find_device(char const* devnode) -> decltype(devices)::iterator
1597+{
1598+ return std::find_if(
1599+ begin(devices),
1600+ end(devices),
1601+ [devnode](decltype(devices)::value_type const& item)
1602+ {
1603+ return devnode == item.first;
1604+ }
1605+ );
1606+}
1607+
1608+void mie::Platform::device_changed(mu::Device const& /*dev*/)
1609+{
1610+}
1611+
1612+void mie::Platform::stop(mi::InputEventHandlerRegister& execution)
1613+{
1614+ execution.unregister_fd_handler(this);
1615+}
1616+
1617+extern "C" std::unique_ptr<mi::Platform> create_input_platform(
1618+ std::shared_ptr<mo::Option> const& /*options*/,
1619+ std::shared_ptr<mir::EmergencyCleanupRegistry> const& /*emergency_cleanup_registry*/,
1620+ std::shared_ptr<mi::InputReport> const& report)
1621+{
1622+ std::unique_ptr<mu::Context> ctx{new mu::Context};
1623+ std::unique_ptr<mu::Monitor> monitor{new mu::Monitor(*ctx.get())};
1624+ std::initializer_list<std::shared_ptr<mie::InputDeviceProvider>> providers =
1625+ {std::make_shared<mie::AndroidDeviceProvider>(), std::make_shared<mie::LibInputDeviceProvider>()};
1626+ return std::unique_ptr<mie::Platform>(
1627+ new mie::Platform(
1628+ report,
1629+ std::move(ctx),
1630+ std::move(monitor),
1631+ std::make_shared<mie::EvdevInputDeviceFactory>(providers))
1632+ );
1633+}
1634+
1635+
1636+extern "C" void add_input_platform_options(
1637+ boost::program_options::options_description& /*config*/)
1638+{
1639+ // no options to add yet
1640+}
1641+
1642+extern "C" mi::PlatformPriority probe_input_platform(
1643+ mo::Option const& options)
1644+{
1645+ if (options.is_set(host_socket_opt))
1646+ {
1647+ return mi::PlatformPriority::unsupported;
1648+ }
1649+ return mi::PlatformPriority::supported;
1650+}
1651
1652=== added file 'src/platforms/evdev/platform.h'
1653--- src/platforms/evdev/platform.h 1970-01-01 00:00:00 +0000
1654+++ src/platforms/evdev/platform.h 2015-01-21 10:33:12 +0000
1655@@ -0,0 +1,69 @@
1656+/*
1657+ * Copyright © 2014 Canonical Ltd.
1658+ *
1659+ * This program is free software: you can redistribute it and/or modify it
1660+ * under the terms of the GNU Lesser General Public License version 3,
1661+ * as published by the Free Software Foundation.
1662+ *
1663+ * This program is distributed in the hope that it will be useful,
1664+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
1665+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1666+ * GNU Lesser General Public License for more details.
1667+ *
1668+ * You should have received a copy of the GNU Lesser General Public License
1669+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
1670+ *
1671+ * Authored by: Andreas Pokorny <andreas.pokorny@canonical.com>
1672+ */
1673+
1674+#ifndef MIR_INPUT_EVDEV_PLATFORM_H_
1675+#define MIR_INPUT_EVDEV_PLATFORM_H_
1676+
1677+#include "mir/input/platform.h"
1678+#include <vector>
1679+
1680+namespace mir
1681+{
1682+namespace udev
1683+{
1684+class Device;
1685+class Monitor;
1686+class Context;
1687+}
1688+namespace input
1689+{
1690+class InputDeviceInfo;
1691+namespace evdev
1692+{
1693+class InputDeviceFactory;
1694+
1695+class Platform : public input::Platform
1696+{
1697+public:
1698+ Platform(std::shared_ptr<InputReport> const& report,
1699+ std::unique_ptr<udev::Context> udev_context,
1700+ std::unique_ptr<udev::Monitor> monitor,
1701+ std::shared_ptr<InputDeviceFactory> const& factory);
1702+ void start(InputEventHandlerRegister& loop, std::shared_ptr<InputDeviceRegistry> const& input_device_registry) override;
1703+ void stop(InputEventHandlerRegister& loop) override;
1704+
1705+private:
1706+ void scan_for_devices();
1707+ void device_added(udev::Device const& dev);
1708+ void device_removed(udev::Device const& dev);
1709+ void device_changed(udev::Device const& dev);
1710+ std::shared_ptr<InputReport> const report;
1711+ std::shared_ptr<udev::Context> udev_context;
1712+ std::unique_ptr<udev::Monitor> monitor;
1713+ std::shared_ptr<InputDeviceRegistry> input_device_registry;
1714+ std::shared_ptr<InputDeviceFactory> input_device_factory;
1715+
1716+ std::vector<std::pair<std::string,std::shared_ptr<InputDevice>>> devices;
1717+ auto find_device(char const* devnode) -> decltype(devices)::iterator;
1718+};
1719+
1720+}
1721+}
1722+}
1723+
1724+#endif
1725
1726=== added file 'src/platforms/input-platform-symbols.map'
1727--- src/platforms/input-platform-symbols.map 1970-01-01 00:00:00 +0000
1728+++ src/platforms/input-platform-symbols.map 2015-01-21 10:33:12 +0000
1729@@ -0,0 +1,7 @@
1730+MIR_INPUT_PLATFORM_1 {
1731+ global:
1732+ add_input_platform_options;
1733+ create_input_platform;
1734+ probe_input_platform;
1735+ local: *;
1736+};
1737
1738=== modified file 'src/server/report/logging/input_report.cpp'
1739--- src/server/report/logging/input_report.cpp 2015-01-14 06:39:13 +0000
1740+++ src/server/report/logging/input_report.cpp 2015-01-21 10:33:12 +0000
1741@@ -107,6 +107,24 @@
1742 return s;
1743 }
1744
1745+void mrl::InputReport::open_input_device(char const* device)
1746+{
1747+ std::stringstream ss;
1748+
1749+ ss << "Opened input device: " << device;
1750+
1751+ logger->log(ml::Severity::informational, ss.str(), component());
1752+}
1753+
1754+void mrl::InputReport::failure_opening_input_device(char const* device)
1755+{
1756+ std::stringstream ss;
1757+
1758+ ss << "Failed to open input device: " << device;
1759+
1760+ logger->log(ml::Severity::error, ss.str(), component());
1761+}
1762+
1763 void mrl::InputReport::received_event_from_kernel(int64_t when, int type, int code, int value)
1764 {
1765 std::stringstream ss;
1766
1767=== modified file 'src/server/report/logging/input_report.h'
1768--- src/server/report/logging/input_report.h 2014-03-06 06:05:17 +0000
1769+++ src/server/report/logging/input_report.h 2015-01-21 10:33:12 +0000
1770@@ -40,6 +40,10 @@
1771 InputReport(std::shared_ptr<mir::logging::Logger> const& logger);
1772 virtual ~InputReport() noexcept(true) = default;
1773
1774+ void open_input_device(char const* device_node) override;
1775+
1776+ void failure_opening_input_device(char const* device_node) override;
1777+
1778 void received_event_from_kernel(int64_t when, int type, int code, int value);
1779
1780 void published_key_event(int dest_fd, uint32_t seq_id, int64_t event_time);
1781
1782=== modified file 'src/server/report/lttng/input_report.cpp'
1783--- src/server/report/lttng/input_report.cpp 2014-03-06 06:05:17 +0000
1784+++ src/server/report/lttng/input_report.cpp 2015-01-21 10:33:12 +0000
1785@@ -24,6 +24,16 @@
1786 #define TRACEPOINT_PROBE_DYNAMIC_LINKAGE
1787 #include "input_report_tp.h"
1788
1789+void mir::report::lttng::InputReport::open_input_device(char const* device)
1790+{
1791+ mir_tracepoint(mir_server_input, opened_input_device, device);
1792+}
1793+
1794+void mir::report::lttng::InputReport::failure_opening_input_device(char const* device)
1795+{
1796+ mir_tracepoint(mir_server_input, failure_opening_input_device, device);
1797+}
1798+
1799 void mir::report::lttng::InputReport::received_event_from_kernel(int64_t when, int type, int code, int value)
1800 {
1801 mir_tracepoint(mir_server_input, received_event_from_kernel, when, type, code, value);
1802
1803=== modified file 'src/server/report/lttng/input_report.h'
1804--- src/server/report/lttng/input_report.h 2014-03-06 06:05:17 +0000
1805+++ src/server/report/lttng/input_report.h 2015-01-21 10:33:12 +0000
1806@@ -36,6 +36,9 @@
1807 InputReport() = default;
1808 virtual ~InputReport() noexcept(true) = default;
1809
1810+ void open_input_device(char const* device_node) override;
1811+ void failure_opening_input_device(char const* device_node) override;
1812+
1813 void received_event_from_kernel(int64_t when, int type, int code, int value) override;
1814
1815 void published_key_event(int dest_fd, uint32_t seq_id, int64_t event_time) override;
1816
1817=== modified file 'src/server/report/lttng/input_report_tp.h'
1818--- src/server/report/lttng/input_report_tp.h 2015-01-14 06:39:13 +0000
1819+++ src/server/report/lttng/input_report_tp.h 2015-01-21 10:33:12 +0000
1820@@ -71,6 +71,24 @@
1821 )
1822 )
1823
1824-#endif /* MIR_LTTNG_DISPLAY_REPORT_TP_H_ */
1825+TRACEPOINT_EVENT(
1826+ mir_server_input,
1827+ opened_input_device,
1828+ TP_ARGS(char const*, device),
1829+ TP_FIELDS(
1830+ ctf_string(device, device)
1831+ )
1832+)
1833+
1834+TRACEPOINT_EVENT(
1835+ mir_server_input,
1836+ failure_opening_input_device,
1837+ TP_ARGS(char const*, device),
1838+ TP_FIELDS(
1839+ ctf_string(device, device)
1840+ )
1841+)
1842+
1843+#endif /* MIR_LTTNG_INPUT_REPORT_TP_H_ */
1844
1845 #include <lttng/tracepoint-event.h>
1846
1847=== modified file 'src/server/report/null/input_report.cpp'
1848--- src/server/report/null/input_report.cpp 2014-03-06 06:05:17 +0000
1849+++ src/server/report/null/input_report.cpp 2015-01-21 10:33:12 +0000
1850@@ -20,6 +20,14 @@
1851
1852 namespace mrn = mir::report::null;
1853
1854+void mrn::InputReport::open_input_device(char const* /* device */)
1855+{
1856+}
1857+
1858+void mrn::InputReport::failure_opening_input_device(char const* /* device */)
1859+{
1860+}
1861+
1862 void mrn::InputReport::received_event_from_kernel(int64_t /* when */, int /* type */, int /* code */, int /* value */)
1863 {
1864 }
1865
1866=== modified file 'src/server/report/null/input_report.h'
1867--- src/server/report/null/input_report.h 2014-03-06 06:05:17 +0000
1868+++ src/server/report/null/input_report.h 2015-01-21 10:33:12 +0000
1869@@ -35,6 +35,9 @@
1870 InputReport() = default;
1871 virtual ~InputReport() noexcept(true) = default;
1872
1873+ void open_input_device(char const* device_node) override;
1874+ void failure_opening_input_device(char const* device_node) override;
1875+
1876 void received_event_from_kernel(int64_t when, int type, int code, int value);
1877
1878 void published_key_event(int dest_fd, uint32_t seq_id, int64_t event_time);
1879
1880=== added file 'tests/include/mir_test_doubles/mock_input_device_registry.h'
1881--- tests/include/mir_test_doubles/mock_input_device_registry.h 1970-01-01 00:00:00 +0000
1882+++ tests/include/mir_test_doubles/mock_input_device_registry.h 2015-01-21 10:33:12 +0000
1883@@ -0,0 +1,46 @@
1884+/*
1885+ * Copyright © 2014 Canonical Ltd.
1886+ *
1887+ * This program is free software: you can redistribute it and/or modify it
1888+ * under the terms of the GNU General Public License version 3,
1889+ * as published by the Free Software Foundation.
1890+ *
1891+ * This program is distributed in the hope that it will be useful,
1892+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
1893+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1894+ * GNU General Public License for more details.
1895+ *
1896+ * You should have received a copy of the GNU General Public License
1897+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
1898+ *
1899+ * Authored by:
1900+ * Andreas Pokorny <andreas.pokorny@canonical.com>
1901+ */
1902+
1903+#ifndef MIR_INPUT_MOCK_INPUT_DEVICE_REGISTRY_H_
1904+#define MIR_INPUT_MOCK_INPUT_DEVICE_REGISTRY_H_
1905+
1906+#include "mir/input/input_device_registry.h"
1907+
1908+#include <gmock/gmock.h>
1909+
1910+namespace mir
1911+{
1912+namespace test
1913+{
1914+namespace doubles
1915+{
1916+
1917+class MockInputDeviceRegistry : public input::InputDeviceRegistry
1918+{
1919+public:
1920+ MOCK_METHOD1(add_device, void(std::shared_ptr<input::InputDevice> const& device));
1921+ MOCK_METHOD1(remove_device, void(std::shared_ptr<input::InputDevice> const& device));
1922+};
1923+
1924+}
1925+}
1926+}
1927+
1928+#endif
1929+
1930
1931=== added file 'tests/include/mir_test_doubles/mock_input_event_handler_register.h'
1932--- tests/include/mir_test_doubles/mock_input_event_handler_register.h 1970-01-01 00:00:00 +0000
1933+++ tests/include/mir_test_doubles/mock_input_event_handler_register.h 2015-01-21 10:33:12 +0000
1934@@ -0,0 +1,62 @@
1935+/*
1936+ * Copyright © 2014 Canonical Ltd.
1937+ *
1938+ * This program is free software: you can redistribute it and/or modify it
1939+ * under the terms of the GNU General Public License version 3,
1940+ * as published by the Free Software Foundation.
1941+ *
1942+ * This program is distributed in the hope that it will be useful,
1943+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
1944+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1945+ * GNU General Public License for more details.
1946+ *
1947+ * You should have received a copy of the GNU General Public License
1948+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
1949+ *
1950+ * Authored by:
1951+ * Andreas Pokorny <andreas.pokorny@canonical.com>
1952+ */
1953+
1954+#ifndef MIR_TEST_DOUBLES_MOCK_INPUT_MULTIPLEXER_H_
1955+#define MIR_TEST_DOUBLES_MOCK_INPUT_MULTIPLEXER_H_
1956+
1957+#include "mir/input/input_event_handler_register.h"
1958+
1959+#include <gmock/gmock.h>
1960+
1961+namespace mir
1962+{
1963+namespace test
1964+{
1965+namespace doubles
1966+{
1967+
1968+class MockInputEventHandlerRegister : public input::InputEventHandlerRegister
1969+{
1970+public:
1971+ void register_fd_handler(
1972+ std::initializer_list<int> fds,
1973+ void const* owner,
1974+ std::function<void(int)> const&& handler) override
1975+ {
1976+ register_fd_handler_(fds, owner, handler);
1977+ }
1978+ MOCK_METHOD3(register_fd_handler_, void(
1979+ std::initializer_list<int> fds,
1980+ void const* owner,
1981+ std::function<void(int)> const& handler));
1982+
1983+ MOCK_METHOD1(unregister_fd_handler, void(void const* owner));
1984+ void register_handler(std::function<void()> const&& handler) override
1985+ {
1986+ register_handler_(handler);
1987+ }
1988+ MOCK_METHOD1(register_handler_, void(std::function<void()> const& handler));
1989+};
1990+
1991+}
1992+}
1993+}
1994+
1995+#endif
1996+
1997
1998=== modified file 'tests/include/mir_test_framework/executable_path.h'
1999--- tests/include/mir_test_framework/executable_path.h 2015-01-14 06:39:13 +0000
2000+++ tests/include/mir_test_framework/executable_path.h 2015-01-21 10:33:12 +0000
2001@@ -26,5 +26,7 @@
2002 std::string executable_path();
2003
2004 std::string library_path();
2005+std::string server_platform(std::string const& name);
2006+std::string client_platform(std::string const& name);
2007 }
2008 #endif /* MIR_TEST_FRAMEWORK_EXECUTABLE_PATH_H_ */
2009
2010=== modified file 'tests/mir_test_framework/CMakeLists.txt'
2011--- tests/mir_test_framework/CMakeLists.txt 2015-01-14 06:39:13 +0000
2012+++ tests/mir_test_framework/CMakeLists.txt 2015-01-21 10:33:12 +0000
2013@@ -11,6 +11,11 @@
2014 ${ANDROID_HEADERS_INCLUDE_DIRS}
2015 )
2016
2017+add_definitions(
2018+ -DMIR_CLIENT_PLATFORM_PATH="${MIR_CLIENT_PLATFORM_PATH}"
2019+ -DMIR_SERVER_PLATFORM_PATH="${MIR_SERVER_PLATFORM_PATH}"
2020+ )
2021+
2022 set(
2023 TEST_FRAMEWORK_SRCS
2024
2025@@ -99,6 +104,7 @@
2026 ${CMAKE_CURRENT_SOURCE_DIR}/udev_recordings ${CMAKE_BINARY_DIR}/bin/udev_recordings
2027 COMMENT "Copying umockdev recordings to build dir..."
2028 )
2029+
2030 add_custom_command(TARGET mir-test-framework POST_BUILD
2031 COMMAND ${CMAKE_COMMAND} -E copy_directory
2032 ${CMAKE_CURRENT_SOURCE_DIR}/testing-cursor-theme ${CMAKE_BINARY_DIR}/bin/testing-cursor-theme
2033
2034=== modified file 'tests/mir_test_framework/executable_path.cpp'
2035--- tests/mir_test_framework/executable_path.cpp 2015-01-14 06:39:13 +0000
2036+++ tests/mir_test_framework/executable_path.cpp 2015-01-21 10:33:12 +0000
2037@@ -24,6 +24,7 @@
2038 #include <stdexcept>
2039 #include <boost/throw_exception.hpp>
2040 #include <boost/exception/errinfo_errno.hpp>
2041+#include <boost/filesystem.hpp>
2042
2043 std::string mir_test_framework::executable_path()
2044 {
2045@@ -43,3 +44,29 @@
2046 {
2047 return executable_path() + "/../lib";
2048 }
2049+
2050+std::string mir_test_framework::server_platform(std::string const& name)
2051+{
2052+ for (auto const& option :
2053+ {library_path() + "/server-modules/", library_path() + "/server-platform/", std::string(MIR_SERVER_PLATFORM_PATH) + '/'})
2054+ {
2055+ auto path_to_test = option + name;
2056+ if (boost::filesystem::exists(path_to_test))
2057+ return path_to_test;
2058+ }
2059+
2060+ BOOST_THROW_EXCEPTION(std::runtime_error("Failed to find server platform in standard search locations"));
2061+}
2062+
2063+std::string mir_test_framework::client_platform(std::string const& name)
2064+{
2065+ for (auto const& option :
2066+ {library_path() + "/client-modules/", library_path() + "/client-platform/", std::string(MIR_CLIENT_PLATFORM_PATH) + '/'})
2067+ {
2068+ auto path_to_test = option + name;
2069+ if (boost::filesystem::exists(path_to_test))
2070+ return path_to_test;
2071+ }
2072+
2073+ BOOST_THROW_EXCEPTION(std::runtime_error("Failed to find server platform in standard search locations"));
2074+}
2075
2076=== added file 'tests/mir_test_framework/udev_recordings/joystick-detection.ioctl'
2077--- tests/mir_test_framework/udev_recordings/joystick-detection.ioctl 1970-01-01 00:00:00 +0000
2078+++ tests/mir_test_framework/udev_recordings/joystick-detection.ioctl 2015-01-21 10:33:12 +0000
2079@@ -0,0 +1,25 @@
2080+@DEV /dev/input/event13
2081+EVIOCGBIT(1) 96 000000000000000000000000000000000000000000000000000000000000000000000000FF0F00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
2082+EVIOCGBIT(2) 2 0000
2083+EVIOCGBIT(3) 8 6300030000000000
2084+EVIOCGBIT(5) 2 0000
2085+EVIOCGBIT(17) 2 0000
2086+EVIOCGBIT(21) 16 00000000000000000000000000000000
2087+EVIOCGPROP(0) 4 00000000
2088+EVIOCGBIT(0) 8 0B00000000000000
2089+EVIOCGNAME(0) 29 4C6F676974656368204C6F6769746563682045787472656D65203344000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
2090+EVIOCGPHYS(0) 26 7573622D303030303A30303A31342E302D322F696E70757430000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
2091+EVIOCGUNIQ(0) 1 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
2092+EVIOCGID 0 03006D0415C21001
2093+EVIOCGVERSION 0 01000100
2094+EVIOCGBIT(4) 8 1000000000000000
2095+EVIOCGBIT(18) 8 0000000000000000
2096+EVIOCGKEY(0) 96 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
2097+EVIOCGLED(0) 8 0000000000000000
2098+EVIOCGSW(0) 8 0000000000000000
2099+EVIOCGABS 0 FC01000000000000FF030000030000003F00000000000000
2100+EVIOCGABS(1) 0 FC01000000000000FF030000030000003F00000000000000
2101+EVIOCGABS(5) 0 8000000000000000FF000000000000000F00000000000000
2102+EVIOCGABS(6) 0 0000000000000000FF000000000000000F00000000000000
2103+EVIOCGABS(16) 0 00000000FFFFFFFF01000000000000000000000000000000
2104+EVIOCGABS(17) 0 00000000FFFFFFFF01000000000000000000000000000000
2105
2106=== added file 'tests/mir_test_framework/udev_recordings/joystick-detection.umockdev'
2107--- tests/mir_test_framework/udev_recordings/joystick-detection.umockdev 1970-01-01 00:00:00 +0000
2108+++ tests/mir_test_framework/udev_recordings/joystick-detection.umockdev 2015-01-21 10:33:12 +0000
2109@@ -0,0 +1,351 @@
2110+P: /devices/pci0000:00/0000:00:14.0/usb3/3-2/3-2:1.0/0003:046D:C215.0016/input/input258/event13
2111+N: input/event13
2112+S: input/by-id/usb-Logitech_Logitech_Extreme_3D-event-joystick
2113+S: input/by-path/pci-0000:00:14.0-usb-0:2:1.0-event-joystick
2114+E: DEVLINKS=/dev/input/by-id/usb-Logitech_Logitech_Extreme_3D-event-joystick /dev/input/by-path/pci-0000:00:14.0-usb-0:2:1.0-event-joystick
2115+E: DEVNAME=/dev/input/event13
2116+E: ID_BUS=usb
2117+E: ID_FOR_SEAT=input-pci-0000_00_14_0-usb-0_2_1_0
2118+E: ID_INPUT=1
2119+E: ID_INPUT_JOYSTICK=1
2120+E: ID_MODEL=Logitech_Extreme_3D
2121+E: ID_MODEL_ENC=Logitech\x20Extreme\x203D
2122+E: ID_MODEL_ID=c215
2123+E: ID_PATH=pci-0000:00:14.0-usb-0:2:1.0
2124+E: ID_PATH_TAG=pci-0000_00_14_0-usb-0_2_1_0
2125+E: ID_REVISION=0204
2126+E: ID_SERIAL=Logitech_Logitech_Extreme_3D
2127+E: ID_TYPE=hid
2128+E: ID_USB_DRIVER=usbhid
2129+E: ID_USB_INTERFACES=:030000:
2130+E: ID_USB_INTERFACE_NUM=00
2131+E: ID_VENDOR=Logitech
2132+E: ID_VENDOR_ENC=Logitech
2133+E: ID_VENDOR_ID=046d
2134+E: MAJOR=13
2135+E: MINOR=77
2136+E: SUBSYSTEM=input
2137+E: TAGS=:seat:uaccess:
2138+A: dev=13:77
2139+L: device=../../input258
2140+A: power/async=disabled
2141+A: power/control=auto
2142+A: power/runtime_active_kids=0
2143+A: power/runtime_active_time=0
2144+A: power/runtime_enabled=disabled
2145+A: power/runtime_status=unsupported
2146+A: power/runtime_suspended_time=0
2147+A: power/runtime_usage=0
2148+
2149+P: /devices/pci0000:00/0000:00:14.0/usb3/3-2/3-2:1.0/0003:046D:C215.0016/input/input258
2150+E: ABS=30063
2151+E: EV=1b
2152+E: ID_BUS=usb
2153+E: ID_FOR_SEAT=input-pci-0000_00_14_0-usb-0_2_1_0
2154+E: ID_INPUT=1
2155+E: ID_INPUT_JOYSTICK=1
2156+E: ID_MODEL=Logitech_Extreme_3D
2157+E: ID_MODEL_ENC=Logitech\x20Extreme\x203D
2158+E: ID_MODEL_ID=c215
2159+E: ID_PATH=pci-0000:00:14.0-usb-0:2:1.0
2160+E: ID_PATH_TAG=pci-0000_00_14_0-usb-0_2_1_0
2161+E: ID_REVISION=0204
2162+E: ID_SERIAL=Logitech_Logitech_Extreme_3D
2163+E: ID_TYPE=hid
2164+E: ID_USB_DRIVER=usbhid
2165+E: ID_USB_INTERFACES=:030000:
2166+E: ID_USB_INTERFACE_NUM=00
2167+E: ID_VENDOR=Logitech
2168+E: ID_VENDOR_ENC=Logitech
2169+E: ID_VENDOR_ID=046d
2170+E: KEY=fff00000000 0 0 0 0
2171+E: MODALIAS=input:b0003v046DpC215e0110-e0,1,3,4,k120,121,122,123,124,125,126,127,128,129,12A,12B,ra0,1,5,6,10,11,m4,lsfw
2172+E: MSC=10
2173+E: NAME="Logitech Logitech Extreme 3D"
2174+E: PHYS="usb-0000:00:14.0-2/input0"
2175+E: PRODUCT=3/46d/c215/110
2176+E: PROP=0
2177+E: SUBSYSTEM=input
2178+E: TAGS=:seat:
2179+E: UNIQ=""
2180+A: capabilities/abs=30063
2181+A: capabilities/ev=1b
2182+A: capabilities/ff=0
2183+A: capabilities/key=fff00000000 0 0 0 0
2184+A: capabilities/led=0
2185+A: capabilities/msc=10
2186+A: capabilities/rel=0
2187+A: capabilities/snd=0
2188+A: capabilities/sw=0
2189+L: device=../../../0003:046D:C215.0016
2190+A: id/bustype=0003
2191+A: id/product=c215
2192+A: id/vendor=046d
2193+A: id/version=0110
2194+A: modalias=input:b0003v046DpC215e0110-e0,1,3,4,k120,121,122,123,124,125,126,127,128,129,12A,12B,ra0,1,5,6,10,11,m4,lsfw
2195+A: name=Logitech Logitech Extreme 3D
2196+A: phys=usb-0000:00:14.0-2/input0
2197+A: power/async=disabled
2198+A: power/control=auto
2199+A: power/runtime_active_kids=0
2200+A: power/runtime_active_time=0
2201+A: power/runtime_enabled=disabled
2202+A: power/runtime_status=unsupported
2203+A: power/runtime_suspended_time=0
2204+A: power/runtime_usage=0
2205+A: properties=0
2206+A: uniq=
2207+
2208+P: /devices/pci0000:00/0000:00:14.0/usb3/3-2/3-2:1.0/0003:046D:C215.0016
2209+E: DRIVER=logitech
2210+E: HID_ID=0003:0000046D:0000C215
2211+E: HID_NAME=Logitech Logitech Extreme 3D
2212+E: HID_PHYS=usb-0000:00:14.0-2/input0
2213+E: MODALIAS=hid:b0003g0000v0000046Dp0000C215
2214+E: SUBSYSTEM=hid
2215+E: UPOWER_VENDOR=Logitech, Inc.
2216+L: driver=../../../../../../../bus/hid/drivers/logitech
2217+A: modalias=hid:b0003g0000v0000046Dp0000C215
2218+A: power/async=disabled
2219+A: power/control=auto
2220+A: power/runtime_active_kids=0
2221+A: power/runtime_active_time=0
2222+A: power/runtime_enabled=disabled
2223+A: power/runtime_status=unsupported
2224+A: power/runtime_suspended_time=0
2225+A: power/runtime_usage=0
2226+H: report_descriptor=05010904A101A1029502750A150026FF03350046FF03093009318102750495012507463B01661400093981426500750826FF0046FF0009358102A495087501250145010509190129088102B409368102950475012501450105091909290C810295048101C0A1029504750826FF0046FF000600FF0901B102C0C0
2227+
2228+P: /devices/pci0000:00/0000:00:14.0/usb3/3-2/3-2:1.0
2229+E: DEVTYPE=usb_interface
2230+E: DRIVER=usbhid
2231+E: ID_MODEL_FROM_DATABASE=Extreme 3D Pro
2232+E: ID_VENDOR_FROM_DATABASE=Logitech, Inc.
2233+E: INTERFACE=3/0/0
2234+E: MODALIAS=usb:v046DpC215d0204dc00dsc00dp00ic03isc00ip00in00
2235+E: PRODUCT=46d/c215/204
2236+E: SUBSYSTEM=usb
2237+E: TYPE=0/0/0
2238+A: bAlternateSetting= 0
2239+A: bInterfaceClass=03
2240+A: bInterfaceNumber=00
2241+A: bInterfaceProtocol=00
2242+A: bInterfaceSubClass=00
2243+A: bNumEndpoints=01
2244+L: driver=../../../../../../bus/usb/drivers/usbhid
2245+A: modalias=usb:v046DpC215d0204dc00dsc00dp00ic03isc00ip00in00
2246+A: power/async=enabled
2247+A: power/runtime_active_kids=0
2248+A: power/runtime_enabled=enabled
2249+A: power/runtime_status=suspended
2250+A: power/runtime_usage=0
2251+A: supports_autosuspend=1
2252+
2253+P: /devices/pci0000:00/0000:00:14.0/usb3/3-2
2254+N: bus/usb/003/043=12011001000000086D0415C204020102000109022200010100800F090400000103000000092110012101227A000705810307000A
2255+E: BUSNUM=003
2256+E: DEVNAME=/dev/bus/usb/003/043
2257+E: DEVNUM=043
2258+E: DEVTYPE=usb_device
2259+E: DRIVER=usb
2260+E: ID_BUS=usb
2261+E: ID_MODEL=Logitech_Extreme_3D
2262+E: ID_MODEL_ENC=Logitech\x20Extreme\x203D
2263+E: ID_MODEL_FROM_DATABASE=Extreme 3D Pro
2264+E: ID_MODEL_ID=c215
2265+E: ID_REVISION=0204
2266+E: ID_SERIAL=Logitech_Logitech_Extreme_3D
2267+E: ID_USB_INTERFACES=:030000:
2268+E: ID_VENDOR=Logitech
2269+E: ID_VENDOR_ENC=Logitech
2270+E: ID_VENDOR_FROM_DATABASE=Logitech, Inc.
2271+E: ID_VENDOR_ID=046d
2272+E: MAJOR=189
2273+E: MINOR=298
2274+E: PRODUCT=46d/c215/204
2275+E: SUBSYSTEM=usb
2276+E: TYPE=0/0/0
2277+E: UPOWER_VENDOR=Logitech, Inc.
2278+A: authorized=1
2279+A: avoid_reset_quirk=0
2280+A: bConfigurationValue=1
2281+A: bDeviceClass=00
2282+A: bDeviceProtocol=00
2283+A: bDeviceSubClass=00
2284+A: bMaxPacketSize0=8
2285+A: bMaxPower=30mA
2286+A: bNumConfigurations=1
2287+A: bNumInterfaces= 1
2288+A: bcdDevice=0204
2289+A: bmAttributes=80
2290+A: busnum=3
2291+A: configuration=
2292+H: descriptors=12011001000000086D0415C204020102000109022200010100800F090400000103000000092110012101227A000705810307000A
2293+A: dev=189:298
2294+A: devnum=43
2295+A: devpath=2
2296+L: driver=../../../../../bus/usb/drivers/usb
2297+A: idProduct=c215
2298+A: idVendor=046d
2299+A: ltm_capable=no
2300+A: manufacturer=Logitech
2301+A: maxchild=0
2302+L: port=../3-0:1.0/usb3-port2
2303+A: power/active_duration=1287064
2304+A: power/async=enabled
2305+A: power/autosuspend=2
2306+A: power/autosuspend_delay_ms=2000
2307+A: power/connected_duration=1287064
2308+A: power/control=on
2309+A: power/level=on
2310+A: power/persist=1
2311+A: power/runtime_active_kids=0
2312+A: power/runtime_active_time=1286764
2313+A: power/runtime_enabled=forbidden
2314+A: power/runtime_status=active
2315+A: power/runtime_suspended_time=0
2316+A: power/runtime_usage=1
2317+A: product=Logitech Extreme 3D
2318+A: quirks=0x0
2319+A: removable=unknown
2320+A: speed=1.5
2321+A: urbnum=24
2322+A: version= 1.10
2323+
2324+P: /devices/pci0000:00/0000:00:14.0/usb3
2325+N: bus/usb/003/001=12010002090001406B1D020016030302010109021900010100E0000904000001090000000705810304000C
2326+E: BUSNUM=003
2327+E: DEVNAME=/dev/bus/usb/003/001
2328+E: DEVNUM=001
2329+E: DEVTYPE=usb_device
2330+E: DRIVER=usb
2331+E: ID_BUS=usb
2332+E: ID_FOR_SEAT=usb-pci-0000_00_14_0
2333+E: ID_MODEL=xHCI_Host_Controller
2334+E: ID_MODEL_ENC=xHCI\x20Host\x20Controller
2335+E: ID_MODEL_FROM_DATABASE=2.0 root hub
2336+E: ID_MODEL_ID=0002
2337+E: ID_PATH=pci-0000:00:14.0
2338+E: ID_PATH_TAG=pci-0000_00_14_0
2339+E: ID_REVISION=0316
2340+E: ID_SERIAL=Linux_3.16.0-24-generic_xhci_hcd_xHCI_Host_Controller_0000:00:14.0
2341+E: ID_SERIAL_SHORT=0000:00:14.0
2342+E: ID_USB_INTERFACES=:090000:
2343+E: ID_VENDOR=Linux_3.16.0-24-generic_xhci_hcd
2344+E: ID_VENDOR_ENC=Linux\x203.16.0-24-generic\x20xhci_hcd
2345+E: ID_VENDOR_FROM_DATABASE=Linux Foundation
2346+E: ID_VENDOR_ID=1d6b
2347+E: MAJOR=189
2348+E: MINOR=256
2349+E: PRODUCT=1d6b/2/316
2350+E: SUBSYSTEM=usb
2351+E: TAGS=:seat:
2352+E: TYPE=9/0/1
2353+A: authorized=1
2354+A: authorized_default=1
2355+A: avoid_reset_quirk=0
2356+A: bConfigurationValue=1
2357+A: bDeviceClass=09
2358+A: bDeviceProtocol=01
2359+A: bDeviceSubClass=00
2360+A: bMaxPacketSize0=64
2361+A: bMaxPower=0mA
2362+A: bNumConfigurations=1
2363+A: bNumInterfaces= 1
2364+A: bcdDevice=0316
2365+A: bmAttributes=e0
2366+A: busnum=3
2367+A: configuration=
2368+H: descriptors=12010002090001406B1D020016030302010109021900010100E0000904000001090000000705810304000C
2369+A: dev=189:256
2370+A: devnum=1
2371+A: devpath=0
2372+L: driver=../../../../bus/usb/drivers/usb
2373+A: idProduct=0002
2374+A: idVendor=1d6b
2375+A: ltm_capable=no
2376+A: manufacturer=Linux 3.16.0-24-generic xhci_hcd
2377+A: maxchild=14
2378+A: power/active_duration=471394472
2379+A: power/async=enabled
2380+A: power/autosuspend=0
2381+A: power/autosuspend_delay_ms=0
2382+A: power/connected_duration=493735372
2383+A: power/control=auto
2384+A: power/level=auto
2385+A: power/runtime_active_kids=3
2386+A: power/runtime_active_time=466119148
2387+A: power/runtime_enabled=enabled
2388+A: power/runtime_status=active
2389+A: power/runtime_suspended_time=22335316
2390+A: power/runtime_usage=0
2391+A: power/wakeup=disabled
2392+A: power/wakeup_abort_count=
2393+A: power/wakeup_active=
2394+A: power/wakeup_active_count=
2395+A: power/wakeup_count=
2396+A: power/wakeup_expire_count=
2397+A: power/wakeup_last_time_ms=
2398+A: power/wakeup_max_time_ms=
2399+A: power/wakeup_total_time_ms=
2400+A: product=xHCI Host Controller
2401+A: quirks=0x0
2402+A: removable=unknown
2403+A: serial=0000:00:14.0
2404+A: speed=480
2405+A: urbnum=1514
2406+A: version= 2.00
2407+
2408+P: /devices/pci0000:00/0000:00:14.0
2409+E: DRIVER=xhci_hcd
2410+E: ID_MODEL_FROM_DATABASE=8 Series/C220 Series Chipset Family USB xHCI
2411+E: ID_PCI_CLASS_FROM_DATABASE=Serial bus controller
2412+E: ID_PCI_INTERFACE_FROM_DATABASE=XHCI
2413+E: ID_PCI_SUBCLASS_FROM_DATABASE=USB controller
2414+E: ID_VENDOR_FROM_DATABASE=Intel Corporation
2415+E: MODALIAS=pci:v00008086d00008C31sv00001558sd00007410bc0Csc03i30
2416+E: PCI_CLASS=C0330
2417+E: PCI_ID=8086:8C31
2418+E: PCI_SLOT_NAME=0000:00:14.0
2419+E: PCI_SUBSYS_ID=1558:7410
2420+E: SUBSYSTEM=pci
2421+A: broken_parity_status=0
2422+A: class=0x0c0330
2423+H: config=8680318C060490020530030C000000000400E2F7000000000000000000000000000000000000000000000000581510740000000070000000000000000B010000FD01368089C60F8000000000000000009F6E8807000000000000000000000000302000000000000000000000000000000180C2C108000000000000000000000005008700F802E0FE000000000000000000000000000000000000000000000000400100000000000000000000000000000F000100000000000000000000000000030420C0030C3000030C300000000000FF3F0000FF3F00003F0000003F000000A0000000D03C000000000000D8D8D8080000000000000000B10F060800000000
2424+A: consistent_dma_mask_bits=64
2425+A: d3cold_allowed=1
2426+A: device=0x8c31
2427+A: dma_mask_bits=64
2428+L: driver=../../../bus/pci/drivers/xhci_hcd
2429+A: driver_override=(null)
2430+A: enabled=1
2431+A: irq=42
2432+A: local_cpulist=0-7
2433+A: local_cpus=00000000,00000000,00000000,00000000,00000000,00000000,00000000,000000ff
2434+A: modalias=pci:v00008086d00008C31sv00001558sd00007410bc0Csc03i30
2435+A: msi_bus=
2436+A: msi_irqs/42=msi
2437+A: numa_node=-1
2438+A: pools=poolinfo - 0.1\nbuffer-2048 0 0 2048 0\nbuffer-512 0 0 512 0\nbuffer-128 0 0 128 0\nbuffer-32 0 0 32 0\nxHCI 1KB stream ctx arrays 0 0 1024 0\nxHCI 256 byte stream ctx arrays 0 0 256 0\nxHCI input/output contexts 7 11 2112 11\nxHCI ring segments 82 152 1024 38\nbuffer-2048 0 38 2048 19\nbuffer-512 0 16 512 2\nbuffer-128 3 32 128 1\nbuffer-32 0 0 32 0
2439+A: power/async=enabled
2440+A: power/control=on
2441+A: power/runtime_active_kids=1
2442+A: power/runtime_active_time=493735800
2443+A: power/runtime_enabled=forbidden
2444+A: power/runtime_status=active
2445+A: power/runtime_suspended_time=0
2446+A: power/runtime_usage=1
2447+A: power/wakeup=enabled
2448+A: power/wakeup_abort_count=0
2449+A: power/wakeup_active=0
2450+A: power/wakeup_active_count=0
2451+A: power/wakeup_count=0
2452+A: power/wakeup_expire_count=0
2453+A: power/wakeup_last_time_ms=1534
2454+A: power/wakeup_max_time_ms=0
2455+A: power/wakeup_total_time_ms=0
2456+A: resource=0x00000000f7e20000 0x00000000f7e2ffff 0x0000000000140204\n0x0000000000000000 0x0000000000000000 0x0000000000000000\n0x0000000000000000 0x0000000000000000 0x0000000000000000\n0x0000000000000000 0x0000000000000000 0x0000000000000000\n0x0000000000000000 0x0000000000000000 0x0000000000000000\n0x0000000000000000 0x0000000000000000 0x0000000000000000\n0x0000000000000000 0x0000000000000000 0x0000000000000000\n0x0000000000000000 0x0000000000000000 0x0000000000000000\n0x0000000000000000 0x0000000000000000 0x0000000000000000\n0x0000000000000000 0x0000000000000000 0x0000000000000000\n0x0000000000000000 0x0000000000000000 0x0000000000000000\n0x0000000000000000 0x0000000000000000 0x0000000000000000\n0x0000000000000000 0x0000000000000000 0x0000000000000000
2457+A: subsystem_device=0x7410
2458+A: subsystem_vendor=0x1558
2459+A: vendor=0x8086
2460+
2461
2462=== added file 'tests/mir_test_framework/udev_recordings/mt-screen-detection.ioctl'
2463--- tests/mir_test_framework/udev_recordings/mt-screen-detection.ioctl 1970-01-01 00:00:00 +0000
2464+++ tests/mir_test_framework/udev_recordings/mt-screen-detection.ioctl 2015-01-21 10:33:12 +0000
2465@@ -0,0 +1,28 @@
2466+@DEV /dev/input/event4
2467+EVIOCGBIT(1) 96 000000000000000000000000000010000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
2468+EVIOCGBIT(2) 2 0000
2469+EVIOCGBIT(3) 8 0300000100006306
2470+EVIOCGBIT(5) 2 0000
2471+EVIOCGBIT(17) 2 0000
2472+EVIOCGBIT(21) 16 00000000000000000000000000000000
2473+EVIOCGPROP(0) 8 02000000
2474+EVIOCGBIT(0) 8 0B00000000000000
2475+EVIOCGNAME(0) 8 6D746B2D747064000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
2476+EVIOCGID 0 0000000000000000
2477+EVIOCGPHYS(0) 0 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
2478+EVIOCGUNIQ(0) 0 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
2479+EVIOCGVERSION 0 01000100
2480+EVIOCGBIT(4) 8 0000000000000000
2481+EVIOCGBIT(18) 8 0000000000000000
2482+EVIOCGKEY(0) 96 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
2483+EVIOCGLED(0) 4 00000000
2484+EVIOCGSW(0) 4 00000000
2485+EVIOCGABS 0 00000000000000001C02000000000000000000001C020000
2486+EVIOCGABS(1) 0 0000000000000000C00300000000000000000000C0030000
2487+EVIOCGABS(24) 0 0000000000000000FF000000000000000000000000000000
2488+EVIOCGABS(48) 0 000000000000000064000000000000000000000000000000
2489+EVIOCGABS(49) 0 000000000000000064000000000000000000000000000000
2490+EVIOCGABS(53) 0 00000000000000001C020000000000000000000000000000
2491+EVIOCGABS(54) 0 0000000000000000C0030000000000000000000000000000
2492+EVIOCGABS(57) 0 000000000000000000000000000000000000000000000000
2493+EVIOCGABS(58) 0 0000000000000000FF000000000000000000000000000000
2494
2495=== added file 'tests/mir_test_framework/udev_recordings/mt-screen-detection.umockdev'
2496--- tests/mir_test_framework/udev_recordings/mt-screen-detection.umockdev 1970-01-01 00:00:00 +0000
2497+++ tests/mir_test_framework/udev_recordings/mt-screen-detection.umockdev 2015-01-21 10:33:12 +0000
2498@@ -0,0 +1,44 @@
2499+P: /devices/virtual/input/input4/event4
2500+N: input/event4
2501+E: DEVNAME=/dev/input/event4
2502+E: ID_INPUT=1
2503+E: ID_INPUT_KEY=1
2504+E: ID_INPUT_TOUCHSCREEN=1
2505+E: MAJOR=13
2506+E: MINOR=68
2507+E: SUBSYSTEM=input
2508+A: dev=13:68
2509+L: device=../../input4
2510+
2511+P: /devices/virtual/input/input4
2512+E: ABS=6630000 1000003
2513+E: EV=b
2514+E: ID_INPUT=1
2515+E: ID_INPUT_KEY=1
2516+E: ID_INPUT_TOUCHSCREEN=1
2517+E: KEY=400 0 0 0 0 0 0 100000 0 0 0
2518+E: MODALIAS=input:b0000v0000p0000e0000-e0,1,3,k74,14A,ra0,1,18,30,31,35,36,39,3A,mlsfw
2519+E: NAME="mtk-tpd"
2520+E: PRODUCT=0/0/0/0
2521+E: PROP=2
2522+E: SUBSYSTEM=input
2523+E: TAGS=:seat:
2524+A: capabilities/abs=6630000 1000003
2525+A: capabilities/ev=b
2526+A: capabilities/ff=0
2527+A: capabilities/key=400 0 0 0 0 0 0 100000 0 0 0
2528+A: capabilities/led=0
2529+A: capabilities/msc=0
2530+A: capabilities/rel=0
2531+A: capabilities/snd=0
2532+A: capabilities/sw=0
2533+A: id/bustype=0000
2534+A: id/product=0000
2535+A: id/vendor=0000
2536+A: id/version=0000
2537+A: modalias=input:b0000v0000p0000e0000-e0,1,3,k74,14A,ra0,1,18,30,31,35,36,39,3A,mlsfw
2538+A: name=mtk-tpd
2539+A: phys=
2540+A: properties=2
2541+A: uniq=
2542+
2543
2544=== modified file 'tests/mir_test_framework/udev_recordings/synaptics-touchpad.ioctl'
2545--- tests/mir_test_framework/udev_recordings/synaptics-touchpad.ioctl 2014-02-17 03:46:06 +0000
2546+++ tests/mir_test_framework/udev_recordings/synaptics-touchpad.ioctl 2015-01-21 10:33:12 +0000
2547@@ -19,11 +19,4 @@
2548 EVIOCGNAME(0) 27 53796E50532F322053796E61707469637320546F756368506164000000000000200B00A8A37F0000C8A59DC6A37F0000C00800A8A37F0000C00407B8A37F0000F0DF950100000000F53326C8A37F00
2549 EVIOCGPHYS(0) 22 697361303036302F736572696F322F696E707574300068506164000000000000200B00A8A37F0000C8A59DC6A37F0000C00800A8A37F0000C00407B8A37F0000F0DF950100000000F53326C8A37F00
2550 EVIOCGNAME(0) 18 48444120496E74656C20504348204D6963007574300068506164000000000000200B00CC1C7F0000C81563E91C7F0000C00800CC1C7F0000C074CCDA1C7F0000307F170200000000F5A3EBEA1C7F00
2551-EVIOCGID 0 0000000000000000
2552 EVIOCGPHYS(0) 5 414C5341006E74656C20504348204D6963007574300068506164000000000000200B00CC1C7F0000C81563E91C7F0000C00800CC1C7F0000C074CCDA1C7F0000307F170200000000F5A3EBEA1C7F00
2553-EVIOCGBIT(1) 96 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
2554-EVIOCGBIT(3) 8 0000000000000000
2555-EVIOCGBIT(5) 2 1000
2556-EVIOCGPROP(0) 4 00000000
2557-EVIOCGNAME(0) 27 53796E50532F322053796E61707469637320546F756368506164000000000000200B00E8217F0000C885F704227F0000C00800E8217F0000C0E460F6217F0000303FF40100000000F5138006227F00
2558-EVIOCGPHYS(0) 22 697361303036302F736572696F322F696E707574300068506164000000000000200B00E8217F0000C885F704227F0000C00800E8217F0000C0E460F6217F0000303FF40100000000F5138006227F00
2559
2560=== modified file 'tests/unit-tests/CMakeLists.txt'
2561--- tests/unit-tests/CMakeLists.txt 2015-01-14 06:39:13 +0000
2562+++ tests/unit-tests/CMakeLists.txt 2015-01-21 10:33:12 +0000
2563@@ -12,6 +12,7 @@
2564 add_definitions(
2565 -DTEST_RECORDINGS_DIR="${CMAKE_CURRENT_SOURCE_DIR}/input_recordings/"
2566 -DMIR_CLIENT_DRIVER_BINARY="${MIR_CLIENT_DRIVER_BINARY}"
2567+ -DMIR_SERVER_INPUT_PLATFORM_VERSION="${MIR_SERVER_INPUT_PLATFORM_VERSION}"
2568 )
2569
2570 include_directories(${DRM_INCLUDE_DIRS} ${GBM_INCLUDE_DIRS} ${UMOCKDEV_INCLUDE_DIRS} ${CMAKE_SOURCE_DIR})
2571@@ -36,6 +37,7 @@
2572 test_thread_safe_list.cpp
2573 test_fatal.cpp
2574 test_fd.cpp
2575+ test_find_best.cpp
2576 test_shared_library_prober.cpp
2577 )
2578
2579
2580=== modified file 'tests/unit-tests/input/CMakeLists.txt'
2581--- tests/unit-tests/input/CMakeLists.txt 2015-01-14 06:39:13 +0000
2582+++ tests/unit-tests/input/CMakeLists.txt 2015-01-21 10:33:12 +0000
2583@@ -1,4 +1,5 @@
2584 add_subdirectory(android)
2585+add_subdirectory(evdev)
2586
2587 list(APPEND UNIT_TEST_SOURCES
2588 ${CMAKE_CURRENT_SOURCE_DIR}/test_event_filter_chain.cpp
2589
2590=== added directory 'tests/unit-tests/input/evdev'
2591=== added file 'tests/unit-tests/input/evdev/CMakeLists.txt'
2592--- tests/unit-tests/input/evdev/CMakeLists.txt 1970-01-01 00:00:00 +0000
2593+++ tests/unit-tests/input/evdev/CMakeLists.txt 2015-01-21 10:33:12 +0000
2594@@ -0,0 +1,13 @@
2595+list(APPEND UNIT_TEST_SOURCES
2596+ ${CMAKE_CURRENT_SOURCE_DIR}/test_android_device_provider.cpp
2597+ ${CMAKE_CURRENT_SOURCE_DIR}/test_evdev_device_detection.cpp
2598+ ${CMAKE_CURRENT_SOURCE_DIR}/test_evdev_input_device_factory.cpp
2599+ ${CMAKE_CURRENT_SOURCE_DIR}/test_libinput_device_provider.cpp
2600+ ${CMAKE_CURRENT_SOURCE_DIR}/test_platform.cpp
2601+ $<TARGET_OBJECTS:mirplatforminputevdevobjects>
2602+)
2603+
2604+set(
2605+ UNIT_TEST_SOURCES
2606+ ${UNIT_TEST_SOURCES}
2607+ PARENT_SCOPE)
2608
2609=== added file 'tests/unit-tests/input/evdev/test_android_device_provider.cpp'
2610--- tests/unit-tests/input/evdev/test_android_device_provider.cpp 1970-01-01 00:00:00 +0000
2611+++ tests/unit-tests/input/evdev/test_android_device_provider.cpp 2015-01-21 10:33:12 +0000
2612@@ -0,0 +1,83 @@
2613+/*
2614+ * Copyright © 2014 Canonical Ltd.
2615+ *
2616+ * This program is free software: you can redistribute it and/or modify it
2617+ * under the terms of the GNU General Public License version 3,
2618+ * as published by the Free Software Foundation.
2619+ *
2620+ * This program is distributed in the hope that it will be useful,
2621+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
2622+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
2623+ * GNU General Public License for more details.
2624+ *
2625+ * You should have received a copy of the GNU General Public License
2626+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
2627+ *
2628+ * Authored by: Andreas Pokorny <andreas.pokorny@canonical.com>
2629+ */
2630+
2631+#include "src/platforms/evdev/android_device_provider.h"
2632+#include "mir_test_framework/udev_environment.h"
2633+
2634+#include <gmock/gmock.h>
2635+#include <gtest/gtest.h>
2636+
2637+namespace mi = mir::input;
2638+namespace mie = mi::evdev;
2639+namespace mtf = mir_test_framework;
2640+
2641+struct AndroidStack : public ::testing::TestWithParam<std::tuple<char const*, char const*, mie::Priority>>
2642+{
2643+ mtf::UdevEnvironment env;
2644+};
2645+
2646+TEST_P(AndroidStack, device_probing_yields_expected_priority)
2647+{
2648+ using namespace testing;
2649+ auto const& param = GetParam();
2650+ env.add_standard_device(std::get<0>(param));
2651+ mie::AndroidDeviceProvider provider;
2652+
2653+ EXPECT_THAT(provider.probe_device(std::get<1>(param)), Eq(std::get<2>(param)));
2654+}
2655+
2656+INSTANTIATE_TEST_CASE_P(InputDeviceProviderTest,
2657+ AndroidStack,
2658+ ::testing::Values(
2659+ std::make_tuple(
2660+ "synaptics-touchpad",
2661+ "/dev/input/event12",
2662+ mie::Priority::unsupported
2663+ ),
2664+ std::make_tuple(
2665+ "bluetooth-magic-trackpad",
2666+ "/dev/input/event13",
2667+ mie::Priority::unsupported
2668+ ),
2669+ std::make_tuple(
2670+ "mt-screen-detection",
2671+ "/dev/input/event4",
2672+ mie::Priority::best
2673+ ),
2674+ std::make_tuple(
2675+ "joystick-detection",
2676+ "/dev/input/event13",
2677+ mie::Priority::supported
2678+ ),
2679+ std::make_tuple(
2680+ "usb-mouse",
2681+ "/dev/input/event13",
2682+ mie::Priority::supported
2683+ ),
2684+ std::make_tuple(
2685+ "usb-keyboard",
2686+ "/dev/input/event14",
2687+ mie::Priority::supported
2688+ ),
2689+ std::make_tuple(
2690+ "laptop-keyboard",
2691+ "/dev/input/event4",
2692+ mie::Priority::supported
2693+ )
2694+ ));
2695+
2696
2697=== added file 'tests/unit-tests/input/evdev/test_evdev_device_detection.cpp'
2698--- tests/unit-tests/input/evdev/test_evdev_device_detection.cpp 1970-01-01 00:00:00 +0000
2699+++ tests/unit-tests/input/evdev/test_evdev_device_detection.cpp 2015-01-21 10:33:12 +0000
2700@@ -0,0 +1,86 @@
2701+/*
2702+ * Copyright © 2014 Canonical Ltd.
2703+ *
2704+ * This program is free software: you can redistribute it and/or modify it
2705+ * under the terms of the GNU General Public License version 3,
2706+ * as published by the Free Software Foundation.
2707+ *
2708+ * This program is distributed in the hope that it will be useful,
2709+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
2710+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
2711+ * GNU General Public License for more details.
2712+ *
2713+ * You should have received a copy of the GNU General Public License
2714+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
2715+ *
2716+ * Authored by: Andreas Pokorny <andreas.pokorny@canonical.com>
2717+ */
2718+
2719+#include "src/platforms/evdev/evdev_device_detection.h"
2720+#include "mir/input/device_capability.h"
2721+
2722+#include "mir_test_framework/udev_environment.h"
2723+
2724+#include <gtest/gtest.h>
2725+#include <tuple>
2726+
2727+namespace mtf = mir_test_framework;
2728+namespace mi = mir::input;
2729+namespace mie = mi::evdev;
2730+
2731+struct EvdevDeviceDetection : public ::testing::TestWithParam<std::tuple<char const*, char const*, mi::DeviceCapabilities>>
2732+{
2733+ mtf::UdevEnvironment env;
2734+};
2735+
2736+TEST_P(EvdevDeviceDetection, evaluates_expected_input_class)
2737+{
2738+ using namespace testing;
2739+ auto const& param = GetParam();
2740+ env.add_standard_device(std::get<0>(param));
2741+ EXPECT_THAT(mie::detect_device_capabilities((std::get<1>(param))),Eq(std::get<2>(param)));
2742+}
2743+
2744+INSTANTIATE_TEST_CASE_P(InputDeviceCapabilityDetection,
2745+ EvdevDeviceDetection,
2746+ ::testing::Values(
2747+ std::make_tuple(
2748+ "synaptics-touchpad",
2749+ "/dev/input/event12",
2750+ mi::DeviceCapability::touchpad
2751+ ),
2752+ std::make_tuple(
2753+ "laptop-keyboard",
2754+ "/dev/input/event4",
2755+ mi::DeviceCapability::keyboard
2756+ ),
2757+ std::make_tuple(
2758+ "usb-keyboard",
2759+ "/dev/input/event14",
2760+ mi::DeviceCapability::keyboard
2761+ ),
2762+ std::make_tuple(
2763+ "usb-mouse",
2764+ "/dev/input/event13",
2765+ mi::DeviceCapability::pointer
2766+ ),
2767+ std::make_tuple(
2768+ "bluetooth-magic-trackpad",
2769+ "/dev/input/event13",
2770+ mi::DeviceCapability::touchpad
2771+ ),
2772+ std::make_tuple(
2773+ "mt-screen-detection", // device also reports available keys..
2774+ "/dev/input/event4",
2775+ mi::DeviceCapabilities{mi::DeviceCapability::touchscreen}|
2776+ mi::DeviceCapability::keyboard
2777+ ),
2778+ std::make_tuple(
2779+ "joystick-detection",
2780+ "/dev/input/event13",
2781+ mi::DeviceCapabilities{mi::DeviceCapability::joystick}|
2782+ mi::DeviceCapability::gamepad|
2783+ mi::DeviceCapability::keyboard
2784+ )
2785+ ));
2786+
2787
2788=== added file 'tests/unit-tests/input/evdev/test_evdev_input_device_factory.cpp'
2789--- tests/unit-tests/input/evdev/test_evdev_input_device_factory.cpp 1970-01-01 00:00:00 +0000
2790+++ tests/unit-tests/input/evdev/test_evdev_input_device_factory.cpp 2015-01-21 10:33:12 +0000
2791@@ -0,0 +1,106 @@
2792+/*
2793+ * Copyright © 2014 Canonical Ltd.
2794+ *
2795+ * This program is free software: you can redistribute it and/or modify
2796+ * it under the terms of the GNU General Public License version 3 as
2797+ * published by the Free Software Foundation.
2798+ *
2799+ * This program is distributed in the hope that it will be useful,
2800+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
2801+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
2802+ * GNU General Public License for more details.
2803+ *
2804+ * You should have received a copy of the GNU General Public License
2805+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
2806+ *
2807+ * Authored by: Christopher Halse Rogers <christopher.halse.rogers@canonical.com>
2808+ * Andreas Pokorny <andreas.pokorny@canonical.com>
2809+ */
2810+
2811+#include "src/platforms/evdev/evdev_input_device_factory.h"
2812+#include "src/platforms/evdev/input_device_provider.h"
2813+
2814+#include "mir/input/input_device.h"
2815+
2816+#include <mir_test/gmock_fixes.h>
2817+#include <gtest/gtest.h>
2818+
2819+#include <stdexcept>
2820+
2821+namespace mi = mir::input;
2822+namespace mie = mi::evdev;
2823+
2824+namespace
2825+{
2826+
2827+class MockInputDeviceProvider : public mie::InputDeviceProvider
2828+{
2829+public:
2830+ MOCK_CONST_METHOD1(probe_device, mie::Priority(const char* node));
2831+ MOCK_CONST_METHOD1(create_device, std::unique_ptr<mi::InputDevice>(const char* node));
2832+};
2833+
2834+}
2835+
2836+TEST(EvdevInputDeviceFactory, probes_all_providers)
2837+{
2838+ using namespace testing;
2839+ auto a = std::make_shared<MockInputDeviceProvider>();
2840+ auto b = std::make_shared<MockInputDeviceProvider>();
2841+
2842+ EXPECT_CALL(*a, probe_device(_))
2843+ .WillOnce(Return(mie::Priority::unsupported));
2844+ EXPECT_CALL(*b, probe_device(_))
2845+ .WillOnce(Return(mie::Priority::unsupported));
2846+
2847+ mie::EvdevInputDeviceFactory factory({a, b});
2848+
2849+ EXPECT_THROW(
2850+ {
2851+ factory.create_device("stub_dev");
2852+ }, std::runtime_error);
2853+}
2854+
2855+TEST(EvdevInputDeviceFactory, creates_device_on_supported_provider)
2856+{
2857+ using namespace testing;
2858+ auto a = std::make_shared<MockInputDeviceProvider>();
2859+ auto b = std::make_shared<MockInputDeviceProvider>();
2860+
2861+ EXPECT_CALL(*a, probe_device(_))
2862+ .WillOnce(Return(mie::Priority::unsupported));
2863+ EXPECT_CALL(*b, probe_device(_))
2864+ .WillOnce(Return(mie::Priority::supported));
2865+ EXPECT_CALL(*b, create_device(_));
2866+ EXPECT_CALL(*a, create_device(_))
2867+ .Times(0);
2868+
2869+ mie::EvdevInputDeviceFactory factory({a, b});
2870+
2871+ factory.create_device("stub_dev");
2872+}
2873+
2874+TEST(EvdevInputDeviceFactory, preferes_creating_on_better_provider)
2875+{
2876+ using namespace testing;
2877+ auto a = std::make_shared<MockInputDeviceProvider>();
2878+ auto b = std::make_shared<MockInputDeviceProvider>();
2879+
2880+ EXPECT_CALL(*a, probe_device(_))
2881+ .Times(2)
2882+ .WillRepeatedly(Return(mie::Priority::best));
2883+ EXPECT_CALL(*b, probe_device(_))
2884+ .Times(2)
2885+ .WillRepeatedly(Return(mie::Priority::supported));
2886+ EXPECT_CALL(*a, create_device(_))
2887+ .Times(2);
2888+ EXPECT_CALL(*b, create_device(_))
2889+ .Times(0);
2890+
2891+ mie::EvdevInputDeviceFactory factory_one({a, b});
2892+ mie::EvdevInputDeviceFactory factory_two({b, a});
2893+
2894+ factory_one.create_device("stub_dev1");
2895+ factory_two.create_device("stub_dev2");
2896+}
2897+
2898
2899=== added file 'tests/unit-tests/input/evdev/test_libinput_device_provider.cpp'
2900--- tests/unit-tests/input/evdev/test_libinput_device_provider.cpp 1970-01-01 00:00:00 +0000
2901+++ tests/unit-tests/input/evdev/test_libinput_device_provider.cpp 2015-01-21 10:33:12 +0000
2902@@ -0,0 +1,82 @@
2903+/*
2904+ * Copyright © 2014 Canonical Ltd.
2905+ *
2906+ * This program is free software: you can redistribute it and/or modify it
2907+ * under the terms of the GNU General Public License version 3,
2908+ * as published by the Free Software Foundation.
2909+ *
2910+ * This program is distributed in the hope that it will be useful,
2911+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
2912+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
2913+ * GNU General Public License for more details.
2914+ *
2915+ * You should have received a copy of the GNU General Public License
2916+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
2917+ *
2918+ * Authored by: Andreas Pokorny <andreas.pokorny@canonical.com>
2919+ */
2920+
2921+#include "src/platforms/evdev/libinput_device_provider.h"
2922+#include "mir_test_framework/udev_environment.h"
2923+
2924+#include <gmock/gmock.h>
2925+#include <gtest/gtest.h>
2926+
2927+namespace mi = mir::input;
2928+namespace mie = mi::evdev;
2929+namespace mtf = mir_test_framework;
2930+
2931+struct LibInput : public ::testing::TestWithParam<std::tuple<char const*, char const*, mie::Priority>>
2932+{
2933+ mtf::UdevEnvironment env;
2934+};
2935+
2936+TEST_P(LibInput, device_probing_yields_expected_priority)
2937+{
2938+ using namespace testing;
2939+ auto const& param = GetParam();
2940+ env.add_standard_device(std::get<0>(param));
2941+ mie::LibInputDeviceProvider provider;
2942+
2943+ EXPECT_THAT(provider.probe_device(std::get<1>(param)), Eq(std::get<2>(param)));
2944+}
2945+
2946+INSTANTIATE_TEST_CASE_P(InputDeviceProviderTest,
2947+ LibInput,
2948+ ::testing::Values(
2949+ std::make_tuple(
2950+ "synaptics-touchpad",
2951+ "/dev/input/event12",
2952+ mie::Priority::best
2953+ ),
2954+ std::make_tuple(
2955+ "bluetooth-magic-trackpad",
2956+ "/dev/input/event13",
2957+ mie::Priority::best
2958+ ),
2959+ std::make_tuple(
2960+ "mt-screen-detection",
2961+ "/dev/input/event4",
2962+ mie::Priority::unsupported
2963+ ),
2964+ std::make_tuple(
2965+ "joystick-detection",
2966+ "/dev/input/event13",
2967+ mie::Priority::unsupported
2968+ ),
2969+ std::make_tuple(
2970+ "usb-mouse",
2971+ "/dev/input/event13",
2972+ mie::Priority::supported
2973+ ),
2974+ std::make_tuple(
2975+ "usb-keyboard",
2976+ "/dev/input/event14",
2977+ mie::Priority::unsupported
2978+ ),
2979+ std::make_tuple(
2980+ "laptop-keyboard",
2981+ "/dev/input/event4",
2982+ mie::Priority::unsupported
2983+ )
2984+ ));
2985
2986=== added file 'tests/unit-tests/input/evdev/test_platform.cpp'
2987--- tests/unit-tests/input/evdev/test_platform.cpp 1970-01-01 00:00:00 +0000
2988+++ tests/unit-tests/input/evdev/test_platform.cpp 2015-01-21 10:33:12 +0000
2989@@ -0,0 +1,207 @@
2990+/*
2991+ * Copyright © 2014 Canonical Ltd.
2992+ *
2993+ * This program is free software: you can redistribute it and/or modify
2994+ * it under the terms of the GNU General Public License version 3 as
2995+ * published by the Free Software Foundation.
2996+ *
2997+ * This program is distributed in the hope that it will be useful,
2998+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
2999+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
3000+ * GNU General Public License for more details.
3001+ *
3002+ * You should have received a copy of the GNU General Public License
3003+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
3004+ *
3005+ * Authored by: Andreas Pokorny <andreas.pokorny@canonical.com>
3006+ */
3007+
3008+#include "src/platforms/evdev/platform.h"
3009+#include "src/server/report/null_report_factory.h"
3010+#include "src/platforms/evdev/input_device_factory.h"
3011+
3012+#include "mir/input/input_device.h"
3013+#include "mir/udev/wrapper.h"
3014+#include "mir/shared_library.h"
3015+
3016+#include "mir_test_doubles/mock_main_loop.h"
3017+#include "mir_test_doubles/mock_input_device_registry.h"
3018+#include "mir_test_doubles/mock_input_event_handler_register.h"
3019+#include "mir_test_framework/udev_environment.h"
3020+#include "mir_test_framework/executable_path.h"
3021+
3022+#include <thread>
3023+#include <chrono>
3024+#include <unistd.h>
3025+#include <fcntl.h>
3026+
3027+#include <gmock/gmock.h>
3028+
3029+namespace mi = mir::input;
3030+namespace mie = mi::evdev;
3031+namespace mr = mir::report;
3032+namespace mtd = mir::test::doubles;
3033+namespace mtf = mir_test_framework;
3034+
3035+namespace
3036+{
3037+
3038+struct EvdevPlatformBase
3039+{
3040+public:
3041+ EvdevPlatformBase()
3042+ : platform_lib(mtf::server_platform("input-evdev.so")),
3043+ platform(platform_lib.load_function<mi::CreatePlatform>("create_input_platform", MIR_SERVER_INPUT_PLATFORM_VERSION)
3044+ (
3045+ std::shared_ptr<mir::options::Option>(),
3046+ std::shared_ptr<mir::EmergencyCleanupRegistry>(),
3047+ mr::null_input_report()
3048+ ))
3049+ {
3050+ }
3051+ mir::SharedLibrary platform_lib;
3052+ mtf::UdevEnvironment env; // has to be created before platform
3053+ std::unique_ptr<mi::Platform> platform;
3054+ ::testing::NiceMock<mtd::MockInputEventHandlerRegister> mock_event_handler_register;
3055+ std::shared_ptr<::testing::NiceMock<mtd::MockInputDeviceRegistry>> mock_registry =
3056+ std::make_shared<::testing::NiceMock<mtd::MockInputDeviceRegistry>>();
3057+};
3058+
3059+struct EvdevPlatform : ::testing::Test, EvdevPlatformBase
3060+{
3061+};
3062+
3063+struct EvdevPlatformDeviceEvents : ::testing::TestWithParam<char const*>, EvdevPlatformBase
3064+{
3065+ EvdevPlatformDeviceEvents()
3066+ : ::testing::TestWithParam<char const*>(), EvdevPlatformBase()
3067+ {
3068+ using namespace ::testing;
3069+ ON_CALL(mock_event_handler_register, register_fd_handler_(_,_,_))
3070+ .WillByDefault(Invoke(
3071+ [this](std::initializer_list<int> fd_list, void const*, std::function<void(int)> const& handler)
3072+ {
3073+ int fd = *fd_list.begin();
3074+ fd_callbacks.push_back([=]() { handler(fd); });
3075+ }));
3076+ ON_CALL(mock_event_handler_register, register_handler_(_))
3077+ .WillByDefault(Invoke(
3078+ [this](std::function<void()> const& action)
3079+ {
3080+ actions.push_back(action);
3081+ }));
3082+ }
3083+
3084+ void remove_device()
3085+ {
3086+ mir::udev::Enumerator devices{std::make_shared<mir::udev::Context>()};
3087+ devices.scan_devices();
3088+
3089+ for (auto& device : devices)
3090+ {
3091+ /*
3092+ * Remove just the device providing dev/input/event*
3093+ * If we remove more, it's possible that we'll remove the parent of the
3094+ * /dev/input device, and umockdev will not generate a remove event
3095+ * in that case.
3096+ */
3097+ if (device.devnode() && (std::string(device.devnode()).find("input/event") != std::string::npos))
3098+ {
3099+ env.remove_device((std::string("/sys") + device.devpath()).c_str());
3100+ }
3101+ }
3102+ }
3103+
3104+ void process_pending_actions()
3105+ {
3106+ decltype(actions) actions_to_execute;
3107+ std::swap(actions, actions_to_execute);
3108+
3109+ for(auto const& action : actions_to_execute)
3110+ action();
3111+ }
3112+
3113+ void process_pending_fd_callbacks()
3114+ {
3115+ decltype(actions) actions_to_execute;
3116+
3117+ actions_to_execute = fd_callbacks;
3118+
3119+ for(auto const& action : actions_to_execute)
3120+ action();
3121+ }
3122+
3123+ void process_pending()
3124+ {
3125+ process_pending_actions();
3126+ process_pending_fd_callbacks();
3127+ }
3128+
3129+ std::vector<std::function<void()>> fd_callbacks;
3130+ std::vector<std::function<void()>> actions;
3131+};
3132+
3133+}
3134+
3135+TEST_F(EvdevPlatform, registers_to_event_handler_register_on_start)
3136+{
3137+ using namespace ::testing;
3138+ EXPECT_CALL(mock_event_handler_register, register_fd_handler_(_,_,_));
3139+ platform->start(mock_event_handler_register, mock_registry);
3140+}
3141+
3142+TEST_F(EvdevPlatform, unregisters_to_event_handler_register_on_stop)
3143+{
3144+ using namespace ::testing;
3145+ EXPECT_CALL(mock_event_handler_register, unregister_fd_handler(_));
3146+ platform->stop(mock_event_handler_register);
3147+}
3148+
3149+TEST_P(EvdevPlatformDeviceEvents, finds_device_on_start)
3150+{
3151+ using namespace ::testing;
3152+ env.add_standard_device(GetParam());
3153+
3154+ EXPECT_CALL(*mock_registry, add_device(_)).Times(1);
3155+ platform->start(mock_event_handler_register, mock_registry);
3156+
3157+ process_pending();
3158+}
3159+
3160+TEST_P(EvdevPlatformDeviceEvents, adds_device_on_hotplug)
3161+{
3162+ using namespace ::testing;
3163+ EXPECT_CALL(*mock_registry, add_device(_)).Times(1);
3164+ platform->start(mock_event_handler_register, mock_registry);
3165+ process_pending();
3166+
3167+ env.add_standard_device(GetParam());
3168+
3169+ process_pending();
3170+}
3171+
3172+TEST_P(EvdevPlatformDeviceEvents, removes_device_on_hotplug)
3173+{
3174+ using namespace ::testing;
3175+ EXPECT_CALL(*mock_registry, add_device(_)).Times(1);
3176+ EXPECT_CALL(*mock_registry, remove_device(_)).Times(1);
3177+ platform->start(mock_event_handler_register, mock_registry);
3178+ env.add_standard_device(GetParam());
3179+
3180+ process_pending();
3181+
3182+ remove_device();
3183+
3184+ process_pending();
3185+}
3186+
3187+INSTANTIATE_TEST_CASE_P(EvdevPlatformHotplugging,
3188+ EvdevPlatformDeviceEvents,
3189+ ::testing::Values("synaptics-touchpad",
3190+ "usb-keyboard",
3191+ "usb-mouse",
3192+ "laptop-keyboard",
3193+ "bluetooth-magic-trackpad",
3194+ "joystick-detection",
3195+ "mt-screen-detection"
3196+ ));
3197
3198=== added file 'tests/unit-tests/test_find_best.cpp'
3199--- tests/unit-tests/test_find_best.cpp 1970-01-01 00:00:00 +0000
3200+++ tests/unit-tests/test_find_best.cpp 2015-01-21 10:33:12 +0000
3201@@ -0,0 +1,72 @@
3202+/*
3203+ * Copyright © 2014 Canonical Ltd.
3204+ *
3205+ * This program is free software: you can redistribute it and/or modify it
3206+ * under the terms of the GNU General Public License version 3,
3207+ * as published by the Free Software Foundation.
3208+ *
3209+ * This program is distributed in the hope that it will be useful,
3210+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
3211+ * MERCHANTABILITY or FITNESS FOR AStructure PARTICULAR PURPOSE. See the
3212+ * GNU General Public License for more details.
3213+ *
3214+ * You should have received a copy of the GNU General Public License
3215+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
3216+ *
3217+ * Authored by: Andreas Pokorny <andreas.pokorny@canonical.com>
3218+ */
3219+
3220+#include "mir/find_best.h"
3221+#include <gtest/gtest.h>
3222+
3223+#include <initializer_list>
3224+
3225+namespace
3226+{
3227+struct AStructure
3228+{
3229+ int value;
3230+};
3231+
3232+int trivial_transform(AStructure const& a)
3233+{
3234+ return a.value;
3235+}
3236+}
3237+
3238+TEST(FindBest, returns_end_iterator_on_empty)
3239+{
3240+ using namespace testing;
3241+ std::initializer_list<::AStructure> empty{};
3242+ EXPECT_THAT(mir::find_best(empty, trivial_transform, 0), Eq(end(empty)));
3243+}
3244+
3245+TEST(FindBest, returns_best_element)
3246+{
3247+ using namespace testing;
3248+ std::vector<::AStructure> values{{123}, {23}, {500}, {42}};
3249+ EXPECT_THAT(mir::find_best(values, trivial_transform, 0)->value, Eq(500));
3250+}
3251+
3252+TEST(FindBest, returns_end_when_initial_is_best)
3253+{
3254+ using namespace testing;
3255+ std::vector<::AStructure> values{{123}, {23}, {500}, {42}};
3256+ EXPECT_THAT(mir::find_best(values, trivial_transform, 501), Eq(end(values)));
3257+}
3258+
3259+TEST(FindBest, calls_transformation_only_n_times)
3260+{
3261+ using namespace testing;
3262+ std::vector<::AStructure> values{{123}, {23}, {500}, {42}};
3263+ int transform_count = 0;
3264+ mir::find_best(values, [&transform_count](::AStructure const& item) { ++transform_count; return item.value; }, 0);
3265+ EXPECT_THAT(transform_count, Eq(values.size()));
3266+}
3267+
3268+TEST(FindBest, different_predicates_can_be_used)
3269+{
3270+ using namespace testing;
3271+ std::vector<::AStructure> values{{123}, {23}, {500}, {42}};
3272+ EXPECT_THAT(mir::find_best(values, trivial_transform, 500, std::less<int>())->value, Eq(23));
3273+}

Subscribers

People subscribed via source and target branches