Mir

Merge lp:~andreas-pokorny/mir/send-input-device-state-event into lp:mir

Proposed by Andreas Pokorny
Status: Merged
Approved by: Andreas Pokorny
Approved revision: no longer in the source branch.
Merged at revision: 3579
Proposed branch: lp:~andreas-pokorny/mir/send-input-device-state-event
Merge into: lp:mir
Prerequisite: lp:~andreas-pokorny/mir/filter-keys-in-seat
Diff against target: 1462 lines (+556/-103)
34 files modified
include/platform/mir/input/event_builder.h (+3/-0)
include/platform/mir/input/input_sink.h (+22/-0)
include/test/mir/test/event_matchers.h (+32/-0)
src/client/input/android/android_input_lexicon.cpp (+6/-0)
src/client/input/android/android_input_receiver.cpp (+0/-3)
src/client/input/xkb_mapper.cpp (+8/-1)
src/include/common/mir/input/key_mapper.h (+1/-0)
src/include/common/mir/input/xkb_mapper.h (+2/-2)
src/include/server/mir/input/seat.h (+7/-0)
src/server/graphics/nested/display_buffer.cpp (+3/-4)
src/server/graphics/nested/input_platform.cpp (+58/-19)
src/server/input/android/input_sender.cpp (+28/-19)
src/server/input/basic_seat.cpp (+23/-2)
src/server/input/basic_seat.h (+10/-1)
src/server/input/default_configuration.cpp (+2/-1)
src/server/input/default_event_builder.cpp (+11/-2)
src/server/input/default_event_builder.h (+6/-1)
src/server/input/default_input_device_hub.cpp (+26/-3)
src/server/input/default_input_device_hub.h (+5/-1)
src/server/input/seat_input_device_tracker.cpp (+54/-15)
src/server/input/seat_input_device_tracker.h (+12/-1)
src/server/server.cpp (+46/-1)
src/server/shell/abstract_shell.cpp (+1/-0)
tests/acceptance-tests/test_nested_input.cpp (+79/-11)
tests/include/mir/test/doubles/mock_input_seat.h (+6/-1)
tests/include/mir/test/doubles/mock_input_sink.h (+2/-0)
tests/include/mir/test/doubles/mock_key_mapper.h (+1/-0)
tests/integration-tests/input/test_single_seat_setup.cpp (+7/-4)
tests/unit-tests/input/android/test_android_input_sender.cpp (+44/-2)
tests/unit-tests/input/evdev/test_libinput_device.cpp (+10/-1)
tests/unit-tests/input/test_nested_input_platform.cpp (+4/-2)
tests/unit-tests/input/test_seat_input_device_tracker.cpp (+10/-5)
tests/unit-tests/input/test_x11_platform.cpp (+3/-1)
tests/unit-tests/scene/test_abstract_shell.cpp (+24/-0)
To merge this branch: bzr merge lp:~andreas-pokorny/mir/send-input-device-state-event
Reviewer Review Type Date Requested Status
Mir CI Bot continuous-integration Approve
Alan Griffiths Needs Fixing
Kevin DuBois (community) Approve
Review via email: mp+297062@code.launchpad.net

Commit message

Make use of the input device state event

AbstractShell sends that event on focus change, the XkbMapper receives that information and used it to update its xkb_state. Additionally the nested input platform forwards that event.

Description of the change

This change now makes use of the new input device state event. The event needs to update the xkb pressed state inside the xkb_mapper, before any further key input events are mapped by the keymapper. So the device state event is sent "on" focus change. "on" because focus is a surface attribute change and because user input has its own queue. It is also necessary for toolkits so that they can redraw menues based on the current modifier state after a focus change.

The handling in nested input platform is a bit special - since input platforms usually do not need to emit an input device state event - but a nested session might be occluded/unfocused/paused so might not have seen the input presses happening.

This change also includes the ability to add event filters prior to startup. That combined with the input device state event provides a utility to detect that a nested server is up, running, focused and capable of receiving events.

In upcoming branches I plan to use that to avoid some of the unconditional sleeps in our acceptance tests.

To post a comment you must log in.
Revision history for this message
Mir CI Bot (mir-ci-bot) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
Mir CI Bot (mir-ci-bot) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
Mir CI Bot (mir-ci-bot) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
Mir CI Bot (mir-ci-bot) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
Mir CI Bot (mir-ci-bot) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
Andreas Pokorny (andreas-pokorny) wrote :

ah there is a shutdown problem shown in one of the nested server tests.

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

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

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

review: Needs Fixing (continuous-integration)
Revision history for this message
Mir CI Bot (mir-ci-bot) wrote :

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

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

review: Needs Fixing (continuous-integration)
Revision history for this message
Mir CI Bot (mir-ci-bot) wrote :

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

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

review: Approve (continuous-integration)
Revision history for this message
Kevin DuBois (kdub) wrote :

nits, otherwise, lgtm

16: + virtual EventUPtr device_state_event(float cursor_x, float cursor_y) = 0;
Would be nice if Point/X/Y could be stored as a float in those types.

199, 1232,1233:
+ mutable std::mutex guard;
std::mutex mutable guard; is more like other use of mutable or const

150:
extra line

300:
+ [this](MirEvent const& event, mir::geometry::Rectangle const& area)
[this](auto const& event, auto const& area) is a bit shorter

1158:
aligned to tab after commas, should just have one space.

1432:
+TEST_F(AbstractShell, as_focus_controller_emits_input_device_state_event_on_focus_change)
"as_focus_controller_" is a bit redundant, just "emits_input_Device_state_change_on_focus_change" is better.

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

CI failure was new and in NestedInput*, probably needs some investigation....

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

FAILED: Autolanding.
More details in the following jenkins job:
https://mir-jenkins.ubuntu.com/job/mir-autolanding/382/
Executed test runs:
    FAILURE: https://mir-jenkins.ubuntu.com/job/build-mir/1436/console
    None: https://mir-jenkins.ubuntu.com/job/generic-land-mp/410/console
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-0-fetch/1488
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-1-sourcepkg/release=vivid+overlay/1479
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-1-sourcepkg/release=xenial/1479
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=clang,platform=mesa,release=vivid+overlay/1450
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=clang,platform=mesa,release=vivid+overlay/1450/artifact/output/*zip*/output.zip
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=gcc,platform=mesa,release=xenial/1450
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=gcc,platform=mesa,release=xenial/1450/artifact/output/*zip*/output.zip
    FAILURE: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=cross-armhf,compiler=gcc,platform=android,release=vivid+overlay/1450/console
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=cross-armhf,compiler=gcc,platform=android,release=vivid+overlay/1450/artifact/output/*zip*/output.zip
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=i386,compiler=gcc,platform=android,release=vivid+overlay/1450
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=i386,compiler=gcc,platform=android,release=vivid+overlay/1450/artifact/output/*zip*/output.zip
    FAILURE: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=i386,compiler=gcc,platform=mesa,release=xenial/1450/console

review: Needs Fixing (continuous-integration)
Revision history for this message
Mir CI Bot (mir-ci-bot) wrote :

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

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

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

CI Problem while setting up krillin ^
22:10:51 Slave went offline during the build
22:10:51 ERROR: Connection was broken: java.io.EOFException

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

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

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

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

Another problem with the krillin, now while flashing the device:
06:14:39 WARNING:root:Unable to mark device offline automatically
06:14:39 Traceback (most recent call last):
06:14:39 File "./recover", line 124, in <module>
06:14:39 print(recover(name))
06:14:39 File "./recover", line 114, in recover
06:14:39 return _full_recovery(device)
06:14:39 File "./recover", line 24, in _full_recovery
06:14:39 device.reimage_from_fastboot()
06:14:39 File "/var/lib/jenkins/slaves/krillin-01/workspace/device-runtests-mir/device_type/krillin/lifeboat/device_info.py", line 100, in reimage_from_fastboot
06:14:39 subprocess.check_output(udf_command)
06:14:39 File "/usr/lib/python2.7/subprocess.py", line 573, in check_output
06:14:39 raise CalledProcessError(retcode, cmd, output=output)
06:14:39 subprocess.CalledProcessError: Command '['ubuntu-device-flash', '--server', 'https://system-image.ubuntu.com', 'touch', '--serial', 'JB011018', '--channel', 'ubuntu-touch/stable/bq-aquaris.en', '--bootstrap', '--developer-mode', '--password', '0000']' returned non-zero exit status 1
06:14:40 Build step 'Execute shell' marked build as failure
06:14:41 Archiving artifacts
06:14:44 [WS-CLEANUP] Deleting project workspace...[WS-CLEANUP] done
06:14:44 Finished: FAILURE

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

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

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

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

Nits:

+#include "mir/events/event_builders.h"

this isn't needed by the header (or any of the files that include it).

~~~~

+ /**
+ * Set all pressed scan codes.
+ * \param scan_codes currently pressed
+ */
+ virtual void set_key_state(std::vector<uint32_t> const& scan_codes) = 0;
+ /**
+ * Set button state of a pointing device.
+ * \param buttons mask of the buttons currently pressed
+ */
+ virtual void set_pointer_state(MirPointerButtons buttons) = 0;

