Merge lp:~oif-team/grail/trunk.v1.0.13 into lp:grail
- trunk.v1.0.13
- Merge into trunk
Status: | Superseded |
---|---|
Proposed branch: | lp:~oif-team/grail/trunk.v1.0.13 |
Merge into: | lp:grail |
Diff against target: |
326 lines (+148/-9) 8 files modified
configure.ac (+1/-1) include/grail-touch.h (+1/-0) src/gestures-tapping.c (+7/-2) src/grail-api.c (+9/-2) src/grail-gestures.c (+1/-1) src/grail-gestures.h (+1/-1) src/touch-caps.c (+37/-0) src/touch-dev.c (+91/-2) |
To merge this branch: | bzr merge lp:~oif-team/grail/trunk.v1.0.13 |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Henrik Rydberg | Pending | ||
Chase Douglas | Pending | ||
Review via email: mp+35028@code.launchpad.net |
This proposal supersedes a proposal from 2010-09-09.
This proposal has been superseded by a proposal from 2010-09-10.
Commit message
Description of the change
The changes needed to support non-MT devices through the utouch stack.
Chase Douglas (chasedouglas) wrote : Posted in a previous version of this proposal | # |
Henrik Rydberg (rydberg) wrote : Posted in a previous version of this proposal | # |
Well, I was thinking maverick for this, since there has already been bug reports about it. I see your point clearly, but I also see the conflict between the normal maverick procedure and the interests to make gestures work for as broad an audience as possible.
Henrik Rydberg (rydberg) wrote : Posted in a previous version of this proposal | # |
Code now replaces the "has_mtdata" with "is_supported" logic, and lets some non-MT devices
through. That should take care of the risk of regression for other devices.
Chase Douglas (chasedouglas) wrote : Posted in a previous version of this proposal | # |
It sounds like we're going to try to push this into maverick. I'm going to do some testing on it to be sure it doesn't kill my cat :).
Duncan McGreggor (oubiwann) wrote : Posted in a previous version of this proposal | # |
Yeah, we try to support animal-friendly products. Thanks for keeping that in mind, Chase.
Chase Douglas (chasedouglas) wrote : Posted in a previous version of this proposal | # |
Well, it didn't kill my cat, but it did kill my single touch cursor motion.
In lines 148, 153, and 158 in the big diff below, the return value should be 0 instead of 1 (according to Henrik). This fixed my issues.
Henrik Rydberg (rydberg) wrote : Posted in a previous version of this proposal | # |
Pacthes for two problems have been folded into the originals: 1) set minor when not available from the device, and 2) let grail-touch be transparent when driving a non-mt device. The latter caused the pointer position in the legacy emulation in grail-gesture to not be updated.
Chase Douglas (chasedouglas) wrote : Posted in a previous version of this proposal | # |
The synaptics functionality seems to work right for me now. However, I noticed another issue: four finger pinches are often recognized as taps. I believe the issue lies in the fact that the motion of the focus point inhibits a tap, but a pinch may not move the focus point. I have a proposed patch to fix this, and I'd like to see a fix end up in 1.0.13.
Henrik Rydberg (rydberg) wrote : Posted in a previous version of this proposal | # |
The triggers are on difference between absolute numbers, whereas here we want to add change, and trigger on the value of that change, which is not consistent (ie wont work properly).
Henrik Rydberg (rydberg) wrote : | # |
repack3, adding two more patches, thanks to Chase for finding those bugs.
- 79. By Henrik Rydberg
-
Make sure contact area is always defined
Some devices do not always send touch_minor after touch_major
has been set. According to the MT protocol, this case should
be treated as if minor is equal to major. This patch makes sure
touch_minor is never zero when touch_major is set. - 80. By Henrik Rydberg
-
Support legacy devices
Simulate MT touch events for legacy devices that support the
DOUBLETAP, TRIPLETAP and QUADTAP events. This allows multi-finger
tap and drag gestures to be emitted, providing a basic level of
MT functionality for legacy devices. - 81. By Henrik Rydberg
-
Discard tapping even when there are zero events between dow
n and upThe current logic assumes there will be at least one frame with
between touch up and touch down or the tap will not be properly
timed out. Fixed with this patch.Reported-by: Chase Douglas <email address hidden>
- 82. By Henrik Rydberg
-
Cancel tapping also on zoom events
The current code cancels tapping when dragging is active. This
patch adds zooming to the set, to inhibit tapping also when a
perfect zoom without dragging is performed.Reported-by: Chase Douglas <email address hidden>
- 83. By Henrik Rydberg
-
Only emit abs events when motion is active
This bug was hidden behind the motion inhibit during tapping,
but resurfaced when tapping from resting finger was introduced.
With this patch, pointer movement is inhibited also when lifting
fingers from the surface.Ideally, tapping should be treated as a transient event, which would
allow zero pointer event also _before_ the tap, but presently unity
seems to depend on the initial pointer movement as a touch-down event. - 84. By Henrik Rydberg
-
Inhibit taps immediately after a finger is lifted
The intentional tap starts with a finger in the air. This patch
treats the sequence up-down-up as unintentional, unless performed
with a single finger. Fixes the problem with accidental taps during
multi-finger gestures. - 85. By Henrik Rydberg
-
Allow slow tapping
For the benefit of hardware that cannot accurately meet the desirable
response times, allow for tapping times up to 300 ms. - 86. By Henrik Rydberg
-
grail v1.0.13
Unmerged revisions
Preview Diff
1 | === modified file 'configure.ac' |
2 | --- configure.ac 2010-09-01 21:01:08 +0000 |
3 | +++ configure.ac 2010-09-10 12:15:55 +0000 |
4 | @@ -1,7 +1,7 @@ |
5 | # Initialize Autoconf |
6 | AC_PREREQ([2.60]) |
7 | AC_INIT([Gesture Recognition And Instantiation Library], |
8 | - [1.0.12], |
9 | + [1.0.13], |
10 | [], |
11 | [utouch-grail]) |
12 | AC_CONFIG_SRCDIR([Makefile.am]) |
13 | |
14 | === modified file 'include/grail-touch.h' |
15 | --- include/grail-touch.h 2010-08-19 20:26:11 +0000 |
16 | +++ include/grail-touch.h 2010-09-10 12:15:55 +0000 |
17 | @@ -72,6 +72,7 @@ |
18 | int state; |
19 | }; |
20 | |
21 | +int touch_caps_is_supported(struct touch_dev *dev, int fd); |
22 | void touch_caps_init(struct touch_dev *dev); |
23 | float touch_angle(const struct touch_dev *dev, int orientation); |
24 | float touch_pressure(const struct touch_dev *dev, int pressure); |
25 | |
26 | === modified file 'src/gestures-tapping.c' |
27 | --- src/gestures-tapping.c 2010-08-26 14:41:20 +0000 |
28 | +++ src/gestures-tapping.c 2010-09-10 12:15:55 +0000 |
29 | @@ -24,8 +24,9 @@ |
30 | #include <math.h> |
31 | |
32 | static const int TAP_MIN_GAP_MS = 25; |
33 | +static const int TAP_MIN_UP_MS = 200; |
34 | |
35 | -static const int fm_mask = 0x03; |
36 | +static const int fm_mask = 0x07; |
37 | |
38 | static void set_props(const struct gesture_inserter *gin, |
39 | struct tapping_model *s, const struct move_model *m, |
40 | @@ -44,6 +45,9 @@ |
41 | struct gesture_recognizer *gru = ge->gru; |
42 | struct tapping_model *state = &gru->tapping; |
43 | struct move_model *move = &gru->move; |
44 | + grail_time_t up = move->time - state->end; |
45 | + if (move->ntouch && move->ntouch < state->ntouch) |
46 | + state->end = move->time; |
47 | if (move->ntouch > state->ntouch) { |
48 | if (state->active) { |
49 | gin_gid_discard(ge, state->gid); |
50 | @@ -67,7 +71,8 @@ |
51 | int x = state->prop[GRAIL_PROP_TAP_X]; |
52 | int y = state->prop[GRAIL_PROP_TAP_Y]; |
53 | int t = move->time - state->start; |
54 | - if (t < TAP_MIN_GAP_MS) { |
55 | + if (t < TAP_MIN_GAP_MS || t > move->fm[FM_X].bar_ms || |
56 | + up < TAP_MIN_UP_MS) { |
57 | gin_gid_discard(ge, state->gid); |
58 | state->ntouch = move->ntouch; |
59 | state->active = 0; |
60 | |
61 | === modified file 'src/grail-api.c' |
62 | --- src/grail-api.c 2010-08-26 14:40:35 +0000 |
63 | +++ src/grail-api.c 2010-09-10 12:15:55 +0000 |
64 | @@ -92,20 +92,27 @@ |
65 | return nevent; |
66 | } |
67 | |
68 | +static int pointer_active(const struct grail *ge) |
69 | +{ |
70 | + static const int fm_mask = 0x03; |
71 | + const struct move_model *move = &ge->gru->move; |
72 | + const struct tapping_model *tap = &ge->gru->tapping; |
73 | + return move->single && ((move->active & fm_mask) || tap->active); |
74 | +} |
75 | + |
76 | static void tp_sync(struct touch_dev *dev, |
77 | const struct input_event *syn) |
78 | { |
79 | struct input_event ev; |
80 | struct grail *ge = dev->priv; |
81 | struct grail_impl *impl = ge->impl; |
82 | - struct gesture_recognizer *gru = ge->gru; |
83 | struct touch_frame *frame = &dev->frame; |
84 | grail_mask_t filtered[DIM_EV_TYPE_BYTES]; |
85 | int pointer, nevent = 0; |
86 | gin_frame_begin(ge, frame); |
87 | gru_recognize(ge, frame); |
88 | gin_frame_end(ge, filtered, sizeof(filtered), frame); |
89 | - pointer = gru->move.single && !grail_mask_get(filtered, EV_ABS); |
90 | + pointer = pointer_active(ge) && !grail_mask_get(filtered, EV_ABS); |
91 | |
92 | if (!ge->event) { |
93 | evbuf_clear(&impl->evbuf); |
94 | |
95 | === modified file 'src/grail-gestures.c' |
96 | --- src/grail-gestures.c 2010-09-01 21:00:37 +0000 |
97 | +++ src/grail-gestures.c 2010-09-10 12:15:55 +0000 |
98 | @@ -26,7 +26,7 @@ |
99 | |
100 | static const float FM_SN[DIM_FM] = { 1000, 1000, 200, 1000 }; |
101 | static const float FM_BAR[DIM_FM] = { 50, 50, 30, 50 }; |
102 | -static const grail_time_t FM_BAR_MS[DIM_FM] = { 200, 200, 10000, 10000 }; |
103 | +static const grail_time_t FM_BAR_MS[DIM_FM] = { 300, 300, 10000, 10000 }; |
104 | static const grail_time_t SAMPLE_MS = 10; |
105 | static const float EPS = 1e-3; |
106 | |
107 | |
108 | === modified file 'src/grail-gestures.h' |
109 | --- src/grail-gestures.h 2010-08-26 14:41:20 +0000 |
110 | +++ src/grail-gestures.h 2010-09-10 12:15:55 +0000 |
111 | @@ -97,7 +97,7 @@ |
112 | const struct touch_frame *frame); |
113 | |
114 | struct tapping_model { |
115 | - grail_time_t start; |
116 | + grail_time_t start, end; |
117 | int ntouch; |
118 | int active, gid; |
119 | int nprop; |
120 | |
121 | === modified file 'src/touch-caps.c' |
122 | --- src/touch-caps.c 2010-08-31 12:20:32 +0000 |
123 | +++ src/touch-caps.c 2010-09-10 12:15:55 +0000 |
124 | @@ -21,6 +21,7 @@ |
125 | ****************************************************************************/ |
126 | |
127 | #include <grail-touch.h> |
128 | +#include <errno.h> |
129 | #include <math.h> |
130 | |
131 | /* see mtdev-mapping.h */ |
132 | @@ -29,6 +30,42 @@ |
133 | #define MTDEV_ORIENTATION 4 |
134 | #define MTDEV_PRESSURE 10 |
135 | |
136 | +#define SYSCALL(call) while (((call) == -1) && (errno == EINTR)) |
137 | + |
138 | +static const int bits_per_long = 8 * sizeof(long); |
139 | + |
140 | +static inline int nlongs(int nbit) |
141 | +{ |
142 | + return (nbit + bits_per_long - 1) / bits_per_long; |
143 | +} |
144 | + |
145 | +static inline int getbit(const unsigned long *map, int key) |
146 | +{ |
147 | + return (map[key / bits_per_long] >> (key % bits_per_long)) & 0x01; |
148 | +} |
149 | + |
150 | +int touch_caps_is_supported(struct touch_dev *dev, int fd) |
151 | +{ |
152 | + unsigned long keybits[nlongs(KEY_MAX)]; |
153 | + unsigned long absbits[nlongs(ABS_MAX)]; |
154 | + int rc; |
155 | + |
156 | + if (dev->mtdev.caps.has_mtdata) |
157 | + return 1; |
158 | + |
159 | + SYSCALL(rc = ioctl(fd, EVIOCGBIT(EV_KEY, sizeof(keybits)), keybits)); |
160 | + if (rc < 0) |
161 | + return 0; |
162 | + SYSCALL(rc = ioctl(fd, EVIOCGBIT(EV_ABS, sizeof(absbits)), absbits)); |
163 | + if (rc < 0) |
164 | + return 0; |
165 | + |
166 | + return getbit(absbits, ABS_X) && |
167 | + getbit(absbits, ABS_Y) && |
168 | + getbit(keybits, BTN_TOUCH) && |
169 | + getbit(keybits, BTN_TOOL_DOUBLETAP); |
170 | +} |
171 | + |
172 | void touch_caps_init(struct touch_dev *dev) |
173 | { |
174 | const struct mtdev_caps *mt = &dev->mtdev.caps; |
175 | |
176 | === modified file 'src/touch-dev.c' |
177 | --- src/touch-dev.c 2010-08-19 20:26:11 +0000 |
178 | +++ src/touch-dev.c 2010-09-10 12:15:55 +0000 |
179 | @@ -25,6 +25,9 @@ |
180 | #include <string.h> |
181 | #include <errno.h> |
182 | |
183 | +/* see mtdev-mapping.h */ |
184 | +#define MTDEV_TOUCH_MINOR 1 |
185 | + |
186 | #define SET_PROP(name, value) \ |
187 | if (t->name != value) { \ |
188 | t->name = value; \ |
189 | @@ -34,6 +37,9 @@ |
190 | static void finish_touch(struct touch_dev *dev, struct touch_frame *frame) |
191 | { |
192 | struct touch *t = &frame->touch[dev->slot]; |
193 | + if (t->touch_major && !t->touch_minor || |
194 | + !dev->mtdev.caps.has_abs[MTDEV_TOUCH_MINOR]) |
195 | + SET_PROP(touch_minor, t->touch_major); |
196 | if (dev->state > 0) { |
197 | t->active = 1; |
198 | grail_mask_set(frame->touches, dev->slot); |
199 | @@ -47,13 +53,45 @@ |
200 | dev->state = 0; |
201 | } |
202 | |
203 | +static void finish_legacy(struct touch_dev *dev, struct touch_frame *frame) |
204 | +{ |
205 | + static int trkid; |
206 | + int i; |
207 | + for (i = 0; i < frame->nactive; i++) { |
208 | + struct touch *t = &frame->touch[i]; |
209 | + t->active = 1; |
210 | + if (t->id < 0) { |
211 | + t->id = trkid++ & 0xffff; |
212 | + frame->ncreate++; |
213 | + } |
214 | + if (i > 0) { |
215 | + SET_PROP(x, frame->touch[0].x); |
216 | + SET_PROP(y, frame->touch[0].y); |
217 | + SET_PROP(pressure, frame->touch[0].pressure); |
218 | + } |
219 | + grail_mask_set(frame->touches, i); |
220 | + } |
221 | + for (i = frame->nactive; i < DIM_TOUCH; i++) { |
222 | + struct touch *t = &frame->touch[i]; |
223 | + t->active = 0; |
224 | + if (t->id >= 0) { |
225 | + t->id = -1; |
226 | + frame->ndestroy++; |
227 | + } |
228 | + grail_mask_clear(frame->touches, i); |
229 | + } |
230 | +} |
231 | + |
232 | static void finish_packet(struct touch_dev *dev, |
233 | const struct input_event *syn) |
234 | { |
235 | static const touch_time_t ms = 1000; |
236 | struct touch_frame *frame = &dev->frame; |
237 | int i, nslot = 0; |
238 | - finish_touch(dev, frame); |
239 | + if (dev->mtdev.caps.has_mtdata) |
240 | + finish_touch(dev, frame); |
241 | + else |
242 | + finish_legacy(dev, frame); |
243 | grail_mask_foreach(i, frame->touches, DIM_TOUCH_BYTES) |
244 | frame->active[nslot++] = &frame->touch[i]; |
245 | frame->nactive = nslot; |
246 | @@ -71,6 +109,21 @@ |
247 | struct touch_frame *frame = &dev->frame; |
248 | struct touch *t = &frame->touch[dev->slot]; |
249 | switch (ev->code) { |
250 | + case ABS_X: |
251 | + if (dev->mtdev.caps.has_mtdata) |
252 | + return 0; |
253 | + SET_PROP(x, ev->value); |
254 | + return 0; |
255 | + case ABS_Y: |
256 | + if (dev->mtdev.caps.has_mtdata) |
257 | + return 0; |
258 | + SET_PROP(y, ev->value); |
259 | + return 0; |
260 | + case ABS_PRESSURE: |
261 | + if (dev->mtdev.caps.has_mtdata) |
262 | + return 0; |
263 | + SET_PROP(pressure, ev->value); |
264 | + return 0; |
265 | case ABS_MT_SLOT: |
266 | if (ev->value >= 0 && ev->value < DIM_TOUCH) { |
267 | if (dev->slot != ev->value) |
268 | @@ -122,6 +175,40 @@ |
269 | } |
270 | } |
271 | |
272 | +static int handle_key_event(struct touch_dev *dev, |
273 | + const struct input_event *ev) |
274 | +{ |
275 | + struct touch_frame *frame = &dev->frame; |
276 | + if (dev->mtdev.caps.has_mtdata) |
277 | + return 0; |
278 | + switch (ev->code) { |
279 | + case BTN_TOUCH: |
280 | + if (ev->value && !frame->nactive) |
281 | + frame->nactive = 1; |
282 | + else if (!ev->value && frame->nactive) |
283 | + frame->nactive = 0; |
284 | + return 0; |
285 | + case BTN_TOOL_FINGER: |
286 | + if (ev->value) |
287 | + frame->nactive = 1; |
288 | + return 0; |
289 | + case BTN_TOOL_DOUBLETAP: |
290 | + if (ev->value) |
291 | + frame->nactive = 2; |
292 | + return 0; |
293 | + case BTN_TOOL_TRIPLETAP: |
294 | + if (ev->value) |
295 | + frame->nactive = 3; |
296 | + return 0; |
297 | + case BTN_TOOL_QUADTAP: |
298 | + if (ev->value) |
299 | + frame->nactive = 4; |
300 | + return 0; |
301 | + default: |
302 | + return 0; |
303 | + } |
304 | +} |
305 | + |
306 | int touch_dev_open(struct touch_dev *dev, int fd) |
307 | { |
308 | struct touch_frame *frame = &dev->frame; |
309 | @@ -133,7 +220,7 @@ |
310 | t->id = MT_ID_NULL; |
311 | } |
312 | ret = mtdev_open(&dev->mtdev, fd); |
313 | - if (!ret && !dev->mtdev.caps.has_mtdata) |
314 | + if (!ret && !touch_caps_is_supported(dev, fd)) |
315 | ret = -ENODEV; |
316 | if (ret) |
317 | goto error; |
318 | @@ -160,6 +247,8 @@ |
319 | consumed++; |
320 | } else if (ev.type == EV_ABS) { |
321 | consumed += handle_abs_event(dev, &ev); |
322 | + } else if (ev.type == EV_KEY) { |
323 | + consumed += handle_key_event(dev, &ev); |
324 | } |
325 | if (!consumed && dev->event) |
326 | dev->event(dev, &ev); |
Commit 79 makes sense, so no issues there.
However, I'm not sure what to do about commit 80. I think it looks good and it probably can introduce some interesting support for synaptics trackpads. However, it's also really late in the cycle to be adding this much new code.
I know it would be a bit of extra work, but can we keep commit 80 in a separate branch for now and not package it up for Maverick? By strict definition it is clearly out of scope at this point in the development cycle, and it likely won't actually add any new features since synaptics will be used for most of these devices anyways. However, I worry that there could be regressions in the single-touch touchscreen use case.
I guess the most appropriate review state for this is resubmit to include only commit 79. If you aren't meaning to push this into maverick, perhaps this could be merged as 1.1.0 and we would keep maverick on the 1.0.x series that would not include commit 80?