Mir

Merge lp:~andreas-pokorny/mir/libinput-platform-pointer-settings into lp:mir

Proposed by Andreas Pokorny
Status: Merged
Approved by: Andreas Pokorny
Approved revision: no longer in the source branch.
Merged at revision: 3037
Proposed branch: lp:~andreas-pokorny/mir/libinput-platform-pointer-settings
Merge into: lp:mir
Prerequisite: lp:~andreas-pokorny/mir/extended-mock-of-libinput
Diff against target: 653 lines (+352/-16)
14 files modified
include/client/mir_toolkit/mir_input_device.h (+39/-0)
include/platform/mir/input/input_device.h (+8/-0)
include/platform/mir/input/pointer_settings.h (+58/-0)
src/platforms/evdev/input_modifier_utils.cpp (+7/-3)
src/platforms/evdev/input_modifier_utils.h (+2/-1)
src/platforms/evdev/libinput_device.cpp (+36/-3)
src/platforms/evdev/libinput_device.h (+4/-0)
src/platforms/mesa/server/x11/input/input_device.cpp (+18/-1)
src/platforms/mesa/server/x11/input/input_device.h (+4/-0)
tests/include/mir/test/gmock_fixes.h (+23/-0)
tests/mir_test_framework/fake_input_device_impl.cpp (+30/-4)
tests/mir_test_framework/fake_input_device_impl.h (+5/-0)
tests/unit-tests/input/evdev/test_libinput_device.cpp (+115/-4)
tests/unit-tests/input/test_default_input_device_hub.cpp (+3/-0)
To merge this branch: bzr merge lp:~andreas-pokorny/mir/libinput-platform-pointer-settings
Reviewer Review Type Date Requested Status
PS Jenkins bot (community) continuous-integration Approve
Chris Halse Rogers Approve
Alan Griffiths Approve
Alexandros Frantzis (community) Abstain
Daniel van Vugt Abstain
Andreas Pokorny (community) Abstain
Review via email: mp+272501@code.launchpad.net

Commit message

Pointer settings in libinput

Allows configuring cursor acceleration, scroll speed and left-hand/right-hand button ordering for all pointing devices.

Description of the change

Add pointer settings to libinput platform.

Pointer settings allow configuring pointer and scroll speed and right-hand / left-hand button ordering. These settings apply to all pointing devices..

Still to come:
 - touchpad settings
 - keyboard settings
 - Exposing settings through mir::input::Device
 - supporting settings in x platform
 - supporting settings in stub input platforme

To post a comment you must log in.
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: Approve (continuous-integration)
Revision history for this message
Alexandros Frantzis (afrantzis) wrote :

+ virtual UniqueModulePtr<PointerSettings> get_pointer_settings() const = 0;

Why do we want PointerSettings to keep the module alive?
I would expect just:

PointerSettings get_pointer_settings() const = 0

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

> + virtual UniqueModulePtr<PointerSettings> get_pointer_settings() const = 0;
>
> Why do we want PointerSettings to keep the module alive?

+1

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

duplication is because I can only have one prereq branch..

Now looking at that again.. I used the additional nullptr state to indicate that the group of options is not applicable for the device. Initially I thought about not allowing callers to construct their own settings objects. And about turning it into a base class .. but I abandoned those two ideas..

I might also go with optioal<PointerSettings> instead.

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
Revision history for this message
Andreas Pokorny (andreas-pokorny) wrote :

... or I might use unique_ptr instead, and then do not have to bump the input platform abi when adding properties to the structure. And there we are again: Now I have to make sure that the library outlives the lifetime of the structure since it is the only one that knows how to delete the added values.

So in the end using UniqueModulePtr was a partial solution to ABI changes (it only ensures old mirserver works with new input library not the other way around)...

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

yeah.. this needs fixing

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

ok fine now..

[side note:
I had to improve the interface of optional_value (but still not quite happy with its behavior and implementation)]

review: Abstain
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
Alan Griffiths (alan-griffiths) wrote :

+ constexpr explicit operator bool() const { return is_set_; }
+ constexpr const T* operator->() const { return &value_; }
+ T* operator->() { return &value_; }
+ constexpr const T& operator*() const { return value_; }
+ T& operator*() { return value_; }

This seems to add a bunch of operators to give different syntax and surprisingly different semantics to the existing interface. Why?

E.g. why do we need operator->()? And why isn't it a synonym for &value()?

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

> + constexpr explicit operator bool() const { return is_set_; }
> + constexpr const T* operator->() const { return &value_; }
> + T* operator->() { return &value_; }
> + constexpr const T& operator*() const { return value_; }
> + T& operator*() { return value_; }
>
> This seems to add a bunch of operators to give different syntax and
> surprisingly different semantics to the existing interface. Why?
>
> E.g. why do we need operator->()? And why isn't it a synonym for &value()?

To be closer to std::(experimental::)optional. Looking at how we implemented it, I should change the above to be more in line with what mir::optional_value<...>::value() does. Fixing that.

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
Alan Griffiths (alan-griffiths) wrote :

> To be closer to std::(experimental::)optional. Looking at how we implemented

mir optional_value is a different design to std::(experimental::)optional - making them look more alike is probably a bad idea.

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

> > To be closer to std::(experimental::)optional. Looking at how we implemented
>
> mir optional_value is a different design to std::(experimental::)optional -
> making them look more alike is probably a bad idea.