These names seem a little odd for an InputSink. (Maybe it is just my experience with C# and Java suggesting "set_" implies these are properties.) Anyway, "key_state()" or "key_state_is()" would be better than "set_key_state()"

~~~~

- std::mutex guard;
+ mutable std::mutex guard;

We put the cv-qualifier after the type:

    std::mutex mutable guard;

~~~~

+#include "mir/event_printer.h"

Needed?

review: Needs Fixing
Revision history for this message
Mir CI Bot (mir-ci-bot) :
review: Approve (continuous-integration)
Revision history for this message
Andreas Pokorny (andreas-pokorny) wrote :

> Nits:
>
> +#include "mir/events/event_builders.h"
>
> this isn't needed by the header (or any of the files that include it).
>
> ~~~~
>
> + /**
> + * Set all pressed scan codes.
> + * \param scan_codes currently pressed
> + */
> + virtual void set_key_state(std::vector<uint32_t> const& scan_codes) = 0;
> + /**
> + * Set button state of a pointing device.
> + * \param buttons mask of the buttons currently pressed
> + */
> + virtual void set_pointer_state(MirPointerButtons buttons) = 0;
>
> These names seem a little odd for an InputSink. (Maybe it is just my
> experience with C# and Java suggesting "set_" implies these are properties.)
> Anyway, "key_state()" or "key_state_is()" would be better than
> "set_key_state()"
>
> ~~~~
>
> - std::mutex guard;
> + mutable std::mutex guard;
>
> We put the cv-qualifier after the type:
>
> std::mutex mutable guard;
>
> ~~~~
>
> +#include "mir/event_printer.h"
>
> Needed?

Nah all of that is valid, also fixed what kdub complained about. If the MP lands, I am going to prepare that in a new MP

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'include/platform/mir/input/event_builder.h'
2--- include/platform/mir/input/event_builder.h 2016-01-29 08:18:22 +0000
3+++ include/platform/mir/input/event_builder.h 2016-07-06 21:48:16 +0000
4@@ -21,6 +21,7 @@
5 #define MIR_INPUT_EVENT_BUILDER_H_
6
7 #include "mir_toolkit/event.h"
8+#include "mir/events/event_builders.h"
9 #include <memory>
10 #include <chrono>
11
12@@ -51,6 +52,8 @@
13
14 virtual EventUPtr configuration_event(Timestamp timestamp, MirInputConfigurationAction action) = 0;
15
16+ virtual EventUPtr device_state_event(float cursor_x, float cursor_y) = 0;
17+
18 protected:
19 EventBuilder(EventBuilder const&) = delete;
20 EventBuilder& operator=(EventBuilder const&) = delete;
21
22=== modified file 'include/platform/mir/input/input_sink.h'
23--- include/platform/mir/input/input_sink.h 2016-01-29 08:18:22 +0000
24+++ include/platform/mir/input/input_sink.h 2016-07-06 21:48:16 +0000
25@@ -24,6 +24,8 @@
26 #include "mir/geometry/rectangle.h"
27 #include "mir/geometry/displacement.h"
28
29+#include <vector>
30+
31 namespace mir
32 {
33 namespace input
34@@ -39,6 +41,26 @@
35 */
36 virtual mir::geometry::Rectangle bounding_rectangle() const = 0;
37
38+ /**
39+ * \name Device State interface of InputSink
40+ *
41+ * In scenarios in which the device is not capable of seeing all changes as they occur,
42+ * these method should be used to update the input device state as needed
43+ * \{
44+ */
45+ /**
46+ * Set all pressed scan codes.
47+ * \param scan_codes currently pressed
48+ */
49+ virtual void set_key_state(std::vector<uint32_t> const& scan_codes) = 0;
50+ /**
51+ * Set button state of a pointing device.
52+ * \param buttons mask of the buttons currently pressed
53+ */
54+ virtual void set_pointer_state(MirPointerButtons buttons) = 0;
55+ /**
56+ * \}
57+ */
58 private:
59 InputSink(InputSink const&) = delete;
60 InputSink& operator=(InputSink const&) = delete;
61
62=== modified file 'include/test/mir/test/event_matchers.h'
63--- include/test/mir/test/event_matchers.h 2016-05-03 06:55:25 +0000
64+++ include/test/mir/test/event_matchers.h 2016-07-06 21:48:16 +0000
65@@ -503,6 +503,38 @@
66 return false;
67 }
68
69+MATCHER(InputDeviceStateEvent, "")
70+{
71+ auto as_address = to_address(arg);
72+ if (mir_event_get_type(as_address) == mir_event_type_input_device_state)
73+ return true;
74+ return false;
75+}
76+
77+MATCHER_P(DeviceStateWithPressedKeys, keys, "")
78+{
79+ auto as_address = to_address(arg);
80+ if (mir_event_get_type(as_address) != mir_event_type_input_device_state)
81+ return false;
82+ auto device_state = mir_event_get_input_device_state_event(as_address);
83+ for (size_t index = 0, count = mir_input_device_state_event_device_count(device_state);
84+ index != count; ++index)
85+ {
86+ auto key_count = mir_input_device_state_event_device_pressed_keys_count(device_state, index);
87+ auto it_keys = begin(keys);
88+ auto end_keys = end(keys);
89+ decltype(key_count) num_required_keys = distance(it_keys, end_keys);
90+ if (num_required_keys != key_count)
91+ continue;
92+
93+ auto pressed_keys = mir_input_device_state_event_device_pressed_keys(device_state, index);
94+ if (!std::equal(it_keys, end_keys, pressed_keys))
95+ continue;
96+ return true;
97+ }
98+ return false;
99+}
100+
101 MATCHER(InputDeviceConfigurationChangedEvent, "")
102 {
103 auto as_address = to_address(arg);
104
105=== modified file 'src/client/input/android/android_input_lexicon.cpp'
106--- src/client/input/android/android_input_lexicon.cpp 2016-01-29 08:18:22 +0000
107+++ src/client/input/android/android_input_lexicon.cpp 2016-07-06 21:48:16 +0000
108@@ -20,6 +20,7 @@
109 #include "mir/input/android/android_input_lexicon.h"
110 #include "mir/input/android/event_conversion_helpers.h"
111 #include "mir/events/event_builders.h"
112+#include "mir/events/event.h"
113 #include "mir/cookie/blob.h"
114
115 #include <androidfw/Input.h>
116@@ -36,6 +37,11 @@
117 {
118 switch(android_event->getType())
119 {
120+ case AINPUT_EVENT_TYPE_BUFFER:
121+ {
122+ auto buf = static_cast<const droidinput::RawBufferEvent*>(android_event);
123+ return MirEvent::deserialize(buf->buffer);
124+ }
125 case AINPUT_EVENT_TYPE_KEY:
126 {
127 auto kev = static_cast<const droidinput::KeyEvent*>(android_event);
128
129=== modified file 'src/client/input/android/android_input_receiver.cpp'
130--- src/client/input/android/android_input_receiver.cpp 2016-06-09 18:38:05 +0000
131+++ src/client/input/android/android_input_receiver.cpp 2016-07-06 21:48:16 +0000
132@@ -132,9 +132,6 @@
133 // of XKBMapper per device id (or modify XKBMapper semantics)
134 if (mir_event_get_type(&ev) != mir_event_type_input)
135 return;
136- if (mir_input_event_get_type(mir_event_get_input_event(&ev)) !=
137- mir_input_event_type_key)
138- return;
139
140 xkb_mapper->map_event(ev);
141 }
142
143=== modified file 'src/client/input/xkb_mapper.cpp'
144--- src/client/input/xkb_mapper.cpp 2016-06-24 06:43:18 +0000
145+++ src/client/input/xkb_mapper.cpp 2016-07-06 21:48:16 +0000
146@@ -76,7 +76,6 @@
147 // xkb scancodes are offset by 8 from evdev scancodes for compatibility with X protocol.
148 return evdev_scan_code + 8;
149 }
150-
151 }
152
153 mi::XKBContextPtr mi::make_unique_context()
154@@ -232,6 +231,14 @@
155 update_modifier();
156 }
157
158+MirInputEventModifiers mircv::XKBMapper::modifiers() const
159+{
160+ std::lock_guard<std::mutex> lg(guard);
161+ if (modifier_state.is_set())
162+ return expand_modifiers(modifier_state.value());
163+ return mir_input_event_modifier_none;
164+}
165+
166 mircv::XKBMapper::XkbMappingState::XkbMappingState(std::shared_ptr<xkb_keymap> const& keymap)
167 : keymap{keymap}, state{make_unique_state(this->keymap.get())}
168 {
169
170=== modified file 'src/include/common/mir/input/key_mapper.h'
171--- src/include/common/mir/input/key_mapper.h 2016-06-23 15:09:02 +0000
172+++ src/include/common/mir/input/key_mapper.h 2016-07-06 21:48:16 +0000
173@@ -88,6 +88,7 @@
174 * masks in input events with the modifier mask evaluated by this Keymapper.
175 */
176 virtual void map_event(MirEvent& event) = 0;
177+ virtual MirInputEventModifiers modifiers() const = 0;
178
179 protected:
180 KeyMapper(KeyMapper const&) = delete;
181
182=== modified file 'src/include/common/mir/input/xkb_mapper.h'
183--- src/include/common/mir/input/xkb_mapper.h 2016-06-24 06:43:18 +0000
184+++ src/include/common/mir/input/xkb_mapper.h 2016-07-06 21:48:16 +0000
185@@ -58,7 +58,7 @@
186 void clear_keymap_for_device(MirInputDeviceId id) override;
187 void clear_all_keymaps() override;
188 void map_event(MirEvent& event) override;
189-
190+ MirInputEventModifiers modifiers() const override;
191
192 protected:
193 XKBMapper(XKBMapper const&) = delete;
194@@ -69,7 +69,7 @@
195 void set_keymap(XKBKeymapPtr map);
196 void update_modifier();
197
198- std::mutex guard;
199+ mutable std::mutex guard;
200
201 struct XkbMappingState
202 {
203
204=== modified file 'src/include/server/mir/input/seat.h'
205--- src/include/server/mir/input/seat.h 2016-06-20 17:10:33 +0000
206+++ src/include/server/mir/input/seat.h 2016-07-06 21:48:16 +0000
207@@ -25,9 +25,11 @@
208 #include "mir_toolkit/event.h"
209
210 #include <memory>
211+#include <vector>
212
213 namespace mir
214 {
215+using EventUPtr = std::unique_ptr<MirEvent, void(*)(MirEvent*)>;
216 namespace input
217 {
218 class Device;
219@@ -40,6 +42,11 @@
220 virtual void remove_device(Device const& device) = 0;
221 virtual void dispatch_event(MirEvent& event) = 0;
222 virtual geometry::Rectangle get_rectangle_for(Device const& dev) = 0;
223+ virtual EventUPtr create_device_state() = 0;
224+
225+ virtual void set_key_state(Device const& dev, std::vector<uint32_t> const& scan_codes) = 0;
226+ virtual void set_pointer_state(Device const& dev, MirPointerButtons buttons) = 0;
227+ virtual void set_cursor_position(float cursor_x, float cursor_y) = 0;
228 virtual void set_confinement_regions(geometry::Rectangles const& regions) = 0;
229 virtual void reset_confinement_regions() = 0;
230 private:
231
232=== modified file 'src/server/graphics/nested/display_buffer.cpp'
233--- src/server/graphics/nested/display_buffer.cpp 2016-06-09 13:15:34 +0000
234+++ src/server/graphics/nested/display_buffer.cpp 2016-07-06 21:48:16 +0000
235@@ -110,10 +110,9 @@
236
237 void mgn::detail::DisplayBuffer::mir_event(MirEvent const& event)
238 {
239- if (mir_event_get_type(&event) != mir_event_type_input)
240- return;
241-
242- host_connection->emit_input_event(event, area);
243+ if (mir_event_get_type(&event) == mir_event_type_input ||
244+ mir_event_get_type(&event) == mir_event_type_input_device_state)
245+ host_connection->emit_input_event(event, area);
246 }
247
248 mg::NativeDisplayBuffer* mgn::detail::DisplayBuffer::native_display_buffer()
249
250=== modified file 'src/server/graphics/nested/input_platform.cpp'
251--- src/server/graphics/nested/input_platform.cpp 2016-06-07 16:20:53 +0000
252+++ src/server/graphics/nested/input_platform.cpp 2016-07-06 21:48:16 +0000
253@@ -31,6 +31,7 @@
254 #include "mir/dispatch/action_queue.h"
255 #include "mir/events/event_builders.h"
256 #include "mir/events/event_private.h"
257+#include "mir/event_printer.h"
258
259 #include <chrono>
260
261@@ -107,13 +108,14 @@
262 case mir_input_event_type_key:
263 {
264 auto const* key_event = mir_input_event_get_keyboard_event(event);
265- destination->handle_input(*builder->key_event(
266+
267+ auto new_kev = builder->key_event(
268 event_time,
269 mir_keyboard_event_action(key_event),
270 mir_keyboard_event_key_code(key_event),
271 mir_keyboard_event_scan_code(key_event)
272- ));
273-
274+ );
275+ destination->handle_input(*new_kev);
276 break;
277 }
278 case mir_input_event_type_pointer:
279@@ -209,28 +211,65 @@
280 action_queue->enqueue([this]{update_devices();});
281 });
282
283- connection->set_input_event_callback([this](MirEvent const& event, mir::geometry::Rectangle const& area) {
284- auto const* input_ev = mir_event_get_input_event(&event);
285- auto const id = mir_input_event_get_device_id(input_ev);
286- auto it = devices.find(id);
287- if (it != end(devices))
288- {
289- it->second->emit_event(input_ev, area);
290- }
291- else // device was not advertised to us yet.
292- {
293- unknown_device_events[id].emplace_back(
294- std::piecewise_construct,
295- std::forward_as_tuple(event.clone(), [](MirEvent* e){delete e;}),
296- std::forward_as_tuple(area));
297- }
298- });
299+ connection->set_input_event_callback(
300+ [this](MirEvent const& event, mir::geometry::Rectangle const& area)
301+ {
302+ auto const event_type = mir_event_get_type(&event);
303+
304+ if (event_type == mir_event_type_input)
305+ {
306+ auto const* input_ev = mir_event_get_input_event(&event);
307+ auto const id = mir_input_event_get_device_id(input_ev);
308+ auto it = devices.find(id);
309+ if (it != end(devices))
310+ {
311+ it->second->emit_event(input_ev, area);
312+ }
313+ else // device was not advertised to us yet.
314+ {
315+ unknown_device_events[id].emplace_back(
316+ std::piecewise_construct,
317+ std::forward_as_tuple(event.clone(), [](MirEvent* e){delete e;}),
318+ std::forward_as_tuple(area));
319+ }
320+ }
321+ else if (event_type == mir_event_type_input_device_state)
322+ {
323+ if (!devices.empty())
324+ {
325+ auto const* device_state = mir_event_get_input_device_state_event(&event);
326+ for (size_t index = 0, end_index = mir_input_device_state_event_device_count(device_state);
327+ index != end_index; ++index)
328+ {
329+ auto it = devices.find(mir_input_device_state_event_device_id(device_state, index));
330+ if (it != end(devices) && it->second->destination)
331+ {
332+ auto dest = it->second->destination;
333+ auto key_count = mir_input_device_state_event_device_pressed_keys_count(device_state, index);
334+ auto const* scan_codes = mir_input_device_state_event_device_pressed_keys(device_state, index);
335+
336+ dest->set_key_state({scan_codes, scan_codes + key_count});
337+ dest->set_pointer_state(
338+ mir_input_device_state_event_device_pointer_buttons(device_state, index));
339+ }
340+ }
341+
342+ auto& front = begin(devices)->second;
343+ auto device_state_event = front->builder->device_state_event(
344+ mir_input_device_state_event_pointer_axis(device_state, mir_pointer_axis_x),
345+ mir_input_device_state_event_pointer_axis(device_state, mir_pointer_axis_y));
346+ front->destination->handle_input(*device_state_event);
347+ }
348+ }
349+ });
350 }
351
352 void mgn::InputPlatform::stop()
353 {
354 std::function<void(mgn::UniqueInputConfig)> reset;
355 connection->set_input_device_change_callback(reset);
356+ std::function<void(MirEvent const&, mir::geometry::Rectangle const&)> empty_event_callback;
357+ connection->set_input_event_callback(empty_event_callback);
358
359 for(auto const& device : devices)
360 input_device_registry->remove_device(device.second);
361
362=== modified file 'src/server/input/android/input_sender.cpp'
363--- src/server/input/android/input_sender.cpp 2016-05-03 06:55:25 +0000
364+++ src/server/input/android/input_sender.cpp 2016-07-06 21:48:16 +0000
365@@ -163,29 +163,38 @@
366
367 void mia::InputSender::ActiveTransfer::send(uint32_t sequence_id, MirEvent const& event)
368 {
369- if (mir_event_get_type(&event) != mir_event_type_input)
370+ auto const type = mir_event_get_type(&event);
371+
372+ if (type != mir_event_type_input_device_state && type != mir_event_type_input)
373 return;
374
375 droidinput::status_t error_status;
376
377- auto event_time = mir_input_event_get_event_time(mir_event_get_input_event(&event));
378- auto input_event = mir_event_get_input_event(&event);
379- switch(mir_input_event_get_type(input_event))
380- {
381- case mir_input_event_type_key:
382- error_status = send_key_event(sequence_id, event);
383- state.report->published_key_event(channel->server_fd(), sequence_id, event_time);
384- break;
385- case mir_input_event_type_touch:
386- error_status = send_touch_event(sequence_id, event);
387- state.report->published_motion_event(channel->server_fd(), sequence_id, event_time);
388- break;
389- case mir_input_event_type_pointer:
390- error_status = send_pointer_event(sequence_id, event);
391- state.report->published_motion_event(channel->server_fd(), sequence_id, event_time);
392- break;
393- default:
394- BOOST_THROW_EXCEPTION(std::runtime_error("unknown input event type"));
395+ if (type == mir_event_type_input)
396+ {
397+ auto event_time = mir_input_event_get_event_time(mir_event_get_input_event(&event));
398+ auto input_event = mir_event_get_input_event(&event);
399+ switch(mir_input_event_get_type(input_event))
400+ {
401+ case mir_input_event_type_key:
402+ error_status = send_key_event(sequence_id, event);
403+ state.report->published_key_event(channel->server_fd(), sequence_id, event_time);
404+ break;
405+ case mir_input_event_type_touch:
406+ error_status = send_touch_event(sequence_id, event);
407+ state.report->published_motion_event(channel->server_fd(), sequence_id, event_time);
408+ break;
409+ case mir_input_event_type_pointer:
410+ error_status = send_pointer_event(sequence_id, event);
411+ state.report->published_motion_event(channel->server_fd(), sequence_id, event_time);
412+ break;
413+ default:
414+ BOOST_THROW_EXCEPTION(std::runtime_error("unknown input event type"));
415+ }
416+ }
417+ else
418+ {
419+ error_status = publisher.publishEventBuffer(sequence_id, MirEvent::serialize(&event));
420 }
421
422 switch(error_status)
423
424=== modified file 'src/server/input/basic_seat.cpp'
425--- src/server/input/basic_seat.cpp 2016-06-28 13:19:50 +0000
426+++ src/server/input/basic_seat.cpp 2016-07-06 21:48:16 +0000
427@@ -30,8 +30,9 @@
428 std::shared_ptr<mi::TouchVisualizer> const& touch_visualizer,
429 std::shared_ptr<mi::CursorListener> const& cursor_listener,
430 std::shared_ptr<mi::InputRegion> const& input_region,
431- std::shared_ptr<mi::KeyMapper> const& key_mapper)
432- : input_state_tracker{dispatcher, touch_visualizer, cursor_listener, input_region, key_mapper}, input_region{input_region}
433+ std::shared_ptr<mi::KeyMapper> const& key_mapper,
434+ std::shared_ptr<time::Clock> const& clock)
435+ : input_state_tracker{dispatcher, touch_visualizer, cursor_listener, input_region, key_mapper, clock}, input_region{input_region}
436 {
437 }
438
439@@ -59,6 +60,26 @@
440 return input_region->bounding_rectangle();
441 }
442
443+mir::EventUPtr mi::BasicSeat::create_device_state()
444+{
445+ return input_state_tracker.create_device_state();
446+}
447+
448+void mi::BasicSeat::set_key_state(Device const& dev, std::vector<uint32_t> const& scan_codes)
449+{
450+ input_state_tracker.set_key_state(dev.id(), scan_codes);
451+}
452+
453+void mi::BasicSeat::set_pointer_state(Device const& dev, MirPointerButtons buttons)
454+{
455+ input_state_tracker.set_pointer_state(dev.id(), buttons);
456+}
457+
458+void mi::BasicSeat::set_cursor_position(float cursor_x, float cursor_y)
459+{
460+ input_state_tracker.set_cursor_position(cursor_x, cursor_y);
461+}
462+
463 void mi::BasicSeat::set_confinement_regions(geometry::Rectangles const& regions)
464 {
465 input_state_tracker.set_confinement_regions(regions);
466
467=== modified file 'src/server/input/basic_seat.h'
468--- src/server/input/basic_seat.h 2016-06-28 13:19:50 +0000
469+++ src/server/input/basic_seat.h 2016-07-06 21:48:16 +0000
470@@ -28,6 +28,10 @@
471
472 namespace mir
473 {
474+namespace time
475+{
476+class Clock;
477+}
478 namespace input
479 {
480 class TouchVisualizer;
481@@ -43,15 +47,20 @@
482 std::shared_ptr<TouchVisualizer> const& touch_visualizer,
483 std::shared_ptr<CursorListener> const& cursor_listener,
484 std::shared_ptr<InputRegion> const& input_region,
485- std::shared_ptr<KeyMapper> const& key_mapper);
486+ std::shared_ptr<KeyMapper> const& key_mapper,
487+ std::shared_ptr<time::Clock> const& clock);
488 // Seat methods:
489 void add_device(Device const& device) override;
490 void remove_device(Device const& device) override;
491 void dispatch_event(MirEvent& event) override;
492 geometry::Rectangle get_rectangle_for(Device const& dev) override;
493+ virtual EventUPtr create_device_state() override;
494 virtual void set_confinement_regions(geometry::Rectangles const& regions) override;
495 virtual void reset_confinement_regions() override;
496
497+ void set_key_state(Device const& dev, std::vector<uint32_t> const& scan_codes) override;
498+ void set_pointer_state(Device const& dev, MirPointerButtons buttons) override;
499+ void set_cursor_position(float cursor_x, float cursor_y) override;
500 private:
501 SeatInputDeviceTracker input_state_tracker;
502 std::shared_ptr<InputRegion> const input_region;
503
504=== modified file 'src/server/input/default_configuration.cpp'
505--- src/server/input/default_configuration.cpp 2016-06-02 08:20:22 +0000
506+++ src/server/input/default_configuration.cpp 2016-07-06 21:48:16 +0000
507@@ -332,7 +332,8 @@
508 the_touch_visualizer(),
509 the_cursor_listener(),
510 the_input_region(),
511- the_key_mapper());
512+ the_key_mapper(),
513+ the_clock());
514 });
515 }
516
517
518=== modified file 'src/server/input/default_event_builder.cpp'
519--- src/server/input/default_event_builder.cpp 2016-05-03 06:55:25 +0000
520+++ src/server/input/default_event_builder.cpp 2016-07-06 21:48:16 +0000
521@@ -18,6 +18,7 @@
522 */
523
524 #include "default_event_builder.h"
525+#include "mir/input/seat.h"
526 #include "mir/events/event_builders.h"
527 #include "mir/cookie/authority.h"
528 #include "mir/events/event_private.h"
529@@ -28,9 +29,11 @@
530 namespace mi = mir::input;
531
532 mi::DefaultEventBuilder::DefaultEventBuilder(MirInputDeviceId device_id,
533- std::shared_ptr<mir::cookie::Authority> const& cookie_authority)
534+ std::shared_ptr<mir::cookie::Authority> const& cookie_authority,
535+ std::shared_ptr<mi::Seat> const& seat)
536 : device_id(device_id),
537- cookie_authority(cookie_authority)
538+ cookie_authority(cookie_authority),
539+ seat(seat)
540 {
541 }
542
543@@ -86,3 +89,9 @@
544 {
545 return me::make_event(action, device_id, timestamp);
546 }
547+
548+mir::EventUPtr mi::DefaultEventBuilder::device_state_event(float cursor_x, float cursor_y)
549+{
550+ seat->set_cursor_position(cursor_x, cursor_y);
551+ return seat->create_device_state();
552+}
553
554=== modified file 'src/server/input/default_event_builder.h'
555--- src/server/input/default_event_builder.h 2016-01-29 08:18:22 +0000
556+++ src/server/input/default_event_builder.h 2016-07-06 21:48:16 +0000
557@@ -31,11 +31,14 @@
558 }
559 namespace input
560 {
561+class Seat;
562+
563 class DefaultEventBuilder : public EventBuilder
564 {
565 public:
566 explicit DefaultEventBuilder(MirInputDeviceId device_id,
567- std::shared_ptr<cookie::Authority> const& cookie_authority);
568+ std::shared_ptr<cookie::Authority> const& cookie_authority,
569+ std::shared_ptr<Seat> const& seat);
570
571 EventUPtr key_event(Timestamp timestamp, MirKeyboardAction action, xkb_keysym_t key_code, int scan_code) override;
572
573@@ -50,9 +53,11 @@
574
575 EventUPtr configuration_event(Timestamp timestamp, MirInputConfigurationAction action) override;
576
577+ EventUPtr device_state_event(float cursor_x, float cursor_y) override;
578 private:
579 MirInputDeviceId const device_id;
580 std::shared_ptr<cookie::Authority> const cookie_authority;
581+ std::shared_ptr<Seat> const seat;
582 };
583 }
584 }
585
586=== modified file 'src/server/input/default_input_device_hub.cpp'
587--- src/server/input/default_input_device_hub.cpp 2016-06-02 08:20:22 +0000
588+++ src/server/input/default_input_device_hub.cpp 2016-07-06 21:48:16 +0000
589@@ -142,7 +142,11 @@
590 std::shared_ptr<dispatch::MultiplexingDispatchable> const& multiplexer,
591 std::shared_ptr<mir::cookie::Authority> const& cookie_authority,
592 std::shared_ptr<mi::DefaultDevice> const& handle)
593- : handle(handle), device_id(device_id), builder(device_id, cookie_authority), device(dev), multiplexer(multiplexer)
594+ : handle(handle),
595+ device_id(device_id),
596+ cookie_authority(cookie_authority),
597+ device(dev),
598+ multiplexer(multiplexer)
599 {
600 }
601
602@@ -160,7 +164,8 @@
603 {
604 auto type = mir_event_get_type(&event);
605
606- if (type != mir_event_type_input)
607+ if (type != mir_event_type_input &&
608+ type != mir_event_type_input_device_state)
609 BOOST_THROW_EXCEPTION(std::invalid_argument("Invalid input event received from device"));
610
611 if (!seat)
612@@ -177,13 +182,15 @@
613 void mi::DefaultInputDeviceHub::RegisteredDevice::start(std::shared_ptr<Seat> const& seat)
614 {
615 this->seat = seat;
616- device->start(this, &builder);
617+ builder = std::make_unique<DefaultEventBuilder>(device_id, cookie_authority, seat);
618+ device->start(this, builder.get());
619 }
620
621 void mi::DefaultInputDeviceHub::RegisteredDevice::stop()
622 {
623 device->stop();
624 seat = nullptr;
625+ builder.reset();
626 }
627
628 mir::geometry::Rectangle mi::DefaultInputDeviceHub::RegisteredDevice::bounding_rectangle() const
629@@ -194,6 +201,22 @@
630 return seat->get_rectangle_for(*handle);
631 }
632
633+void mi::DefaultInputDeviceHub::RegisteredDevice::set_key_state(std::vector<uint32_t> const& scan_codes)
634+{
635+ if (!seat)
636+ BOOST_THROW_EXCEPTION(std::runtime_error("Device not started and has no seat assigned"));
637+
638+ seat->set_key_state(*handle, scan_codes);
639+}
640+
641+void mi::DefaultInputDeviceHub::RegisteredDevice::set_pointer_state(MirPointerButtons buttons)
642+{
643+ if (!seat)
644+ BOOST_THROW_EXCEPTION(std::runtime_error("Device not started and has no seat assigned"));
645+
646+ seat->set_pointer_state(*handle, buttons);
647+}
648+
649 void mi::DefaultInputDeviceHub::add_observer(std::shared_ptr<InputDeviceObserver> const& observer)
650 {
651 observer_queue->enqueue(
652
653=== modified file 'src/server/input/default_input_device_hub.h'
654--- src/server/input/default_input_device_hub.h 2016-06-02 08:20:22 +0000
655+++ src/server/input/default_input_device_hub.h 2016-07-06 21:48:16 +0000
656@@ -108,9 +108,13 @@
657 MirInputDeviceId id();
658 std::shared_ptr<Seat> seat;
659 const std::shared_ptr<DefaultDevice> handle;
660+
661+ void set_key_state(std::vector<uint32_t> const& scan_codes) override;
662+ void set_pointer_state(MirPointerButtons buttons) override;
663 private:
664 MirInputDeviceId device_id;
665- DefaultEventBuilder builder;
666+ std::unique_ptr<DefaultEventBuilder> builder;
667+ std::shared_ptr<cookie::Authority> cookie_authority;
668 std::shared_ptr<InputDevice> const device;
669 std::shared_ptr<dispatch::MultiplexingDispatchable> const multiplexer;
670 };
671
672=== modified file 'src/server/input/seat_input_device_tracker.cpp'
673--- src/server/input/seat_input_device_tracker.cpp 2016-07-01 20:24:26 +0000
674+++ src/server/input/seat_input_device_tracker.cpp 2016-07-06 21:48:16 +0000
675@@ -26,6 +26,7 @@
676 #include "mir/geometry/displacement.h"
677 #include "mir/events/event_builders.h"
678 #include "mir/events/event_private.h"
679+#include "mir/time/clock.h"
680
681 #include "input_modifier_utils.h"
682
683@@ -44,9 +45,10 @@
684 std::shared_ptr<TouchVisualizer> const& touch_visualizer,
685 std::shared_ptr<CursorListener> const& cursor_listener,
686 std::shared_ptr<InputRegion> const& input_region,
687- std::shared_ptr<KeyMapper> const& key_mapper)
688+ std::shared_ptr<KeyMapper> const& key_mapper,
689+ std::shared_ptr<time::Clock> const& clock)
690 : dispatcher{dispatcher}, touch_visualizer{touch_visualizer}, cursor_listener{cursor_listener},
691- input_region{input_region}, key_mapper{key_mapper}, buttons{0},
692+ input_region{input_region}, key_mapper{key_mapper}, clock{clock}, buttons{0},
693 confine_function{[input_region](mir::geometry::Point& pos) { input_region->confine(pos); }}
694 {
695 }
696@@ -77,20 +79,23 @@
697
698 void mi::SeatInputDeviceTracker::dispatch(MirEvent &event)
699 {
700- auto input_event = mir_event_get_input_event(&event);
701-
702- if (filter_input_event(input_event))
703- return;
704-
705- update_seat_properties(input_event);
706-
707- key_mapper->map_event(event);
708-
709- if (mir_input_event_type_pointer == mir_input_event_get_type(input_event))
710+ if (mir_event_get_type(&event) == mir_event_type_input)
711 {
712- event.to_input()->to_motion()->set_x(0, cursor_x);
713- event.to_input()->to_motion()->set_y(0, cursor_y);
714- mev::set_button_state(event, button_state());
715+ auto input_event = mir_event_get_input_event(&event);
716+
717+ if (filter_input_event(input_event))
718+ return;
719+
720+ update_seat_properties(input_event);
721+
722+ key_mapper->map_event(event);
723+
724+ if (mir_input_event_type_pointer == mir_input_event_get_type(input_event))
725+ {
726+ event.to_input()->to_motion()->set_x(0, cursor_x);
727+ event.to_input()->to_motion()->set_y(0, cursor_y);
728+ mev::set_button_state(event, button_state());
729+ }
730 }
731
732 dispatcher->dispatch(event);
733@@ -227,6 +232,16 @@
734 cursor_listener->cursor_moved_to(cursor_x, cursor_y);
735 }
736
737+mir::EventUPtr mi::SeatInputDeviceTracker::create_device_state() const
738+{
739+ std::vector<mev::InputDeviceState> devices;
740+ devices.reserve(device_data.size());
741+ for (auto const& item : device_data)
742+ devices.push_back({item.first, item.second.scan_codes, item.second.buttons});
743+ return mev::make_event(
744+ clock->now().time_since_epoch(), buttons, key_mapper->modifiers(), cursor_x, cursor_y, std::move(devices));
745+}
746+
747 void mi::SeatInputDeviceTracker::DeviceData::update_scan_codes(MirKeyboardEvent const* event)
748 {
749 auto const action = mir_keyboard_event_action(event);
750@@ -237,6 +252,30 @@
751 scan_codes.erase(remove(begin(scan_codes), end(scan_codes), scan_code), end(scan_codes));
752 }
753
754+void mi::SeatInputDeviceTracker::set_key_state(MirInputDeviceId id, std::vector<uint32_t> const& scan_codes)
755+{
756+ key_mapper->set_key_state(id, scan_codes);
757+
758+ auto device = device_data.find(id);
759+
760+ if (device != end(device_data))
761+ device->second.scan_codes = scan_codes;
762+}
763+
764+void mi::SeatInputDeviceTracker::set_pointer_state(MirInputDeviceId id, MirPointerButtons buttons)
765+{
766+ auto device = device_data.find(id);
767+
768+ if (device != end(device_data))
769+ device->second.update_button_state(buttons);
770+}
771+
772+void mi::SeatInputDeviceTracker::set_cursor_position(float x, float y)
773+{
774+ cursor_x = x;
775+ cursor_y = y;
776+}
777+
778 bool mi::SeatInputDeviceTracker::DeviceData::allowed_scan_code_action(MirKeyboardEvent const* event) const
779 {
780 auto const action = mir_keyboard_event_action(event);
781
782=== modified file 'src/server/input/seat_input_device_tracker.h'
783--- src/server/input/seat_input_device_tracker.h 2016-07-01 20:24:26 +0000
784+++ src/server/input/seat_input_device_tracker.h 2016-07-06 21:48:16 +0000
785@@ -29,6 +29,11 @@
786
787 namespace mir
788 {
789+using EventUPtr = std::unique_ptr<MirEvent, void(*)(MirEvent*)>;
790+namespace time
791+{
792+class Clock;
793+}
794 namespace input
795 {
796 class CursorListener;
797@@ -50,7 +55,8 @@
798 std::shared_ptr<TouchVisualizer> const& touch_visualizer,
799 std::shared_ptr<CursorListener> const& cursor_listener,
800 std::shared_ptr<InputRegion> const& input_region,
801- std::shared_ptr<KeyMapper> const& key_mapper);
802+ std::shared_ptr<KeyMapper> const& key_mapper,
803+ std::shared_ptr<time::Clock> const& clock);
804 void add_device(MirInputDeviceId);
805 void remove_device(MirInputDeviceId);
806
807@@ -58,7 +64,11 @@
808
809 MirPointerButtons button_state() const;
810 geometry::Point cursor_position() const;
811+ EventUPtr create_device_state() const;
812
813+ void set_key_state(MirInputDeviceId id, std::vector<uint32_t> const& scan_codes);
814+ void set_pointer_state(MirInputDeviceId id, MirPointerButtons buttons);
815+ void set_cursor_position(float cursor_x, float cursor_y);
816 void set_confinement_regions(geometry::Rectangles const& region);
817 void reset_confinement_regions();
818 private:
819@@ -74,6 +84,7 @@
820 std::shared_ptr<CursorListener> const cursor_listener;
821 std::shared_ptr<InputRegion> const input_region;
822 std::shared_ptr<KeyMapper> const key_mapper;
823+ std::shared_ptr<time::Clock> const clock;
824
825 struct DeviceData
826 {
827
828=== modified file 'src/server/server.cpp'
829--- src/server/server.cpp 2016-06-22 14:43:28 +0000
830+++ src/server/server.cpp 2016-07-06 21:48:16 +0000
831@@ -23,6 +23,8 @@
832 #include "mir/frontend/connector.h"
833 #include "mir/graphics/graphic_buffer_allocator.h"
834 #include "mir/graphics/display_buffer.h"
835+#include "mir/input/composite_event_filter.h"
836+#include "mir/input/event_filter.h"
837 #include "mir/options/default_configuration.h"
838 #include "mir/renderer/gl/render_target.h"
839 #include "mir/default_server_configuration.h"
840@@ -41,6 +43,37 @@
841 #include <iostream>
842
843 namespace mo = mir::options;
844+namespace mi = mir::input;
845+
846+namespace
847+{
848+struct TemporaryCompositeEventFilter : public mi::CompositeEventFilter
849+{
850+ bool handle(MirEvent const&) override { return false; }
851+ void append(std::shared_ptr<mi::EventFilter> const& filter) override
852+ {
853+ append_event_filters.push_back(filter);
854+ }
855+ void prepend(std::shared_ptr<mi::EventFilter> const& filter) override
856+ {
857+ prepend_event_filters.push_back(filter);
858+ }
859+
860+ void move_filters(std::shared_ptr<mi::CompositeEventFilter> const& composite_event_filter)
861+ {
862+ for (auto const& filter : prepend_event_filters)
863+ composite_event_filter->prepend(filter);
864+
865+ for (auto const& filter : append_event_filters)
866+ composite_event_filter->append(filter);
867+
868+ append_event_filters.clear();
869+ prepend_event_filters.clear();
870+ }
871+ std::vector<std::shared_ptr<mi::EventFilter>> prepend_event_filters;
872+ std::vector<std::shared_ptr<mi::EventFilter>> append_event_filters;
873+};
874+}
875
876 #define FOREACH_WRAPPER(MACRO)\
877 MACRO(cursor)\
878@@ -76,7 +109,6 @@
879 MACRO(the_buffer_stream_factory)\
880 MACRO(the_compositor)\
881 MACRO(the_compositor_report)\
882- MACRO(the_composite_event_filter)\
883 MACRO(the_cursor_listener)\
884 MACRO(the_cursor)\
885 MACRO(the_display)\
886@@ -121,6 +153,8 @@
887 std::function<void()> exception_handler{};
888 Terminator terminator{};
889 EmergencyCleanupHandler emergency_cleanup_handler;
890+ std::shared_ptr<TemporaryCompositeEventFilter> temporary_event_filter{
891+ std::make_shared<TemporaryCompositeEventFilter>()};
892
893 std::function<void(int argc, char const* const* argv)> command_line_hander{};
894
895@@ -386,6 +420,9 @@
896 verify_accessing_allowed(self->server_config);
897
898 auto const emergency_cleanup = self->server_config->the_emergency_cleanup();
899+ auto const composite_event_filter = self->server_config->the_composite_event_filter();
900+
901+ self->temporary_event_filter->move_filters(composite_event_filter);
902
903 if (self->emergency_cleanup_handler)
904 emergency_cleanup->add(self->emergency_cleanup_handler);
905@@ -498,6 +535,14 @@
906
907 #undef MIR_SERVER_WRAP
908
909+auto mir::Server::the_composite_event_filter() const -> decltype(self->server_config->the_composite_event_filter())
910+{
911+ if (self->server_config)
912+ return self->server_config->the_composite_event_filter();
913+ else
914+ return self->temporary_event_filter;
915+}
916+
917 void mir::Server::add_configuration_option(
918 std::string const& option,
919 std::string const& description,
920
921=== modified file 'src/server/shell/abstract_shell.cpp'
922--- src/server/shell/abstract_shell.cpp 2016-06-20 17:10:33 +0000
923+++ src/server/shell/abstract_shell.cpp 2016-07-06 21:48:16 +0000
924@@ -254,6 +254,7 @@
925
926 // Ensure the surface has really taken the focus before notifying it that it is focused
927 input_targeter->set_focus(surface);
928+ surface->consume(seat->create_device_state().get());
929 surface->configure(mir_surface_attrib_focus, mir_surface_focused);
930 }
931 else
932
933=== modified file 'tests/acceptance-tests/test_nested_input.cpp'
934--- tests/acceptance-tests/test_nested_input.cpp 2016-05-03 06:55:25 +0000
935+++ tests/acceptance-tests/test_nested_input.cpp 2016-07-06 21:48:16 +0000
936@@ -75,19 +75,24 @@
937
938 struct NestedServerWithMockEventFilter : mtf::HeadlessNestedServerRunner
939 {
940- NestedServerWithMockEventFilter(std:: string const& connection_string)
941- : mtf::HeadlessNestedServerRunner(connection_string)
942+ NestedServerWithMockEventFilter(std::string const& connection_string,
943+ std::shared_ptr<MockEventFilter> const& event_filter)
944+ : mtf::HeadlessNestedServerRunner(connection_string), mock_event_filter{event_filter}
945 {
946+ server.the_composite_event_filter()->append(mock_event_filter);
947 start_server();
948- server.the_composite_event_filter()->append(mock_event_filter);
949-
950- }
951+ }
952+ NestedServerWithMockEventFilter(std::string const& connection_string)
953+ : NestedServerWithMockEventFilter(connection_string, std::make_shared<MockEventFilter>())
954+ {
955+ }
956+
957 ~NestedServerWithMockEventFilter()
958 {
959 stop_server();
960 }
961
962- std::shared_ptr<MockEventFilter> const mock_event_filter = std::make_shared<MockEventFilter>();
963+ std::shared_ptr<MockEventFilter> const mock_event_filter;
964 };
965
966 struct NestedInput : public mtf::HeadlessInProcessServer
967@@ -121,14 +126,52 @@
968 // Ensure the nested server posts a frame
969 connection = mir_connect_sync(connect_string.c_str(), __PRETTY_FUNCTION__);
970 surface = mtf::make_any_surface(connection);
971+ mir_surface_set_event_handler(surface, handle_event, this);
972 mir_buffer_stream_swap_buffers_sync(mir_surface_get_buffer_stream(surface));
973 }
974
975+ MOCK_METHOD1(handle_input, void(MirEvent const*));
976+
977+ void handle_surface_event(MirSurfaceEvent const* event)
978+ {
979+ auto const attrib = mir_surface_event_get_attribute(event);
980+ auto const value = mir_surface_event_get_attribute_value(event);
981+
982+ if (mir_surface_attrib_visibility == attrib &&
983+ mir_surface_visibility_exposed == value)
984+ exposed = true;
985+
986+ if (mir_surface_attrib_focus == attrib &&
987+ mir_surface_focused == value)
988+ focused = true;
989+
990+ if (exposed && focused)
991+ ready_to_accept_events.raise();
992+ }
993+
994+ static void handle_event(MirSurface*, MirEvent const* ev, void* context)
995+ {
996+ auto const client = static_cast<ExposedSurface*>(context);
997+ auto type = mir_event_get_type(ev);
998+ if (type == mir_event_type_surface)
999+ {
1000+ auto surface_event = mir_event_get_surface_event(ev);
1001+ client->handle_surface_event(surface_event);
1002+
1003+ }
1004+ if (type == mir_event_type_input)
1005+ client->handle_input(ev);
1006+ }
1007+
1008+ static void null_event_handler(MirSurface*, MirEvent const*, void*) {};
1009 ~ExposedSurface()
1010 {
1011+ mir_surface_set_event_handler(surface, null_event_handler, nullptr);
1012 mir_surface_release_sync(surface);
1013 mir_connection_release(connection);
1014 }
1015+ mir::test::Signal ready_to_accept_events;
1016+
1017 protected:
1018 ExposedSurface(ExposedSurface const&) = delete;
1019 ExposedSurface& operator=(ExposedSurface const&) = delete;
1020@@ -136,28 +179,32 @@
1021 private:
1022 MirConnection *connection;
1023 MirSurface *surface;
1024+ bool exposed{false};
1025+ bool focused{false};
1026 };
1027
1028 }
1029
1030 TEST_F(NestedInput, nested_event_filter_receives_keyboard_from_host)
1031 {
1032- NestedServerWithMockEventFilter nested_mir{new_connection()};
1033- ExposedSurface client(nested_mir.new_connection());
1034+ MockEventFilter nested_event_filter;
1035 std::atomic<int> num_key_a_events{0};
1036-
1037 auto const increase_key_a_events = [&num_key_a_events] { ++num_key_a_events; };
1038
1039 InSequence seq;
1040- EXPECT_CALL(*nested_mir.mock_event_filter, handle(mt::KeyOfScanCode(KEY_A))).
1041+ EXPECT_CALL(nested_event_filter, handle(mt::InputDeviceStateEvent()));
1042+ EXPECT_CALL(nested_event_filter, handle(mt::KeyOfScanCode(KEY_A))).
1043 Times(AtLeast(1)).
1044 WillRepeatedly(DoAll(InvokeWithoutArgs(increase_key_a_events), Return(true)));
1045
1046- EXPECT_CALL(*nested_mir.mock_event_filter, handle(mt::KeyOfScanCode(KEY_RIGHTSHIFT))).
1047+ EXPECT_CALL(nested_event_filter, handle(mt::KeyOfScanCode(KEY_RIGHTSHIFT))).
1048 Times(2).
1049 WillOnce(Return(true)).
1050 WillOnce(DoAll(mt::WakeUp(&all_events_received), Return(true)));
1051
1052+ NestedServerWithMockEventFilter nested_mir{new_connection(), mt::fake_shared(nested_event_filter)};
1053+ ExposedSurface client(nested_mir.new_connection());
1054+
1055 // Because we are testing a nested setup, it's difficult to guarantee
1056 // that the nested framebuffer surface (and consenquently the client surface
1057 // contained in it) is going to be ready (i.e., exposed and focused) to receive
1058@@ -229,3 +276,24 @@
1059
1060 input_device_changes_complete.wait_for(10s);
1061 }
1062+
1063+TEST_F(NestedInput, on_input_device_state_nested_server_emits_input_device_state)
1064+{
1065+ MockEventFilter nested_event_filter;
1066+ NestedServerWithMockEventFilter nested_mir{new_connection(), mt::fake_shared(nested_event_filter)};
1067+ ExposedSurface client_to_nested_mir(nested_mir.new_connection());
1068+
1069+ client_to_nested_mir.ready_to_accept_events.wait_for(1s);
1070+ ExposedSurface client_to_host(new_connection());
1071+ client_to_host.ready_to_accept_events.wait_for(1s);
1072+
1073+ EXPECT_CALL(client_to_host, handle_input(mt::KeyOfScanCode(KEY_LEFTALT)));
1074+ EXPECT_CALL(nested_event_filter,
1075+ handle(mt::DeviceStateWithPressedKeys(std::vector<uint32_t>({KEY_LEFTALT, KEY_TAB}))))
1076+ .WillOnce(DoAll(mt::WakeUp(&all_events_received), Return(true)));
1077+
1078+ fake_keyboard->emit_event(mis::a_key_down_event().of_scancode(KEY_LEFTALT));
1079+ fake_keyboard->emit_event(mis::a_key_down_event().of_scancode(KEY_TAB));
1080+
1081+ all_events_received.wait_for(2s);
1082+}
1083
1084=== modified file 'tests/include/mir/test/doubles/mock_input_seat.h'
1085--- tests/include/mir/test/doubles/mock_input_seat.h 2016-06-27 20:44:49 +0000
1086+++ tests/include/mir/test/doubles/mock_input_seat.h 2016-07-06 21:48:16 +0000
1087@@ -20,9 +20,10 @@
1088 #define MIR_TEST_DOUBLES_MOCK_INPUT_SEAT_H_
1089
1090 #include "mir/input/seat.h"
1091+#include "mir/input/device.h"
1092+#include "mir/test/gmock_fixes.h"
1093
1094 #include <gmock/gmock.h>
1095-#include "mir/input/device.h"
1096
1097 namespace mir
1098 {
1099@@ -36,6 +37,10 @@
1100 MOCK_METHOD1(remove_device, void(input::Device const& device));
1101 MOCK_METHOD1(dispatch_event, void(MirEvent& event));
1102 MOCK_METHOD1(get_rectangle_for, geometry::Rectangle(input::Device const& dev));
1103+ MOCK_METHOD0(create_device_state, mir::EventUPtr());
1104+ MOCK_METHOD2(set_key_state, void(input::Device const&, std::vector<uint32_t> const&));
1105+ MOCK_METHOD2(set_pointer_state, void (input::Device const&, MirPointerButtons));
1106+ MOCK_METHOD2(set_cursor_position, void (float, float));
1107 MOCK_METHOD1(set_confinement_regions, void(geometry::Rectangles const&));
1108 MOCK_METHOD0(reset_confinement_regions, void());
1109 };
1110
1111=== modified file 'tests/include/mir/test/doubles/mock_input_sink.h'
1112--- tests/include/mir/test/doubles/mock_input_sink.h 2015-07-21 17:57:15 +0000
1113+++ tests/include/mir/test/doubles/mock_input_sink.h 2016-07-06 21:48:16 +0000
1114@@ -35,6 +35,8 @@
1115 MOCK_METHOD1(handle_input, void(MirEvent&));
1116 MOCK_METHOD1(confine_pointer, void(mir::geometry::Point&));
1117 MOCK_CONST_METHOD0(bounding_rectangle, mir::geometry::Rectangle());
1118+ MOCK_METHOD1(set_key_state, void(std::vector<uint32_t> const&));
1119+ MOCK_METHOD1(set_pointer_state, void(MirPointerButtons));
1120 };
1121
1122 }
1123
1124=== modified file 'tests/include/mir/test/doubles/mock_key_mapper.h'
1125--- tests/include/mir/test/doubles/mock_key_mapper.h 2016-06-24 06:43:18 +0000
1126+++ tests/include/mir/test/doubles/mock_key_mapper.h 2016-07-06 21:48:16 +0000
1127@@ -40,6 +40,7 @@
1128 MOCK_METHOD1(clear_keymap_for_device, void(MirInputDeviceId id));
1129 MOCK_METHOD0(clear_all_keymaps, void());
1130 MOCK_METHOD1(map_event, void(MirEvent& event));
1131+ MOCK_CONST_METHOD0(modifiers, MirInputEventModifiers());
1132 };
1133
1134
1135
1136=== modified file 'tests/integration-tests/input/test_single_seat_setup.cpp'
1137--- tests/integration-tests/input/test_single_seat_setup.cpp 2016-06-02 08:20:22 +0000
1138+++ tests/integration-tests/input/test_single_seat_setup.cpp 2016-07-06 21:48:16 +0000
1139@@ -28,6 +28,7 @@
1140 #include "mir/test/doubles/mock_event_sink.h"
1141 #include "mir/test/doubles/triggered_main_loop.h"
1142 #include "mir/test/event_matchers.h"
1143+#include "mir/test/doubles/advanceable_clock.h"
1144 #include "mir/test/fake_shared.h"
1145
1146 #include "mir/dispatch/multiplexing_dispatchable.h"
1147@@ -81,10 +82,12 @@
1148 NiceMock<mtd::MockTouchVisualizer> mock_visualizer;
1149 mi::receiver::XKBMapper key_mapper;
1150 mir::dispatch::MultiplexingDispatchable multiplexer;
1151- mi::BasicSeat seat{mt::fake_shared(mock_dispatcher), mt::fake_shared(mock_visualizer),
1152- mt::fake_shared(mock_cursor_listener), mt::fake_shared(mock_region), mt::fake_shared(key_mapper)};
1153- mi::DefaultInputDeviceHub hub{mt::fake_shared(mock_sink), mt::fake_shared(seat), mt::fake_shared(multiplexer), mt::fake_shared(observer_loop),
1154- cookie_authority, mt::fake_shared(key_mapper)};
1155+ mtd::AdvanceableClock clock;
1156+ mi::BasicSeat seat{mt::fake_shared(mock_dispatcher), mt::fake_shared(mock_visualizer),
1157+ mt::fake_shared(mock_cursor_listener), mt::fake_shared(mock_region),
1158+ mt::fake_shared(key_mapper), mt::fake_shared(clock)};
1159+ mi::DefaultInputDeviceHub hub{mt::fake_shared(mock_sink), mt::fake_shared(seat), mt::fake_shared(multiplexer),
1160+ mt::fake_shared(observer_loop), cookie_authority, mt::fake_shared(key_mapper)};
1161 NiceMock<mtd::MockInputDeviceObserver> mock_observer;
1162
1163 mi::DeviceCapabilities const keyboard_caps = mi::DeviceCapability::keyboard | mi::DeviceCapability::alpha_numeric;
1164
1165=== modified file 'tests/unit-tests/input/android/test_android_input_sender.cpp'
1166--- tests/unit-tests/input/android/test_android_input_sender.cpp 2016-06-07 17:00:15 +0000
1167+++ tests/unit-tests/input/android/test_android_input_sender.cpp 2016-07-06 21:48:16 +0000
1168@@ -17,6 +17,7 @@
1169 */
1170
1171 #include "mir/events/event_private.h"
1172+#include "mir/events/event_builders.h"
1173
1174 #include "src/server/input/channel.h"
1175 #include "src/server/input/android/input_sender.h"
1176@@ -25,6 +26,7 @@
1177
1178 #include "mir/test/doubles/stub_scene_surface.h"
1179 #include "mir/test/doubles/mock_input_surface.h"
1180+#include "mir/test/doubles/mock_input_seat.h"
1181 #include "mir/test/doubles/stub_scene.h"
1182 #include "mir/test/doubles/mock_scene.h"
1183 #include "mir/test/doubles/triggered_main_loop.h"
1184@@ -54,7 +56,7 @@
1185 namespace mtd = mt::doubles;
1186 namespace droidinput = android;
1187
1188-using testing::_;
1189+using namespace testing;
1190
1191 namespace
1192 {
1193@@ -108,10 +110,11 @@
1194 mir::geometry::Displacement const movement{10, -10};
1195 std::shared_ptr<mir::cookie::Authority> const cookie_authority;
1196 mi::DefaultEventBuilder builder;
1197+ mtd::MockInputSeat seat;
1198
1199 AndroidInputSender()
1200 : cookie_authority(mir::cookie::Authority::create_from({0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88})),
1201- builder(MirInputDeviceId(), cookie_authority),
1202+ builder(MirInputDeviceId(), cookie_authority, mt::fake_shared(seat)),
1203 key_event(builder.key_event(std::chrono::nanoseconds(1), mir_keyboard_action_down, 7, test_scan_code)),
1204 motion_event(builder.touch_event(std::chrono::nanoseconds(-1))),
1205 pointer_event(builder.pointer_event(std::chrono::nanoseconds(123), mir_pointer_action_motion,
1206@@ -128,6 +131,7 @@
1207
1208 ON_CALL(event_factory, createKeyEvent()).WillByDefault(Return(&client_key_event));
1209 ON_CALL(event_factory, createMotionEvent()).WillByDefault(Return(&client_motion_event));
1210+ ON_CALL(event_factory, createRawBufferEvent()).WillByDefault(Return(&client_raw_event));
1211 }
1212
1213 void register_surface()
1214@@ -154,6 +158,7 @@
1215
1216 droidinput::MotionEvent client_motion_event;
1217 droidinput::KeyEvent client_key_event;
1218+ droidinput::RawBufferEvent client_raw_event;
1219
1220 testing::NiceMock<MockInputEventFactory> event_factory;
1221
1222@@ -490,3 +495,40 @@
1223 EXPECT_EQ(4, client_motion_event.getPointerId(2));
1224 EXPECT_EQ(3, client_motion_event.getPointerCount());
1225 }
1226+
1227+TEST_F(AndroidInputSender, encodes_input_device_state_event_as_raw_buffer_event)
1228+{
1229+ const float cursor_x = 50.0f;
1230+ const float cursor_y = 60.0f;
1231+ const auto timestamp = std::chrono::nanoseconds(10);
1232+ register_surface();
1233+ std::vector<mir::events::InputDeviceState> states;
1234+ states.push_back({MirInputDeviceId{23}, {50, 60, 80}, 0});
1235+ states.push_back({MirInputDeviceId{21}, {}, mir_pointer_button_primary});
1236+
1237+ auto device_state = mir::events::make_event(timestamp, mir_pointer_button_primary, mir_input_event_modifier_caps_lock,
1238+ cursor_x, cursor_y, std::move(states));
1239+
1240+ sender.send_event(*device_state, channel);
1241+ EXPECT_EQ(droidinput::OK, consumer.consume(&event_factory, true, std::chrono::nanoseconds(86), &seq, &event));
1242+ EXPECT_EQ(&client_raw_event, event);
1243+
1244+ auto dest_event = MirEvent::deserialize(client_raw_event.buffer);
1245+ ASSERT_THAT(mir_event_get_type(dest_event.get()), mir_event_type_input_device_state);
1246+
1247+ auto input_device_state = mir_event_get_input_device_state_event(dest_event.get());
1248+ EXPECT_THAT(mir_input_device_state_event_time(input_device_state), Eq(timestamp.count()));
1249+ EXPECT_THAT(mir_input_device_state_event_modifiers(input_device_state), Eq(mir_input_event_modifier_caps_lock));
1250+ EXPECT_THAT(mir_input_device_state_event_device_count(input_device_state), Eq(2));
1251+
1252+ EXPECT_THAT(mir_input_device_state_event_device_id(input_device_state, 0), Eq(MirInputDeviceId{23}));
1253+ EXPECT_THAT(mir_input_device_state_event_device_pressed_keys_count(input_device_state, 0), Eq(3));
1254+ EXPECT_THAT(mir_input_device_state_event_device_pressed_keys(input_device_state, 0)[0], Eq(50));
1255+ EXPECT_THAT(mir_input_device_state_event_device_pressed_keys(input_device_state, 0)[1], Eq(60));
1256+ EXPECT_THAT(mir_input_device_state_event_device_pressed_keys(input_device_state, 0)[2], Eq(80));
1257+ EXPECT_THAT(mir_input_device_state_event_device_pointer_buttons(input_device_state, 0), 0);
1258+
1259+ EXPECT_THAT(mir_input_device_state_event_device_id(input_device_state, 1), Eq(MirInputDeviceId{21}));
1260+ EXPECT_THAT(mir_input_device_state_event_device_pressed_keys_count(input_device_state, 1), Eq(0));
1261+ EXPECT_THAT(mir_input_device_state_event_device_pointer_buttons(input_device_state, 1), mir_pointer_button_primary);
1262+}
1263
1264=== modified file 'tests/unit-tests/input/evdev/test_libinput_device.cpp'
1265--- tests/unit-tests/input/evdev/test_libinput_device.cpp 2016-05-03 06:55:25 +0000
1266+++ tests/unit-tests/input/evdev/test_libinput_device.cpp 2016-07-06 21:48:16 +0000
1267@@ -30,7 +30,9 @@
1268 #include "mir/geometry/rectangle.h"
1269 #include "mir/test/event_matchers.h"
1270 #include "mir/test/doubles/mock_libinput.h"
1271+#include "mir/test/doubles/mock_input_seat.h"
1272 #include "mir/test/gmock_fixes.h"
1273+#include "mir/test/fake_shared.h"
1274 #include "mir/udev/wrapper.h"
1275 #include "mir/cookie/authority.h"
1276 #include "mir_test_framework/libinput_environment.h"
1277@@ -71,12 +73,15 @@
1278 MOCK_METHOD1(handle_input,void(MirEvent &));
1279 MOCK_METHOD1(confine_pointer, void(geom::Point&));
1280 MOCK_CONST_METHOD0(bounding_rectangle, geom::Rectangle());
1281+ MOCK_METHOD1(set_key_state, void(std::vector<uint32_t> const&));
1282+ MOCK_METHOD1(set_pointer_state, void(MirPointerButtons));
1283 };
1284
1285 struct MockEventBuilder : mi::EventBuilder
1286 {
1287 std::shared_ptr<mir::cookie::Authority> const cookie_authority = mir::cookie::Authority::create();
1288- mi::DefaultEventBuilder builder{MirInputDeviceId{3}, cookie_authority};
1289+ mtd::MockInputSeat seat;
1290+ mi::DefaultEventBuilder builder{MirInputDeviceId{3}, cookie_authority, mt::fake_shared(seat)};
1291 MockEventBuilder()
1292 {
1293 ON_CALL(*this, key_event(_,_,_,_))
1294@@ -119,6 +124,10 @@
1295 MOCK_METHOD7(pointer_event,
1296 mir::EventUPtr(Timestamp, MirPointerAction, MirPointerButtons, float, float, float, float));
1297 MOCK_METHOD2(configuration_event, mir::EventUPtr(Timestamp, MirInputConfigurationAction));
1298+ mir::EventUPtr device_state_event(float, float) override
1299+ {
1300+ return {nullptr,[](MirEvent*){}};
1301+ }
1302 };
1303
1304 struct LibInputDevice : public ::testing::Test
1305
1306=== modified file 'tests/unit-tests/input/test_nested_input_platform.cpp'
1307--- tests/unit-tests/input/test_nested_input_platform.cpp 2016-06-09 13:15:34 +0000
1308+++ tests/unit-tests/input/test_nested_input_platform.cpp 2016-07-06 21:48:16 +0000
1309@@ -31,6 +31,7 @@
1310
1311 #include "mir/test/doubles/mock_input_device_registry.h"
1312 #include "mir/test/doubles/mock_input_sink.h"
1313+#include "mir/test/doubles/mock_input_seat.h"
1314 #include "mir/test/doubles/stub_host_connection.h"
1315 #include "mir/test/fake_shared.h"
1316 #include "mir/test/event_matchers.h"
1317@@ -72,6 +73,7 @@
1318 {
1319 NiceMock<mtd::MockInputDeviceRegistry> mock_input_device_registry;
1320 NiceMock<MockHostConnection> mock_host_connection;
1321+ NiceMock<mtd::MockInputSeat> mock_seat;
1322 mgn::InputPlatform platform{mt::fake_shared(mock_host_connection), mt::fake_shared(mock_input_device_registry),
1323 mr::null_input_report()};
1324 mi::DeviceData a_keyboard{1, mir_input_device_capability_keyboard, "keys" , "keys-evdev2"};
1325@@ -141,7 +143,7 @@
1326 {
1327 auto nested_input_device = capture_input_device(a_mouse);
1328 NiceMock<mtd::MockInputSink> event_sink;
1329- mi::DefaultEventBuilder builder(MirInputDeviceId{12}, mir::cookie::Authority::create());
1330+ mi::DefaultEventBuilder builder(MirInputDeviceId{12}, mir::cookie::Authority::create(), mt::fake_shared(mock_seat));
1331
1332 ASSERT_THAT(nested_input_device, Ne(nullptr));
1333 nested_input_device->start(&event_sink, &builder);
1334@@ -165,7 +167,7 @@
1335 auto nested_input_device = capture_input_device(a_keyboard);
1336 auto const scan_code = 45;
1337 NiceMock<mtd::MockInputSink> event_sink;
1338- mi::DefaultEventBuilder builder(MirInputDeviceId{18}, mir::cookie::Authority::create());
1339+ mi::DefaultEventBuilder builder(MirInputDeviceId{18}, mir::cookie::Authority::create(), mt::fake_shared(mock_seat));
1340
1341 ASSERT_THAT(nested_input_device, Ne(nullptr));
1342 nested_input_device->start(&event_sink, &builder);
1343
1344=== modified file 'tests/unit-tests/input/test_seat_input_device_tracker.cpp'
1345--- tests/unit-tests/input/test_seat_input_device_tracker.cpp 2016-07-01 20:24:26 +0000
1346+++ tests/unit-tests/input/test_seat_input_device_tracker.cpp 2016-07-06 21:48:16 +0000
1347@@ -25,6 +25,8 @@
1348 #include "mir/test/doubles/mock_input_region.h"
1349 #include "mir/test/doubles/mock_cursor_listener.h"
1350 #include "mir/test/doubles/mock_touch_visualizer.h"
1351+#include "mir/test/doubles/mock_input_seat.h"
1352+#include "mir/test/doubles/advanceable_clock.h"
1353 #include "mir/test/event_matchers.h"
1354 #include "mir/test/fake_shared.h"
1355
1356@@ -53,17 +55,20 @@
1357 Nice<mtd::MockInputRegion> mock_region;
1358 Nice<mtd::MockCursorListener> mock_cursor_listener;
1359 Nice<mtd::MockTouchVisualizer> mock_visualizer;
1360+ Nice<mtd::MockInputSeat> mock_seat;
1361 MirInputDeviceId some_device{8712};
1362 MirInputDeviceId another_device{1246};
1363 MirInputDeviceId third_device{86};
1364 std::shared_ptr<mir::cookie::Authority> cookie_factory = mir::cookie::Authority::create();
1365+ mtd::AdvanceableClock clock;
1366
1367- mi::DefaultEventBuilder some_device_builder{some_device, cookie_factory};
1368- mi::DefaultEventBuilder another_device_builder{another_device, cookie_factory};
1369- mi::DefaultEventBuilder third_device_builder{third_device, cookie_factory};
1370+ mi::DefaultEventBuilder some_device_builder{some_device, cookie_factory, mt::fake_shared(mock_seat)};
1371+ mi::DefaultEventBuilder another_device_builder{another_device, cookie_factory, mt::fake_shared(mock_seat)};
1372+ mi::DefaultEventBuilder third_device_builder{third_device, cookie_factory, mt::fake_shared(mock_seat)};
1373 mi::receiver::XKBMapper mapper;
1374- mi::SeatInputDeviceTracker tracker{mt::fake_shared(mock_dispatcher), mt::fake_shared(mock_visualizer),
1375- mt::fake_shared(mock_cursor_listener), mt::fake_shared(mock_region), mt::fake_shared(mapper)};
1376+ mi::SeatInputDeviceTracker tracker{
1377+ mt::fake_shared(mock_dispatcher), mt::fake_shared(mock_visualizer), mt::fake_shared(mock_cursor_listener),
1378+ mt::fake_shared(mock_region), mt::fake_shared(mapper), mt::fake_shared(clock)};
1379
1380 std::chrono::nanoseconds arbitrary_timestamp;
1381 };
1382
1383=== modified file 'tests/unit-tests/input/test_x11_platform.cpp'
1384--- tests/unit-tests/input/test_x11_platform.cpp 2016-05-03 06:55:25 +0000
1385+++ tests/unit-tests/input/test_x11_platform.cpp 2016-07-06 21:48:16 +0000
1386@@ -28,6 +28,7 @@
1387 #include "mir_toolkit/event.h"
1388 #include "mir_toolkit/events/input/input_event.h"
1389 #include "mir/test/doubles/mock_input_sink.h"
1390+#include "mir/test/doubles/mock_input_seat.h"
1391 #include "mir/test/doubles/mock_input_device_registry.h"
1392 #include "mir/test/doubles/mock_x11.h"
1393 #include "mir/test/fake_shared.h"
1394@@ -48,9 +49,10 @@
1395 {
1396 NiceMock<mtd::MockInputSink> mock_pointer_sink;
1397 NiceMock<mtd::MockInputSink> mock_keyboard_sink;
1398+ NiceMock<mtd::MockInputSeat> mock_seat;
1399 NiceMock<mtd::MockX11> mock_x11;
1400 NiceMock<mtd::MockInputDeviceRegistry> mock_registry;
1401- mir::input::DefaultEventBuilder builder{0, mir::cookie::Authority::create()};
1402+ mir::input::DefaultEventBuilder builder{0, mir::cookie::Authority::create(), mt::fake_shared(mock_seat)};
1403
1404 mir::input::X::XInputPlatform x11_platform{
1405 mt::fake_shared(mock_registry),
1406
1407=== modified file 'tests/unit-tests/scene/test_abstract_shell.cpp'
1408--- tests/unit-tests/scene/test_abstract_shell.cpp 2016-06-20 17:10:33 +0000
1409+++ tests/unit-tests/scene/test_abstract_shell.cpp 2016-07-06 21:48:16 +0000
1410@@ -44,6 +44,7 @@
1411 #include "mir/test/doubles/mock_input_seat.h"
1412
1413 #include "mir/test/fake_shared.h"
1414+#include "mir/test/event_matchers.h"
1415
1416 #include <gmock/gmock.h>
1417 #include <gtest/gtest.h>
1418@@ -54,10 +55,12 @@
1419 namespace msh = mir::shell;
1420 namespace geom = mir::geometry;
1421 namespace mg = mir::graphics;
1422+namespace mev = mir::events;
1423
1424 namespace mt = mir::test;
1425 namespace mtd = mir::test::doubles;
1426 using namespace ::testing;
1427+using namespace std::chrono_literals;
1428
1429 namespace
1430 {
1431@@ -145,6 +148,13 @@
1432 .WillByDefault(Return(geom::Size{}));
1433 ON_CALL(surface_factory, create_surface(_,_))
1434 .WillByDefault(Return(mt::fake_shared(mock_surface)));
1435+ ON_CALL(seat, create_device_state())
1436+ .WillByDefault(Invoke(
1437+ []()
1438+ {
1439+ return mev::make_event(0ns, 0, mir_input_event_modifier_none, 0.0f, 0.0f,
1440+ std::vector<mev::InputDeviceState>());
1441+ }));
1442 }
1443
1444 std::chrono::nanoseconds const event_timestamp = std::chrono::nanoseconds(0);
1445@@ -603,3 +613,17 @@
1446
1447 focus_controller.raise(surfaces);
1448 }
1449+
1450+TEST_F(AbstractShell, as_focus_controller_emits_input_device_state_event_on_focus_change)
1451+{
1452+ EXPECT_CALL(mock_surface, consume(mt::InputDeviceStateEvent())).Times(1);
1453+
1454+ auto session = shell.open_session(__LINE__, "some", std::shared_ptr<mf::EventSink>());
1455+ auto creation_params = ms::a_surface()
1456+ .with_buffer_stream(session->create_buffer_stream(properties));
1457+ auto surface_id = shell.create_surface(session, creation_params, nullptr);
1458+ auto surface = session->surface(surface_id);
1459+
1460+ msh::FocusController& focus_controller = shell;
1461+ focus_controller.set_focus_to(session, surface);
1462+}

Subscribers

People subscribed via source and target branches