Ok the difference between value() and -> in this proposal is odd. I will revert it to the original and update the usage for now.

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
Alan Griffiths (alan-griffiths) wrote :

/mir/include/common/mir/optional_value.h:31:45: error: no viable conversion from 'const mir::input::PointerSettings' to 'MirPointerButton'
    optional_value(T const& value) : value_{value}, is_set_{true} {}

+ PointerSettings() {}

"Otherwise clang does not allow construction with {}"

I'm confused. We're in the optional_value<PointerSettings> converting constructor, are trying to construct a MirPointerButton(!) and this is solved by giving PointerSettings() a user-defined default constructor?
...
Oh! clang is trying to use aggregate initialization and that is defeated by adding any user-defined constructor.

review: Approve
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
Revision history for this message
Daniel van Vugt (vanvugt) wrote :

(1) It sounds like we're mixing up the terms "speed" (magnitude of velocity) and "acceleration". Acceleration is the rate of change of velocity. However it appears actual acceleration might be always zero, and 'acceleration' here refers to the velocity? Have we confused our physics terminology? If so, that should be cleared up...

(2) So how long before we can declare bug 124440 fixed? :)

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

> (1) It sounds like we're mixing up the terms "speed" (magnitude of velocity)
> and "acceleration". Acceleration is the rate of change of velocity. However it
> appears actual acceleration might be always zero, and 'acceleration' here
> refers to the velocity? Have we confused our physics terminology? If so, that
> should be cleared up...

Yes kind of .. this is an physical inaccuracy that leaks into the software from the domain model. Naming it acceleration would be incorrect to. Since the cursor speed is actually a scaling of the acceleration curve - which is a curve providing the actual speed scale based on the amount of recent movement. Where recent movement is the relative steps we were able to observe from the device.

I could offer a similar confusing comment to clarify things.

>
> (2) So how long before we can declare bug 124440 fixed? :)

Oh I didn’t realize.. Soon this is one of the values that is planed to be configurable by the initial pocket desktop ui.

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

Kay.... try to use "velocity" or "speed" if you're referring to the first derivative of position :)

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

> > (1) It sounds like we're mixing up the terms "speed" (magnitude of velocity)
> > and "acceleration". Acceleration is the rate of change of velocity. However
> it
> > appears actual acceleration might be always zero, and 'acceleration' here
> > refers to the velocity? Have we confused our physics terminology? If so,
> that
> > should be cleared up...
>
> Yes kind of .. this is an physical inaccuracy that leaks into the software
> from the domain model. Naming it acceleration would be incorrect to. Since the
> cursor speed is actually a scaling of the acceleration curve - which is a
> curve providing the actual speed scale based on the amount of recent movement.
> Where recent movement is the relative steps we were able to observe from the
> device.
>
> I could offer a similar confusing comment to clarify things.

This sounds like a number, not a speed or acceleration. Let's try for clearer terminology.

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

Paraphrasing in the hope of confirming (or refuting) my understanding:

"cursor accelaration" is scaling of the first derivative of cursor position (and neither a speed nor an acceleration).

The "acceleration curve" is a function providing this scaling.

PointerSettings::cursor_speed is an adjustment[1] to this scaling function (and not a speed nor an acceleration).

Would it be better to use a term like "speed coefficient" than mixing "acceleration" and "speed"?

[1] Looking at the fake code it is just added to 1 to get the scale factor? If that isn't just an example, wouldn't [0.2] be more intuitive than [-1,1]?

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

> Paraphrasing in the hope of confirming (or refuting) my understanding:
>
> "cursor accelaration" is scaling of the first derivative of cursor position
> (and neither a speed nor an acceleration).
>
> The "acceleration curve" is a function providing this scaling.
>
> PointerSettings::cursor_speed is an adjustment[1] to this scaling function
> (and not a speed nor an acceleration).
>
> Would it be better to use a term like "speed coefficient" than mixing
> "acceleration" and "speed"?

coefficient also implies a linear relation.. What about just calling it 'acceleration curve'?
The default set of curves looks like this:
http://wayland.freedesktop.org/libinput/doc/latest/ptraccel-linear.svg

Afaik other pointing devices get different curve sets...

> [1] Looking at the fake code it is just added to 1 to get the scale factor? If
> that isn't just an example, wouldn't [0.2] be more intuitive than [-1,1]?

Since I wanted to use the acceleration offered by libinput, and since it only provides a weakly defined setting called 'acceleration speed', I decided for this MP that I use the value to affect the positioning of fake pointers, but in a simpler way - not depending on previous events. Also the range is what libinput uses. We could also just have [0,1], and scale it as needed in libinput..

Revision history for this message
Alexandros Frantzis (afrantzis) wrote :

Unfortunately the historical terms used to describe how mouse movement translates to cursor movement are confusing.

What is called "speed" is actually just distance scaling (e.g. 1 cm of mouse movement => N pixels of cursors movement), and what is called "acceleration" is just changing the scaling dynamically depending on (real) mouse speed.

Not sure what the best term would be, but perhaps it would be better to stick to the historical terms for reasons of familiarity.

+ [-1, 0[

Usually written as [-1, 0)

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

+ /**
+ * Scale cursor accelaration.
+ * - 0: default acceleration
+ * - [-1, 0[: reduced acceleration
+ * - ]0, 1]: increased acceleration
+ */
+ double cursor_speed{0.0};
+ double horizontal_scroll_speed{1.0};
+ double vertical_scroll_speed{1.0};

/1/ I don't think this actually follows the terminology explained in the comments.
/2/ "accelaration" => "acceleration"
/3/ Is the doc comment intended to apply to all three fields? (It only applies to the first.)

So, as I understand the explanation...

    /**
     * Bias cursor acceleration:
     * - [-1, 0): reduced acceleration
     * - 0: default acceleration
     * - (0, 1]: increased acceleration
     */
    double bias_cursor_acceleration{0.0};

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

It would be more consistent with "horizontal_scroll_scale" to have "cursor_acceleration_bias", but these names do fit better with the explanation of "terms of art".

review: Approve
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
Andreas Pokorny (andreas-pokorny) wrote :

[1444835234.581027] mirserver: Stopping
/bin/bash: line 1: 6450 Segmentation fault mir_demo_server --test-client /usr/bin/mir_demo_client_basic

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)
Revision history for this message
Andreas Pokorny (andreas-pokorny) wrote :

Resolving s-jenkins.ubuntu-ci (s-jenkins.ubuntu-ci)... 10.100.0.4
Connecting to s-jenkins.ubuntu-ci (s-jenkins.ubuntu-ci)|10.100.0.4|:8080... connected.
HTTP request sent, awaiting response... 500 Internal Server Error
2015-10-14 18:13:32 ERROR 500: Internal Server Error.

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
Revision history for this message
Chris Halse Rogers (raof) wrote :

+ /**
+ * Configure left and right handed mode by selecting a primary button
+ * - mir_pointer_button_primary -> right handed
+ * - mir_pointer_button_secondary -> left handed
+ */
+ MirPointerButton primary_button{mir_pointer_button_primary};

Non-blocking: I think this would be better as an explicit mir_pointer_left_handed/mir_pointer_right_handed - in the case of those truly monstrous 112-button mice we might reasonably want to be able to switch more than just left-mouse-button and right-mouse-button.

Feel free to fix that, or not.

review: Approve
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: Approve (continuous-integration)

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== added file 'include/client/mir_toolkit/mir_input_device.h'
2--- include/client/mir_toolkit/mir_input_device.h 1970-01-01 00:00:00 +0000
3+++ include/client/mir_toolkit/mir_input_device.h 2015-10-19 10:46:25 +0000
4@@ -0,0 +1,39 @@
5+/*
6+ * Copyright © 2015 Canonical Ltd.
7+ *
8+ * This program is free software: you can redistribute it and/or modify it
9+ * under the terms of the GNU Lesser General Public License version 3,
10+ * as published by the Free Software Foundation.
11+ *
12+ * This program is distributed in the hope that it will be useful,
13+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
14+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15+ * GNU Lesser General Public License for more details.
16+ *
17+ * You should have received a copy of the GNU Lesser General Public License
18+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
19+ *
20+ */
21+
22+#ifndef MIR_TOOLKIT_MIR_INPUT_DEVICE_H_
23+#define MIR_TOOLKIT_MIR_INPUT_DEVICE_H_
24+
25+/**
26+ * \addtogroup mir_toolkit
27+ * @{
28+ */
29+#ifdef __cplusplus
30+extern "C" {
31+#endif
32+
33+typedef enum MirPointerHandedness
34+{
35+ mir_pointer_handedness_right = 0,
36+ mir_pointer_handedness_left = 1
37+} MirPointerHandedness;
38+
39+#ifdef __cplusplus
40+}
41+#endif
42+
43+#endif
44
45=== modified file 'include/platform/mir/input/input_device.h'
46--- include/platform/mir/input/input_device.h 2015-09-01 07:41:29 +0000
47+++ include/platform/mir/input/input_device.h 2015-10-19 10:46:25 +0000
48@@ -20,6 +20,9 @@
49 #ifndef MIR_INPUT_INPUT_DEVICE_H_
50 #define MIR_INPUT_INPUT_DEVICE_H_
51
52+#include "mir/module_deleter.h"
53+#include "mir/optional_value.h"
54+
55 #include <memory>
56
57 namespace mir
58@@ -34,6 +37,8 @@
59 class InputDeviceInfo;
60 class EventBuilder;
61
62+class PointerSettings;
63+
64 /**
65 * Represents an input device.
66 */
67@@ -54,6 +59,9 @@
68
69 virtual InputDeviceInfo get_device_info() = 0;
70
71+ virtual mir::optional_value<PointerSettings> get_pointer_settings() const = 0;
72+ virtual void apply_settings(PointerSettings const&) = 0;
73+
74 protected:
75 InputDevice(InputDevice const&) = delete;
76 InputDevice& operator=(InputDevice const&) = delete;
77
78=== added file 'include/platform/mir/input/pointer_settings.h'
79--- include/platform/mir/input/pointer_settings.h 1970-01-01 00:00:00 +0000
80+++ include/platform/mir/input/pointer_settings.h 2015-10-19 10:46:25 +0000
81@@ -0,0 +1,58 @@
82+/*
83+ * Copyright © 2015 Canonical Ltd.
84+ *
85+ * This program is free software: you can redistribute it and/or modify it
86+ * under the terms of the GNU Lesser General Public License version 3,
87+ * as published by the Free Software Foundation.
88+ *
89+ * This program is distributed in the hope that it will be useful,
90+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
91+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
92+ * GNU Lesser General Public License for more details.
93+ *
94+ * You should have received a copy of the GNU Lesser General Public License
95+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
96+ *
97+ * Authored by:
98+ * Andreas Pokorny <andreas.pokorny@canonical.com>
99+ */
100+
101+#ifndef MIR_INPUT_POINTER_SETTINGS_H_
102+#define MIR_INPUT_POINTER_SETTINGS_H_
103+
104+#include "mir_toolkit/client_types.h"
105+#include "mir_toolkit/mir_input_device.h"
106+
107+namespace mir
108+{
109+namespace input
110+{
111+
112+struct PointerSettings
113+{
114+ PointerSettings() {}
115+ /**
116+ * Configure left and right handed mode by selecting a primary button
117+ */
118+ MirPointerHandedness handedness{mir_pointer_handedness_right};
119+ /**
120+ * Bias cursor acceleration.
121+ * - [-1, 0): reduced acceleration
122+ * - 0: default acceleration
123+ * - (0, 1]: increased acceleration
124+ */
125+ double cursor_acceleration_bias{0.0};
126+ /**
127+ * Scale horizontal scrolling linearly
128+ */
129+ double horizontal_scroll_scale{1.0};
130+ /**
131+ * Scale vertical scrolling linearly
132+ */
133+ double vertical_scroll_scale{1.0};
134+};
135+
136+}
137+}
138+
139+#endif
140
141=== modified file 'src/platforms/evdev/input_modifier_utils.cpp'
142--- src/platforms/evdev/input_modifier_utils.cpp 2015-09-17 06:40:14 +0000
143+++ src/platforms/evdev/input_modifier_utils.cpp 2015-10-19 10:46:25 +0000
144@@ -27,12 +27,16 @@
145
146 namespace mie = mir::input::evdev;
147
148-MirPointerButton mie::to_pointer_button(int button)
149+MirPointerButton mie::to_pointer_button(int button, MirPointerHandedness handedness)
150 {
151 switch(button)
152 {
153- case BTN_LEFT: return mir_pointer_button_primary;
154- case BTN_RIGHT: return mir_pointer_button_secondary;
155+ case BTN_LEFT: return (handedness == mir_pointer_handedness_right)
156+ ? mir_pointer_button_primary
157+ : mir_pointer_button_secondary;
158+ case BTN_RIGHT: return (handedness == mir_pointer_handedness_right)
159+ ? mir_pointer_button_secondary
160+ : mir_pointer_button_primary;
161 case BTN_MIDDLE: return mir_pointer_button_tertiary;
162 case BTN_BACK: return mir_pointer_button_back;
163 case BTN_FORWARD: return mir_pointer_button_forward;
164
165=== modified file 'src/platforms/evdev/input_modifier_utils.h'
166--- src/platforms/evdev/input_modifier_utils.h 2015-09-17 06:40:14 +0000
167+++ src/platforms/evdev/input_modifier_utils.h 2015-10-19 10:46:25 +0000
168@@ -20,6 +20,7 @@
169 #define MIR_INPUT_EVDEV_INPUT_MODIFIER_UTILS_H_
170
171 #include "mir_toolkit/event.h"
172+#include "mir_toolkit/mir_input_device.h"
173
174 namespace mir
175 {
176@@ -27,7 +28,7 @@
177 {
178 namespace evdev
179 {
180-MirPointerButton to_pointer_button(int button);
181+MirPointerButton to_pointer_button(int button, MirPointerHandedness handedness);
182 MirInputEventModifiers to_modifiers(int32_t scan_code);
183 MirInputEventModifiers expand_modifiers(MirInputEventModifiers modifiers);
184 }
185
186=== modified file 'src/platforms/evdev/libinput_device.cpp'
187--- src/platforms/evdev/libinput_device.cpp 2015-10-07 15:32:10 +0000
188+++ src/platforms/evdev/libinput_device.cpp 2015-10-19 10:46:25 +0000
189@@ -25,6 +25,7 @@
190 #include "mir/input/input_sink.h"
191 #include "mir/input/input_report.h"
192 #include "mir/input/device_capability.h"
193+#include "mir/input/pointer_settings.h"
194 #include "mir/input/input_device_info.h"
195 #include "mir/events/event_builders.h"
196 #include "mir/geometry/displacement.h"
197@@ -159,7 +160,8 @@
198 auto const action = (libinput_event_pointer_get_button_state(pointer) == LIBINPUT_BUTTON_STATE_PRESSED)?
199 mir_pointer_action_button_down : mir_pointer_action_button_up;
200
201- auto const pointer_button = mie::to_pointer_button(button);
202+ auto const do_not_swap_buttons = mir_pointer_handedness_right;
203+ auto const pointer_button = mie::to_pointer_button(button, do_not_swap_buttons);
204 auto const relative_x_value = 0.0f;
205 auto const relative_y_value = 0.0f;
206 auto const hscroll_value = 0.0f;
207@@ -232,10 +234,12 @@
208 auto const relative_x_value = 0.0f;
209 auto const relative_y_value = 0.0f;
210 auto const hscroll_value = libinput_event_pointer_has_axis(pointer, LIBINPUT_POINTER_AXIS_SCROLL_HORIZONTAL)
211- ? libinput_event_pointer_get_axis_value(pointer, LIBINPUT_POINTER_AXIS_SCROLL_HORIZONTAL)
212+ ? horizontal_scroll_scale * libinput_event_pointer_get_axis_value(pointer,
213+ LIBINPUT_POINTER_AXIS_SCROLL_HORIZONTAL)
214 : 0.0f;
215 auto const vscroll_value = libinput_event_pointer_has_axis(pointer, LIBINPUT_POINTER_AXIS_SCROLL_VERTICAL)
216- ? libinput_event_pointer_get_axis_value(pointer, LIBINPUT_POINTER_AXIS_SCROLL_VERTICAL)
217+ ? vertical_scroll_scale * libinput_event_pointer_get_axis_value(pointer,
218+ LIBINPUT_POINTER_AXIS_SCROLL_VERTICAL)
219 : 0.0f;
220
221 report->received_event_from_kernel(time.count(), EV_REL, 0, 0);
222@@ -360,3 +364,32 @@
223 {
224 return devices.front().get();
225 }
226+
227+mir::optional_value<mi::PointerSettings> mie::LibInputDevice::get_pointer_settings() const
228+{
229+ if (!contains(info.capabilities, mi::DeviceCapability::pointer))
230+ return {};
231+
232+ auto dev = device();
233+ auto accel_bias = libinput_device_config_accel_get_speed(dev);
234+ auto left_handed = (libinput_device_config_left_handed_get(dev) == 1);
235+
236+ mi::PointerSettings settings;
237+ settings.cursor_acceleration_bias = accel_bias;
238+ settings.vertical_scroll_scale = vertical_scroll_scale;
239+ settings.horizontal_scroll_scale = horizontal_scroll_scale;
240+ settings.handedness = left_handed? mir_pointer_handedness_left : mir_pointer_handedness_right;
241+ return settings;
242+}
243+
244+void mie::LibInputDevice::apply_settings(mir::input::PointerSettings const& settings)
245+{
246+ if (!contains(info.capabilities, mi::DeviceCapability::pointer))
247+ return;
248+
249+ auto dev = device();
250+ libinput_device_config_accel_set_speed(dev, settings.cursor_acceleration_bias);
251+ libinput_device_config_left_handed_set(dev, mir_pointer_handedness_left == settings.handedness);
252+ vertical_scroll_scale = settings.vertical_scroll_scale;
253+ horizontal_scroll_scale = settings.horizontal_scroll_scale;
254+}
255
256=== modified file 'src/platforms/evdev/libinput_device.h'
257--- src/platforms/evdev/libinput_device.h 2015-10-07 15:32:10 +0000
258+++ src/platforms/evdev/libinput_device.h 2015-10-19 10:46:25 +0000
259@@ -54,6 +54,8 @@
260 void start(InputSink* sink, EventBuilder* builder) override;
261 void stop() override;
262 InputDeviceInfo get_device_info() override;
263+ mir::optional_value<PointerSettings> get_pointer_settings() const override;
264+ void apply_settings(PointerSettings const&) override;
265
266 void process_event(libinput_event* event);
267 ::libinput_device* device() const;
268@@ -86,6 +88,8 @@
269 mir::geometry::Point pointer_pos;
270 MirInputEventModifiers modifier_state;
271 MirPointerButtons button_state;
272+ double vertical_scroll_scale{1.0};
273+ double horizontal_scroll_scale{1.0};
274
275 struct ContactData
276 {
277
278=== modified file 'src/platforms/mesa/server/x11/input/input_device.cpp'
279--- src/platforms/mesa/server/x11/input/input_device.cpp 2015-09-01 07:41:29 +0000
280+++ src/platforms/mesa/server/x11/input/input_device.cpp 2015-10-19 10:46:25 +0000
281@@ -16,8 +16,11 @@
282 * Authored by: Cemil Azizoglu <cemil.azizoglu@canonical.com>
283 */
284
285+#include "input_device.h"
286+
287+#include "mir/input/pointer_settings.h"
288 #include "mir/input/input_device_info.h"
289-#include "input_device.h"
290+#include "mir/input/device_capability.h"
291
292 namespace mi = mir::input;
293 namespace mix = mi::X;
294@@ -43,3 +46,17 @@
295 {
296 return info;
297 }
298+
299+mir::optional_value<mi::PointerSettings> mix::XInputDevice::get_pointer_settings() const
300+{
301+ mir::optional_value<PointerSettings> ret;
302+ if (contains(info.capabilities, DeviceCapability::pointer))
303+ ret = PointerSettings();
304+
305+ return ret;
306+}
307+
308+void mix::XInputDevice::apply_settings(PointerSettings const&)
309+{
310+ // TODO Make use if X11-XInput2
311+}
312
313=== modified file 'src/platforms/mesa/server/x11/input/input_device.h'
314--- src/platforms/mesa/server/x11/input/input_device.h 2015-09-01 07:41:29 +0000
315+++ src/platforms/mesa/server/x11/input/input_device.h 2015-10-19 10:46:25 +0000
316@@ -21,6 +21,7 @@
317
318 #include "mir/input/input_device.h"
319 #include "mir/input/input_device_info.h"
320+#include "mir/optional_value.h"
321
322 namespace mir
323 {
324@@ -40,6 +41,9 @@
325 void stop() override;
326 InputDeviceInfo get_device_info() override;
327
328+ mir::optional_value<PointerSettings> get_pointer_settings() const override;
329+ void apply_settings(PointerSettings const& settings) override;
330+
331 InputSink* sink{nullptr};
332 EventBuilder* builder{nullptr};
333 private:
334
335=== modified file 'tests/include/mir/test/gmock_fixes.h'
336--- tests/include/mir/test/gmock_fixes.h 2015-08-27 05:59:27 +0000
337+++ tests/include/mir/test/gmock_fixes.h 2015-10-19 10:46:25 +0000
338@@ -142,6 +142,29 @@
339 }
340 };
341
342+template<typename T, typename D>
343+class DefaultValue<std::unique_ptr<T, D>> {
344+ public:
345+ // Unsets the default value for type T.
346+ static void Clear() {}
347+
348+ // Returns true if the user has set the default value for type T.
349+ static bool IsSet() { return false; }
350+
351+ // Returns true if T has a default return value set by the user or there
352+ // exists a built-in default value.
353+ static bool Exists() {
354+ return true;
355+ }
356+
357+ // Returns the default value for type T if the user has set one;
358+ // otherwise returns the built-in default value if there is one;
359+ // otherwise aborts the process.
360+ static std::unique_ptr<T, D> Get() {
361+ return std::unique_ptr<T, D>();
362+ }
363+};
364+
365
366
367 }
368
369=== modified file 'tests/mir_test_framework/fake_input_device_impl.cpp'
370--- tests/mir_test_framework/fake_input_device_impl.cpp 2015-10-12 08:08:58 +0000
371+++ tests/mir_test_framework/fake_input_device_impl.cpp 2015-10-19 10:46:25 +0000
372@@ -22,9 +22,11 @@
373 #include "mir/input/input_device.h"
374 #include "mir/input/input_device_info.h"
375 #include "mir/input/input_sink.h"
376+#include "mir/input/pointer_settings.h"
377 #include "mir/input/event_builder.h"
378 #include "mir/dispatch/action_queue.h"
379 #include "mir/geometry/displacement.h"
380+#include "mir/module_deleter.h"
381 #include "src/platforms/evdev/input_modifier_utils.h"
382
383 #include "boost/throw_exception.hpp"
384@@ -117,7 +119,7 @@
385 {
386 auto event_time = std::chrono::duration_cast<std::chrono::nanoseconds>(
387 std::chrono::system_clock::now().time_since_epoch());
388- auto action = update_buttons(button.action, mie::to_pointer_button(button.button));
389+ auto action = update_buttons(button.action, mie::to_pointer_button(button.button, settings.handedness));
390 auto event_modifiers = mie::expand_modifiers(modifiers);
391 auto button_event = builder->pointer_event(event_time,
392 event_modifiers,
393@@ -157,7 +159,14 @@
394 auto event_time = std::chrono::duration_cast<std::chrono::nanoseconds>(
395 std::chrono::system_clock::now().time_since_epoch());
396 auto event_modifiers = mie::expand_modifiers(modifiers);
397- update_position(pointer.rel_x, pointer.rel_y);
398+ // constant scaling is used here to simplify checking for the
399+ // expected results. Default settings of the device lead to no
400+ // scaling at all.
401+ auto acceleration = (settings.cursor_acceleration_bias + 1.0);
402+ auto rel_x = pointer.rel_x * acceleration;
403+ auto rel_y = pointer.rel_y * acceleration;
404+
405+ update_position(rel_x, rel_y);
406 auto pointer_event = builder->pointer_event(event_time,
407 event_modifiers,
408 mir_pointer_action_motion,
409@@ -166,8 +175,8 @@
410 pos.y.as_float(),
411 scroll.x.as_float(),
412 scroll.y.as_float(),
413- pointer.rel_x,
414- pointer.rel_y);
415+ rel_x,
416+ rel_y);
417
418 sink->handle_input(*pointer_event);
419 }
420@@ -220,6 +229,23 @@
421 sink->handle_input(*touch_event);
422 }
423
424+mir::optional_value<mi::PointerSettings> mtf::FakeInputDeviceImpl::InputDevice::get_pointer_settings() const
425+{
426+ mir::optional_value<mi::PointerSettings> ret;
427+ if (!contains(info.capabilities, mi::DeviceCapability::pointer))
428+ return ret;
429+
430+ ret = mi::PointerSettings();
431+ return ret;
432+}
433+
434+void mtf::FakeInputDeviceImpl::InputDevice::apply_settings(mi::PointerSettings const& settings)
435+{
436+ if (!contains(info.capabilities, mi::DeviceCapability::pointer))
437+ return;
438+ this->settings = settings;
439+}
440+
441 void mtf::FakeInputDeviceImpl::InputDevice::map_touch_coordinates(float& x, float& y)
442 {
443 // TODO take orientation of input sink into account?
444
445=== modified file 'tests/mir_test_framework/fake_input_device_impl.h'
446--- tests/mir_test_framework/fake_input_device_impl.h 2015-09-01 07:41:29 +0000
447+++ tests/mir_test_framework/fake_input_device_impl.h 2015-10-19 10:46:25 +0000
448@@ -22,6 +22,7 @@
449 #include "mir_test_framework/fake_input_device.h"
450
451 #include "mir/input/input_device.h"
452+#include "mir/input/pointer_settings.h"
453 #include "mir/input/input_device_info.h"
454 #include "mir/geometry/point.h"
455
456@@ -64,6 +65,9 @@
457 return info;
458 }
459
460+ mir::optional_value<mir::input::PointerSettings> get_pointer_settings() const override;
461+ void apply_settings(mir::input::PointerSettings const& settings) override;
462+
463 private:
464 MirPointerAction update_buttons(synthesis::EventAction action, MirPointerButton button);
465 void update_position(int rel_x, int rel_y);
466@@ -76,6 +80,7 @@
467 uint32_t modifiers{0};
468 mir::geometry::Point pos, scroll;
469 MirPointerButtons buttons;
470+ mir::input::PointerSettings settings;
471 };
472 std::shared_ptr<mir::dispatch::ActionQueue> queue;
473 std::shared_ptr<InputDevice> device;
474
475=== modified file 'tests/unit-tests/input/evdev/test_libinput_device.cpp'
476--- tests/unit-tests/input/evdev/test_libinput_device.cpp 2015-10-07 16:41:50 +0000
477+++ tests/unit-tests/input/evdev/test_libinput_device.cpp 2015-10-19 10:46:25 +0000
478@@ -22,6 +22,7 @@
479
480 #include "mir/input/input_device_registry.h"
481 #include "mir/input/input_sink.h"
482+#include "mir/input/pointer_settings.h"
483 #include "mir/geometry/point.h"
484 #include "mir/geometry/rectangle.h"
485 #include "mir/test/event_matchers.h"
486@@ -159,12 +160,12 @@
487 mock_libinput.setup_device(fake_input, dev, device_path, umock_name, vendor_id, product_id);
488 }
489
490- void setup_pointer_configuration(libinput_device* dev, double accel_speed, MirPointerButton primary)
491+ void setup_pointer_configuration(libinput_device* dev, double accel_speed, MirPointerHandedness handedness)
492 {
493 EXPECT_CALL(mock_libinput, libinput_device_config_accel_get_speed(dev))
494 .WillRepeatedly(Return(accel_speed));
495 EXPECT_CALL(mock_libinput, libinput_device_config_left_handed_get(dev))
496- .WillRepeatedly(Return(primary == mir_pointer_button_secondary));
497+ .WillRepeatedly(Return(handedness == mir_pointer_handedness_left));
498 }
499
500 void setup_key_event(libinput_event* event, uint64_t event_time, uint32_t key, libinput_key_state state)
501@@ -318,7 +319,7 @@
502 std::shared_ptr<libinput> lib = mie::make_libinput();
503 char const* second_dev = "/dev/input/event13";
504 char const* second_umock_dev_name = "bluetooth-magic-trackpad";
505-
506+
507 setup_device(second_fake_device, second_dev, second_umock_dev_name, 9663, 1234);
508
509 InSequence seq;
510@@ -341,7 +342,7 @@
511 std::shared_ptr<libinput> lib = mie::make_libinput();
512 char const* second_dev = "/dev/input/event13";
513 char const* second_umock_dev_name = "bluetooth-magic-trackpad";
514-
515+
516 setup_device(second_fake_device, second_dev, second_umock_dev_name, 9663, 1234);
517
518 mie::LibInputDevice dev(mir::report::null_input_report(),
519@@ -595,3 +596,113 @@
520 dev.process_event(fake_event_3);
521 dev.process_event(fake_event_4);
522 }
523+
524+TEST_F(LibInputDevice, provides_no_pointer_settings_for_non_pointing_devices)
525+{
526+ char const keyboard_name[] = "usb-keyboard";
527+ char const keyboard_device_path[] = "/dev/input/event14";
528+ setup_device(second_fake_device, keyboard_device_path, keyboard_name, 1231, 4124);
529+
530+ std::shared_ptr<libinput> lib = mie::make_libinput();
531+ mie::LibInputDevice dev(mir::report::null_input_report(), keyboard_device_path, mie::make_libinput_device(lib.get(), keyboard_device_path));
532+
533+ auto ptr = dev.get_pointer_settings();
534+ EXPECT_THAT(ptr.is_set(), Eq(false));
535+}
536+
537+TEST_F(LibInputDevice, reads_pointer_settings_from_libinput)
538+{
539+ char const mouse_device_path[] = "/dev/input/event13";
540+ char const mouse_name[] = "usb-mouse";
541+ setup_device(second_fake_device, mouse_device_path, mouse_name, 1231, 4124);
542+
543+ std::shared_ptr<libinput> lib = mie::make_libinput();
544+ mie::LibInputDevice dev(mir::report::null_input_report(), mouse_device_path, mie::make_libinput_device(lib.get(), mouse_device_path));
545+
546+ setup_pointer_configuration(dev.device(), 1, mir_pointer_handedness_right);
547+ auto optional_settings = dev.get_pointer_settings();
548+
549+ EXPECT_THAT(optional_settings.is_set(), Eq(true));
550+
551+ auto ptr_settings = optional_settings.value();
552+ EXPECT_THAT(ptr_settings.handedness, Eq(mir_pointer_handedness_right));
553+ EXPECT_THAT(ptr_settings.cursor_acceleration_bias, Eq(1.0));
554+ EXPECT_THAT(ptr_settings.horizontal_scroll_scale, Eq(1.0));
555+ EXPECT_THAT(ptr_settings.vertical_scroll_scale, Eq(1.0));
556+
557+ setup_pointer_configuration(dev.device(), 0.0, mir_pointer_handedness_left);
558+ optional_settings = dev.get_pointer_settings();
559+
560+ EXPECT_THAT(optional_settings.is_set(), Eq(true));
561+
562+ ptr_settings = optional_settings.value();
563+ EXPECT_THAT(ptr_settings.handedness, Eq(mir_pointer_handedness_left));
564+ EXPECT_THAT(ptr_settings.cursor_acceleration_bias, Eq(0.0));
565+ EXPECT_THAT(ptr_settings.horizontal_scroll_scale, Eq(1.0));
566+ EXPECT_THAT(ptr_settings.vertical_scroll_scale, Eq(1.0));
567+}
568+
569+TEST_F(LibInputDevice, applies_pointer_settings)
570+{
571+ char const mouse_device_path[] = "/dev/input/event13";
572+ char const mouse_name[] = "usb-mouse";
573+ setup_device(second_fake_device, mouse_device_path, mouse_name, 1231, 4124);
574+
575+ std::shared_ptr<libinput> lib = mie::make_libinput();
576+ mie::LibInputDevice dev(mir::report::null_input_report(), mouse_device_path, mie::make_libinput_device(lib.get(), path));
577+
578+ setup_pointer_configuration(dev.device(), 1, mir_pointer_handedness_right);
579+ mi::PointerSettings settings(dev.get_pointer_settings().value());
580+ settings.cursor_acceleration_bias = 1.1;
581+ settings.handedness = mir_pointer_handedness_left;
582+
583+ EXPECT_CALL(mock_libinput,libinput_device_config_accel_set_speed(dev.device(), 1.1)).Times(1);
584+ EXPECT_CALL(mock_libinput,libinput_device_config_left_handed_set(dev.device(), true)).Times(1);
585+
586+ dev.apply_settings(settings);
587+}
588+
589+TEST_F(LibInputDevice, denies_pointer_settings_on_keyboards)
590+{
591+ char const mouse_device_path[] = "/dev/input/event13";
592+ char const mouse_name[] = "usb-mouse";
593+ setup_device(second_fake_device, mouse_device_path, mouse_name, 1231, 4124);
594+
595+ std::shared_ptr<libinput> lib = mie::make_libinput();
596+ mie::LibInputDevice keyboard_dev(mir::report::null_input_report(), path, mie::make_libinput_device(lib.get(), path));
597+ mie::LibInputDevice mouse_dev(mir::report::null_input_report(), mouse_device_path, mie::make_libinput_device(lib.get(), path));
598+
599+ auto settings_from_mouse = mouse_dev.get_pointer_settings();
600+
601+ EXPECT_CALL(mock_libinput,libinput_device_config_accel_set_speed(_, _)).Times(0);
602+ EXPECT_CALL(mock_libinput,libinput_device_config_left_handed_set(_, _)).Times(0);
603+
604+ keyboard_dev.apply_settings(settings_from_mouse.value());
605+}
606+
607+TEST_F(LibInputDevice, scroll_speed_scales_scroll_events)
608+{
609+ char const mouse_device_path[] = "/dev/input/event13";
610+ char const mouse_name[] = "usb-mouse";
611+ setup_device(second_fake_device, mouse_device_path, mouse_name, 1231, 4124);
612+
613+ std::shared_ptr<libinput> lib = mie::make_libinput();
614+ mie::LibInputDevice dev(mir::report::null_input_report(), mouse_device_path, mie::make_libinput_device(lib.get(), mouse_device_path));
615+
616+ setup_axis_event(fake_event_1, event_time_1, 0.0, 3.0);
617+ setup_axis_event(fake_event_2, event_time_2, -2.0, 0.0);
618+
619+ // expect two scroll events..
620+ EXPECT_CALL(mock_sink, handle_input(mt::PointerAxisChange(mir_pointer_axis_vscroll, -3.0f)));
621+ EXPECT_CALL(mock_sink, handle_input(mt::PointerAxisChange(mir_pointer_axis_hscroll, -10.0f)));
622+
623+ setup_pointer_configuration(dev.device(), 1, mir_pointer_handedness_right);
624+ mi::PointerSettings settings(dev.get_pointer_settings().value());
625+ settings.vertical_scroll_scale = -1.0;
626+ settings.horizontal_scroll_scale = 5.0;
627+ dev.apply_settings(settings);
628+
629+ dev.start(&mock_sink, &mock_builder);
630+ dev.process_event(fake_event_1);
631+ dev.process_event(fake_event_2);
632+}
633
634=== modified file 'tests/unit-tests/input/test_default_input_device_hub.cpp'
635--- tests/unit-tests/input/test_default_input_device_hub.cpp 2015-10-07 16:41:50 +0000
636+++ tests/unit-tests/input/test_default_input_device_hub.cpp 2015-10-19 10:46:25 +0000
637@@ -25,6 +25,7 @@
638 #include "mir/test/event_matchers.h"
639
640 #include "mir/input/input_device.h"
641+#include "mir/input/pointer_settings.h"
642 #include "mir/input/device.h"
643 #include "mir/input/touch_visualizer.h"
644 #include "mir/input/input_device_observer.h"
645@@ -85,6 +86,8 @@
646 MOCK_METHOD2(start, void(mi::InputSink* destination, mi::EventBuilder* builder));
647 MOCK_METHOD0(stop, void());
648 MOCK_METHOD0(get_device_info, mi::InputDeviceInfo());
649+ MOCK_CONST_METHOD0(get_pointer_settings, mir::optional_value<mi::PointerSettings>());
650+ MOCK_METHOD1(apply_settings, void(mi::PointerSettings const&));
651 };
652
653 template<typename Type>

Subscribers

People subscribed via source and target branches