Status: | Superseded |
---|---|
Proposed branch: | lp:~oif-team/grail/grail2 |
Merge into: | lp:grail |
Diff against target: |
2575 lines (+1969/-148) 36 files modified
AUTHORS (+1/-0) configure.ac (+7/-0) docs/gestures.txt (+18/-0) docs/pivot.txt (+144/-0) include/grail-bits.h (+1/-2) include/grail-types.h (+1/-2) include/grail.h (+247/-49) src/Makefile.am (+4/-1) src/evbuf.h (+16/-23) src/gebuf.h (+1/-2) src/gestures-drag.c (+1/-2) src/gestures-pinch.c (+1/-2) src/gestures-rotate.c (+1/-2) src/gestures-tapping.c (+1/-2) src/grail-api.c (+10/-7) src/grail-bits.c (+1/-2) src/grail-event.c (+1/-27) src/grail-frame.c (+372/-0) src/grail-gestures.c (+1/-2) src/grail-gestures.h (+1/-2) src/grail-impl.h (+40/-3) src/grail-init.c (+240/-0) src/grail-inserter.c (+1/-2) src/grail-inserter.h (+1/-2) src/grail-legacy.c (+65/-0) src/grail-recognizer.c (+1/-2) src/grail-recognizer.h (+1/-2) src/grailbuf.h (+1/-2) test/Makefile.am (+1/-0) test/check-grail.c (+2/-0) test/check-transform.c (+137/-0) tools/Makefile.am (+12/-4) tools/grail-gesture.c (+1/-4) tools/grail-test-mtdev.c (+256/-0) tools/grail-transform.c (+374/-0) utouch-grail.sym.in (+6/-0) |
To merge this branch: | bzr merge lp:~oif-team/grail/grail2 |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Open Input Framework Team | Pending | ||
Review via email: mp+55291@code.launchpad.net |
This proposal has been superseded by a proposal from 2011-03-29.
Commit message
Description of the change
Rebased grail2 starter kit, this could go in trunk now.
- 139. By Chase Douglas
-
Merge send-key-events branch for better semi-mt support.
- 140. By Henrik Rydberg
-
Do not discard a started gesture
Not all discarding code paths were taking the notion of a started
gesture into account. Specifically, switching to a gesture of higher
priority would leave the old gesture without a finish. Fixed with
this patch.Note that timeout implies not sent, so all discarding code paths
are now covered.Signed-off-by: Henrik Rydberg <email address hidden>
- 141. By Henrik Rydberg
-
Glue touch gestures as well
All motion-activated gestures are held for a short (glue) time
to allow for direct transition to multi-finger gesture types.
The touch gestures were mistakenly implemented without this.
Fixed with this patch. LP: #748282Signed-off-by: Henrik Rydberg <email address hidden>
- 142. By Chase Douglas
-
Merge branch to remove the EWMA move filter
- 143. By Jussi Pakkanen
-
Merged visibility fixes.
- 144. By Jussi Pakkanen
-
Merged C++ header fix.
- 145. By Jussi Pakkanen
-
Merge Pkg-config fix.
- 146. By Henrik Rydberg
-
Fixup remaining C++ and public function declarations
The grail-bits.h file can be included on its own, so it needs
the same handling. To save files in public name space, move the
visibility declarations to grail-bits.h, and include it as a main
file from grail.h.Signed-off-by: Henrik Rydberg <email address hidden>
- 147. By Jussi Pakkanen
-
Merged Clang cleanups.
- 148. By Henrik Rydberg
-
Expose utouch-frame through grail API
Start a gentle API change by exposing utouch-frame through grail,
and deprecating the grail_contact struct. Old programs compile and
run fine. To only use the new api, compile with -DGRAIL_NO_LEGACY_ API. Signed-off-by: Henrik Rydberg <email address hidden>
- 149. By Henrik Rydberg
-
Prepare for gesture frame additions
Rename internal variables and fix makefile to make room for new
targets.Signed-off-by: Henrik Rydberg <email address hidden>
- 150. By Henrik Rydberg
-
Introduce gesture frames
This patch extends the API with parallel new/delete functions,
aiming to eventually replace the open/close function. The new
functions give access to the grail gesture frames, containing
gestural transform information. This information is useful in its
own right, and will eventually replace the internal recognizer.Signed-off-by: Henrik Rydberg <email address hidden>
- 151. By Henrik Rydberg
-
Document the gesture frame logic
Add some notes on the math of the gesture frame computations.
Signed-off-by: Henrik Rydberg <email address hidden>
- 152. By Henrik Rydberg
-
Add gesture transform unit tests
Start the gesture frame test suite with some basic coordinate
mapping tests.Signed-off-by: Henrik Rydberg <email address hidden>
- 153. By Henrik Rydberg
-
Introduce test-mtdev
A new tool (test-mtdev) is added, showing the usage of gesture frames.
Signed-off-by: Henrik Rydberg <email address hidden>
- 154. By Henrik Rydberg
-
Introduce the grail transform tool
This tool tests the transform capabilities of grail. Similar to a
map application, one can use a single finger, two fingers, a whole
hand or two hands to move the rectangle around, scale and rotate it.Signed-off-by: Henrik Rydberg <email address hidden>
- 155. By Henrik Rydberg
-
Update copyright information
The license information was always right, but the copyright information
for this particular project was never quite right. Corrected with this
patch. No functional changes.Signed-off-by: Henrik Rydberg <email address hidden>
Unmerged revisions
Preview Diff
1 | === added file 'AUTHORS' |
2 | --- AUTHORS 1970-01-01 00:00:00 +0000 |
3 | +++ AUTHORS 2011-03-29 08:01:03 +0000 |
4 | @@ -0,0 +1,1 @@ |
5 | +Henrik Rydberg <rydberg@bitmath.org> |
6 | |
7 | === modified file 'configure.ac' |
8 | --- configure.ac 2011-03-17 09:47:52 +0000 |
9 | +++ configure.ac 2011-03-29 08:01:03 +0000 |
10 | @@ -26,6 +26,13 @@ |
11 | PKG_CHECK_MODULES([EVEMU], [utouch-evemu >= 1.0.5]) |
12 | PKG_CHECK_MODULES([FRAME], [utouch-frame >= 1.0]) |
13 | |
14 | +AC_ARG_WITH([xi], AS_HELP_STRING([--with-xi], [Build with XI2.1 support])) |
15 | +AM_CONDITIONAL([HAVE_XI], [test "x$with_xi" != "x"]) |
16 | + |
17 | +AS_IF([test "x$with_xi" = "xyes"], [ |
18 | + PKG_CHECK_MODULES(XINPUT, x11 xext [xi >= 1.4.1.99.1] [inputproto >= 2.0.99.1]) |
19 | + AC_DEFINE([HAVE_XI], [1], [XI2.1 support]) |
20 | +]) |
21 | # Check for TDD tools |
22 | PKG_CHECK_MODULES([CHECK], [check >= 0.9.8], |
23 | [have_check=yes], |
24 | |
25 | === added file 'docs/gestures.txt' |
26 | --- docs/gestures.txt 1970-01-01 00:00:00 +0000 |
27 | +++ docs/gestures.txt 2011-03-29 08:01:03 +0000 |
28 | @@ -0,0 +1,18 @@ |
29 | +The gesture transformation from a multi-finger action is overstated and to |
30 | +a certain extent arbitrary. This document describes how it is performed in |
31 | +grail2. |
32 | + |
33 | +All two-finger transformations are extracted. These are all exact, in the |
34 | +sense that continusouly transforming the original finger position, frame |
35 | +per frame, will exactly follow the actual finger position. |
36 | + |
37 | +In addition to two-finger transformations, one global gesture is also |
38 | +extracted. The rotation and scaling is taken from the pair with the longest |
39 | +distance between contacts. This approximates the behavior of a region, such |
40 | +that complex transformations could be happening inside the region, but at a |
41 | +distance, the behavior should look like it was performed with two fingers. |
42 | + |
43 | +The pivot of the global gesture is extracted using least squares, using the |
44 | +same principle as for contact pairs; the pivot is the point which, after |
45 | +rotation and scaling, leaves the transformed contacts as close to the |
46 | +actual positions as possible. |
47 | |
48 | === added file 'docs/pivot.txt' |
49 | --- docs/pivot.txt 1970-01-01 00:00:00 +0000 |
50 | +++ docs/pivot.txt 2011-03-29 08:01:03 +0000 |
51 | @@ -0,0 +1,144 @@ |
52 | +The pivot, p, is defined as the point, within the convex hull of the |
53 | +contacts, which, after rotation and scaling, leaves the transformed |
54 | +contacts as close to the actual positions as possible. |
55 | + |
56 | +Let r_i be the starting points and s_i the actual ending points in a |
57 | +transformation. Let D be the scaling, and R the rotation. Then, minimizing |
58 | + |
59 | +L(p) = sum_i |D R (r_i - p) + p - s_i|^2 / N |
60 | + |
61 | +yields the pivot. Let |
62 | + |
63 | +rm = sum_i r_i / N, |
64 | +p = rm + u, |
65 | +q_i = s_i - rm - D R (r_i - rm), |
66 | + |
67 | +and we get |
68 | + |
69 | +L(p) = sum_i |(1 - D R) u - q_i|^2 / N. |
70 | + |
71 | +With |
72 | + |
73 | +L0 = sum_i norm2(q_i) / N, |
74 | +T = (1 - D R)' (1 - D R), |
75 | +m = sum_i q_i / N, |
76 | + |
77 | +we can write this as |
78 | + |
79 | +L(p) = L0 + u' T u - 2 m' (1 - D R) u. |
80 | + |
81 | +To handle the constraint, we can approximate the hull with a circle |
82 | +centered at rm. If we pick the average radius, P, the constraint becomes |
83 | + |
84 | +|u| < P. |
85 | + |
86 | +Relaxing the expression (h >= 0) yields |
87 | + |
88 | +L(p, h) = L0 + u' T u - 2 m' (1 - D R) u + h (|u|^2 - P^2), |
89 | + |
90 | +leading to the linear equation |
91 | + |
92 | +(T + h) u = (1 - D R)' m. |
93 | + |
94 | +Further, |
95 | + |
96 | +sm = sum_i s_i / N, |
97 | +m = sum_i (s_i - rm - D R (r_i - rm)) / N = sm - rm, |
98 | + |
99 | +thus m is the average displacement. In words, the pivot is the average |
100 | +position plus a correction depending on the average displacement. |
101 | + |
102 | +* |
103 | + |
104 | +Some algebra solves the equation, |
105 | + |
106 | +D' = D, |
107 | +[D, R] = 0, |
108 | +R = S + C, |
109 | +S' = -S, |
110 | +C' = C, |
111 | +R + R' = 2 C, |
112 | +T = (1 - D R)' (1 - D R) = 1 + D^2 - 2 D C, |
113 | + |
114 | +which is a simple diagonal scaling operator. With |
115 | + |
116 | +a = 1 - D C, |
117 | +b = D S, |
118 | + |
119 | +we can write this as |
120 | + |
121 | +T = (1 - DC)^2 + D^2(1 - C^2) = (1 - DC)^2 + D^2 S^2 = a^2 + b^2. |
122 | + |
123 | +Similarly, we can write |
124 | + |
125 | +(1 - D R)' = ((a, b), (-b, a)), |
126 | + |
127 | +and thusly, |
128 | + |
129 | +u = Q(h) m, |
130 | + |
131 | +with |
132 | + |
133 | +Q(h) = ((a, b), (-b, a)) / (a^2 + b^2 + h). |
134 | + |
135 | +When D R = 1, it follows that a^2 + b^2 = 0, and the relaxation ensures |
136 | +that u is finite. |
137 | + |
138 | +* |
139 | + |
140 | +The drag is found by minimizing |
141 | + |
142 | +E(d) = sum_i | D R (r_i - p) + p + d - s_i |^2 / N, |
143 | +E(d) = d^2 + 2 d' ((1 - D R) u - m) + E0, |
144 | + |
145 | +which leads to the linear equation |
146 | + |
147 | +d = m - (1 - D R) u. |
148 | + |
149 | +Explicitly, |
150 | + |
151 | +d = m - (a ux - b uy, a uy + b ux). |
152 | + |
153 | +Inserting the expression for u yields, after some algebra, |
154 | + |
155 | +d = m (1 - (a^2 + b^2) / (a^2 + b^2 + h)). |
156 | + |
157 | +When h = 0, d = 0, as expected. |
158 | + |
159 | +When a^2 + b^2 = 0, d = m, also as expected. |
160 | + |
161 | +For constrained cases, the drag is a fraction of the average displacement. |
162 | + |
163 | +* |
164 | + |
165 | +Time to look at measures for the relaxation parameter. Since d depends on |
166 | +h, we can write the correction u(h) in terms of d instead. After som |
167 | +algebra, |
168 | + |
169 | +|u(h)| = (|m| - |d|) / sqrt(a^2 + b^2). |
170 | + |
171 | +Conversely, d(h) can be written in terms of the constrained u(h) as |
172 | + |
173 | +d(h) = m (1 - sqrt(a^2 + b^2) |u(h)| / |m|). |
174 | + |
175 | +Since |u(0)| = |m| / sqrt(a^2 + b^2), we obtain |
176 | + |
177 | +d(h) = m (1 - |u(h)| / |u(0)|). |
178 | + |
179 | +* |
180 | + |
181 | +We can now write down an explicit recipe for determining the pivot (p) and |
182 | +drag (d), given the transformation parameters a and b. |
183 | + |
184 | +w = (a mx + b my, a my - b mx). |
185 | + |
186 | +If |w| = 0, then u = 0. Consequently p = rm, d = m, and we are done. Else, |
187 | + |
188 | +u = w |m|^2 / |w|^2, |
189 | + |
190 | +t = P / |u|. |
191 | + |
192 | +If t >= 1, then p = rm + u, d = 0, and we are done. Else, |
193 | + |
194 | +p = rm + t u, |
195 | +d = (1 - t) m. |
196 | |
197 | === modified file 'include/grail-bits.h' |
198 | --- include/grail-bits.h 2010-08-06 20:30:20 +0000 |
199 | +++ include/grail-bits.h 2011-03-29 08:01:03 +0000 |
200 | @@ -2,8 +2,7 @@ |
201 | * |
202 | * grail - Gesture Recognition And Instantiation Library |
203 | * |
204 | - * Copyright (C) 2010 Canonical Ltd. |
205 | - * Copyright (C) 2010 Henrik Rydberg <rydberg@bitmath.org> |
206 | + * Copyright (C) 2010-2011 Canonical Ltd. |
207 | * |
208 | * This program is free software: you can redistribute it and/or modify it |
209 | * under the terms of the GNU General Public License as published by the |
210 | |
211 | === modified file 'include/grail-types.h' |
212 | --- include/grail-types.h 2011-03-28 20:04:07 +0000 |
213 | +++ include/grail-types.h 2011-03-29 08:01:03 +0000 |
214 | @@ -2,8 +2,7 @@ |
215 | * |
216 | * grail - Gesture Recognition And Instantiation Library |
217 | * |
218 | - * Copyright (C) 2010 Canonical Ltd. |
219 | - * Copyright (C) 2010 Henrik Rydberg <rydberg@bitmath.org> |
220 | + * Copyright (C) 2010-2011 Canonical Ltd. |
221 | * |
222 | * This program is free software: you can redistribute it and/or modify it |
223 | * under the terms of the GNU General Public License as published by the |
224 | |
225 | === modified file 'include/grail.h' |
226 | --- include/grail.h 2010-08-19 20:35:45 +0000 |
227 | +++ include/grail.h 2011-03-29 08:01:03 +0000 |
228 | @@ -2,8 +2,7 @@ |
229 | * |
230 | * grail - Gesture Recognition And Instantiation Library |
231 | * |
232 | - * Copyright (C) 2010 Canonical Ltd. |
233 | - * Copyright (C) 2010 Henrik Rydberg <rydberg@bitmath.org> |
234 | + * Copyright (C) 2010-2011 Canonical Ltd. |
235 | * |
236 | * This program is free software: you can redistribute it and/or modify it |
237 | * under the terms of the GNU General Public License as published by the |
238 | @@ -25,8 +24,11 @@ |
239 | |
240 | #include <grail-bits.h> |
241 | #include <grail-types.h> |
242 | +#include <utouch/frame.h> |
243 | #include <linux/input.h> |
244 | |
245 | +#define GRAIL_VERSION 0x00011000 |
246 | + |
247 | #define DIM_GRAIL_TYPE 64 |
248 | #define DIM_GRAIL_TYPE_BYTES ((DIM_GRAIL_TYPE + 7) >> 3) |
249 | |
250 | @@ -37,8 +39,28 @@ |
251 | #define GRAIL_STATUS_UPDATE 1 |
252 | #define GRAIL_STATUS_END 2 |
253 | |
254 | -typedef float grail_prop_t; /* gesture properties */ |
255 | -typedef __u64 grail_time_t; /* time in milliseconds */ |
256 | +#define GRAIL_EXPECT_X 0x0001 |
257 | +#define GRAIL_EXPECT_Y 0x0002 |
258 | +#define GRAIL_EXPECT_SCALE 0x0004 |
259 | +#define GRAIL_EXPECT_ANGLE 0x0008 |
260 | +#define GRAIL_EXPECT_MASK 0x000f |
261 | + |
262 | +typedef float grail_prop_t; /* gesture properties */ |
263 | +typedef utouch_frame_time_t grail_time_t; /* time in milliseconds */ |
264 | +typedef struct grail *grail_handle; /* the grail instance handle */ |
265 | + |
266 | +/** |
267 | + * struct grail_get_version - get grail library version |
268 | + * |
269 | + * Report the version of the grail library, which can be different from |
270 | + * the value of GRAIL_VERSION in this header file. |
271 | + * |
272 | + * This function allows for fallback options from major interface |
273 | + * extensions within the same ABI version. For the normal cases of ABI |
274 | + * agnostic or backwards incompatible changes, this function is not |
275 | + * needed. |
276 | + */ |
277 | +unsigned int grail_get_version(void); |
278 | |
279 | /** |
280 | * struct grail_coord - coordinate in bounding box units |
281 | @@ -49,32 +71,63 @@ |
282 | float x, y; |
283 | }; |
284 | |
285 | -/** |
286 | - * struct grail_contact - MT event information in bounding box units |
287 | - * @id: Contact tracking id |
288 | - * @tool_type: Tool type (ABS_MT_TOOL_TYPE) |
289 | - * @pos: Position of contact (bbox units) |
290 | - * @touch_major: Major axis of contact shape (bbox units) |
291 | - * @touch_minor: Minor axis of contact shape (bbox units) |
292 | - * @width_major: Major axis of perimeter (bbox units) |
293 | - * @width_minor: Minor axis of perimeter (bbox units) |
294 | - * @angle: Angle of orientation (vertical: 0 horizontal: +-M_PI_2) |
295 | - * @pressure: Pressure of contact (min: 0 max: 1) |
296 | - * |
297 | - * Depending on the native support of the underlying device, some or all of |
298 | - * the listed properties may be computed. |
299 | - */ |
300 | -struct grail_contact { |
301 | - int id; |
302 | - int tool_type; |
303 | - struct grail_coord pos; |
304 | - float touch_major; |
305 | - float touch_minor; |
306 | - float width_major; |
307 | - float width_minor; |
308 | - float angle; |
309 | - float pressure; |
310 | -}; |
311 | +grail_handle grail_new_raw(utouch_frame_handle fh, |
312 | + unsigned int num_frames, |
313 | + void *select, |
314 | + unsigned int version, |
315 | + unsigned int control_size, |
316 | + unsigned int frame_size, |
317 | + unsigned int slot_size); |
318 | + |
319 | +/** |
320 | + * grail_new - allocate and initialize a new grail instance |
321 | + * @fh: utouch frame handle to use |
322 | + * @num_frames: number of frames in cyclic buffer |
323 | + * @select: client selection callback |
324 | + * |
325 | + * Initialize the internal grail structures. |
326 | + * |
327 | + * Returns zero in case of failure. |
328 | + */ |
329 | +#define grail_new(fh, num_frames, select) \ |
330 | + grail_new_raw(fh, num_frames, select, \ |
331 | + GRAIL_VERSION, \ |
332 | + sizeof(struct grail_control), \ |
333 | + sizeof(struct grail_frame), \ |
334 | + sizeof(struct grail_element)) |
335 | + |
336 | +/** |
337 | + * grail_delete - destroy and delete grail instance |
338 | + * @ge: grail instance in use |
339 | + * |
340 | + * Deallocates all internal memory structures. |
341 | + */ |
342 | +void grail_delete(grail_handle ge); |
343 | + |
344 | +/** |
345 | + * grail_get_control - get mutable control structure |
346 | + * @ge: the grail device in use |
347 | + * |
348 | + * Return the control struct of the grail instance. |
349 | + * |
350 | + * The control pointer is ABI agnostic, owned by the grail instance, and |
351 | + * has grail scope. |
352 | + */ |
353 | +struct grail_control *grail_get_control(grail_handle ge); |
354 | + |
355 | +/** |
356 | + * grail_pump_frame - insert touch frames into grail |
357 | + * @ge: the grail device in use |
358 | + * @frame: the touch frame to insert |
359 | + * |
360 | + * Insert a new touch frame into the grail engine. If the frame induces a |
361 | + * new gesture frame, a pointer to the frame is returned. |
362 | + * |
363 | + * The grail frame pointer is ABI agnostic, owned by the grail instance, and |
364 | + * has grail scope. |
365 | + */ |
366 | +const struct grail_frame *grail_pump_frame(grail_handle ge, |
367 | + const struct utouch_frame *frame); |
368 | |
369 | /** |
370 | * struct grail_client_id - Gesture client information |
371 | @@ -102,6 +155,139 @@ |
372 | }; |
373 | |
374 | /** |
375 | + * struct grail_control - control parameters of grail |
376 | + * @glue_ms: minimum time to hold activation (ms) |
377 | + * @thresh_drag: minimum moveness for drag |
378 | + * @thresh_scale: maximum moveness for rotate and scale |
379 | + * @bar_x: minimum horizontal distance to activate (surface width fraction) |
380 | + * @bar_y: minimum vertical distance to activate (surface height fraction) |
381 | + * @bar_scale: minimum scaling to activate (fraction) |
382 | + * @bar_angle: minimum angle to activate (radians) |
383 | + * @drop_x_ms: horizontal expect timeout (ms) |
384 | + * @drop_y_ms: vertical expect timeout (ms) |
385 | + * @drop_scale_ms: scaling expect timeout (ms) |
386 | + * @drop_angle_ms: rotation expect timeout (ms) |
387 | + * |
388 | + * The parameters are used to tune the behavior of the gesture recognition. |
389 | + * |
390 | + * The moveness is a number between zero and one denoting the |
391 | + * character of the current transform. Zero means pure rotate and |
392 | + * scale, one means pure drag. |
393 | + * |
394 | + * Later versions of this struct may grow in size, but will remain |
395 | + * binary compatible with older versions. |
396 | + */ |
397 | +struct grail_control { |
398 | + float glue_ms; |
399 | + float thresh_drag; |
400 | + float thresh_scale; |
401 | + float bar_x; |
402 | + float bar_y; |
403 | + float bar_scale; |
404 | + float bar_angle; |
405 | + float drop_x_ms; |
406 | + float drop_y_ms; |
407 | + float drop_scale_ms; |
408 | + float drop_angle_ms; |
409 | +}; |
410 | + |
411 | +/** |
412 | + * struct grail_frame - frame of ongoing elementary transformations |
413 | + * @prev: pointer to the previous gesture frame |
414 | + * @touch: pointer to the touch frame triggering this gesture frame |
415 | + * @num_ongoing: number of elements in the ongoing array |
416 | + * @ongoing: array of ongoing transformation elements |
417 | + * @slots: array of all transformation slots |
418 | + * |
419 | + * A gesture frame consists of one or several touch frames glued |
420 | + * together into a stable transition, combined with information on |
421 | + * ongoing elementary gestural transformations. The array of ongoing |
422 | + * elements contains all elements with a nonzero expect mask. |
423 | + * |
424 | + * Later versions of this struct may grow in size, but will remain |
425 | + * binary compatible with older versions. |
426 | + */ |
427 | +struct grail_frame { |
428 | + const struct grail_frame *prev; |
429 | + const struct utouch_frame *touch; |
430 | + unsigned int num_ongoing; |
431 | + struct grail_element **ongoing; |
432 | + struct grail_element **slots; |
433 | +}; |
434 | + |
435 | +/** |
436 | + * struct grail_element - elementary gesture transformation |
437 | + * @prev: respective element of previous frame |
438 | + * @slot: the transformation slot occupied by this element |
439 | + * @id: unique identifier of the ongoing transformation |
440 | + * @num_touches: number of contacts of this element |
441 | + * @touches: array of contacts of this element |
442 | + * @start_time: start time of this element |
443 | + * @expect_mask: bitmask of expected gestures (grail main types) |
444 | + * @active_mask: bitmask of activated gestures (grail main types) |
445 | + * @center: gesture center position (surface units) |
446 | + * @velocity: current center velocity (surface units per second) |
447 | + * @radius: gesture radius from center (surface units) |
448 | + * @transform: the transformation matrix of the gesture |
449 | + * @pivot: current center of rotate and scale (surface units) |
450 | + * @drag: accumulated transformation displacement (surface units) |
451 | + * @scale: accumulated scale (dimensionless) |
452 | + * @angle: accumulated rotation angle (radians) |
453 | + * |
454 | + * The grail element describes the ongoing gestural transformation of |
455 | + * a particular set of contacts. The expect mask describes which |
456 | + * gestural transformations may become active during the course of |
457 | + * events, and the active mask describes which have passed their |
458 | + * respective activation threshold. The set of expected gestures can |
459 | + * change over time, for instance by exclusion or timeout. |
460 | + * |
461 | + * Applications handling rotation, either by transformation matrix or |
462 | + * angle, should use the drag displacement. For other applications, |
463 | + * the center displacement may be used instead, as to not lose |
464 | + * movement accuracy. |
465 | + * |
466 | + * Later versions of this struct may grow in size, but will remain |
467 | + * binary compatible with older versions. |
468 | + */ |
469 | +struct grail_element { |
470 | + const struct grail_element *prev; |
471 | + int slot; |
472 | + int id; |
473 | + int num_touches; |
474 | + const struct utouch_contact **touches; |
475 | + grail_time_t start_time; |
476 | + unsigned int expect_mask; |
477 | + unsigned int active_mask; |
478 | + struct grail_coord center; |
479 | + struct grail_coord velocity; |
480 | + float radius2; |
481 | + float transform[6]; |
482 | + float moveness; |
483 | + struct grail_coord pivot; |
484 | + struct grail_coord drag; |
485 | + float scale2; |
486 | + float angle; |
487 | +}; |
488 | + |
489 | +/** |
490 | + * grail_element_transform - transform coordinates using element |
491 | + * @slot: the transformation element to use |
492 | + * @q: the grail coordinate to fill |
493 | + * @x: the grail coordinate to transform |
494 | + * |
495 | + * Performs the 3x3 transform *q = T *p, where T is the element |
496 | + * transform. |
497 | + */ |
498 | +static inline void grail_element_transform(const struct grail_element *slot, |
499 | + struct grail_coord *q, |
500 | + const struct grail_coord *p) |
501 | +{ |
502 | + const float *T = slot->transform; |
503 | + q->x = T[0] * p->x + T[1] * p->y + T[2]; |
504 | + q->y = T[3] * p->x + T[4] * p->y + T[5]; |
505 | +} |
506 | + |
507 | +/** |
508 | * struct grail_event - Gesture event |
509 | * @type: The gesture type |
510 | * @id: Unique identifier foof the gesture instance |
511 | @@ -227,19 +413,6 @@ |
512 | const struct grail_coord *max); |
513 | |
514 | /** |
515 | - * grail_filter_abs_events - filter kernel motion events |
516 | - * @ge: the grail device in use |
517 | - * @usage: When true, filter kernel motion events. |
518 | - * |
519 | - * Single-finger pointer events are treated as pointer gestures in |
520 | - * grail. When filter_motion_events is non-zero, the kernel events |
521 | - * corresponding to pointer movement are removed from the event |
522 | - * stream. |
523 | - * |
524 | - */ |
525 | -void grail_filter_abs_events(struct grail *ge, int usage); |
526 | - |
527 | -/** |
528 | * grail_get_units - get device coordinate ranges |
529 | * @ge: the grail device in use |
530 | * @min: minimum x and y coordinates |
531 | @@ -255,15 +428,40 @@ |
532 | struct grail_coord *min, struct grail_coord *max); |
533 | |
534 | /** |
535 | - * grail_get_contacts - get current contact state |
536 | + * grail_get_contact_frame - get current contact frame |
537 | * @ge: the grail device in use |
538 | - * @touch: array of contacts to be filled in |
539 | - * @max_touch: maximum number of contacts supported by the array |
540 | - * |
541 | - * Extract the contact state as currently seen by grail. |
542 | - * |
543 | + * |
544 | + * Return the contact frame current being processed. If called from |
545 | + * within a gesture callback, it is guaranteed to return the frame |
546 | + * corresponding to the gesture. |
547 | + * |
548 | + * The returned pointer can be NULL if no input has yet been extracted |
549 | + * through the grail instance. |
550 | + * |
551 | + * The frame pointer is ABI agnostic, owned by the grail instance, and |
552 | + * has grail scope. |
553 | */ |
554 | +const struct utouch_frame *grail_get_contact_frame(const struct grail *ge); |
555 | + |
556 | +#ifndef GRAIL_NO_LEGACY_API |
557 | + |
558 | +struct grail_contact { |
559 | + int id; |
560 | + int tool_type; |
561 | + struct grail_coord pos; |
562 | + float touch_major; |
563 | + float touch_minor; |
564 | + float width_major; |
565 | + float width_minor; |
566 | + float angle; |
567 | + float pressure; |
568 | +}; |
569 | + |
570 | +void grail_filter_abs_events(struct grail *ge, int usage); |
571 | + |
572 | int grail_get_contacts(const struct grail *ge, |
573 | struct grail_contact *touch, int max_touch); |
574 | |
575 | #endif |
576 | + |
577 | +#endif |
578 | |
579 | === modified file 'src/Makefile.am' |
580 | --- src/Makefile.am 2011-03-28 20:04:07 +0000 |
581 | +++ src/Makefile.am 2011-03-29 08:01:03 +0000 |
582 | @@ -26,7 +26,10 @@ |
583 | grail-recognizer.h \ |
584 | grail-event.c \ |
585 | grail-impl.h \ |
586 | - grail-api.c |
587 | + grail-api.c \ |
588 | + grail-legacy.c \ |
589 | + grail-init.c \ |
590 | + grail-frame.c |
591 | |
592 | AM_CFLAGS = $(CWARNFLAGS) |
593 | |
594 | |
595 | === modified file 'src/evbuf.h' |
596 | --- src/evbuf.h 2011-02-24 22:50:31 +0000 |
597 | +++ src/evbuf.h 2011-03-29 08:01:03 +0000 |
598 | @@ -1,28 +1,21 @@ |
599 | /***************************************************************************** |
600 | * |
601 | - * mtdev - Multitouch Protocol Translation Library (MIT license) |
602 | - * |
603 | - * Copyright (C) 2010 Canonical Ltd. |
604 | - * Copyright (C) 2010 Henrik Rydberg <rydberg@bitmath.org> |
605 | - * |
606 | - * Permission is hereby granted, free of charge, to any person obtaining a |
607 | - * copy of this software and associated documentation files (the "Software"), |
608 | - * to deal in the Software without restriction, including without limitation |
609 | - * the rights to use, copy, modify, merge, publish, distribute, sublicense, |
610 | - * and/or sell copies of the Software, and to permit persons to whom the |
611 | - * Software is furnished to do so, subject to the following conditions: |
612 | - * |
613 | - * The above copyright notice and this permission notice (including the next |
614 | - * paragraph) shall be included in all copies or substantial portions of the |
615 | - * Software. |
616 | - * |
617 | - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
618 | - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
619 | - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL |
620 | - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
621 | - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING |
622 | - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER |
623 | - * DEALINGS IN THE SOFTWARE. |
624 | + * grail - Gesture Recognition And Instantiation Library |
625 | + * |
626 | + * Copyright (C) 2010-2011 Canonical Ltd. |
627 | + * |
628 | + * This program is free software: you can redistribute it and/or modify it |
629 | + * under the terms of the GNU General Public License as published by the |
630 | + * Free Software Foundation, either version 3 of the License, or (at your |
631 | + * option) any later version. |
632 | + * |
633 | + * This program is distributed in the hope that it will be useful, but |
634 | + * WITHOUT ANY WARRANTY; without even the implied warranty of |
635 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
636 | + * General Public License for more details. |
637 | + * |
638 | + * You should have received a copy of the GNU General Public License along |
639 | + * with this program. If not, see <http://www.gnu.org/licenses/>. |
640 | * |
641 | ****************************************************************************/ |
642 | |
643 | |
644 | === modified file 'src/gebuf.h' |
645 | --- src/gebuf.h 2011-01-02 12:08:08 +0000 |
646 | +++ src/gebuf.h 2011-03-29 08:01:03 +0000 |
647 | @@ -2,8 +2,7 @@ |
648 | * |
649 | * grail - Gesture Recognition And Instantiation Library |
650 | * |
651 | - * Copyright (C) 2010 Canonical Ltd. |
652 | - * Copyright (C) 2010 Henrik Rydberg <rydberg@bitmath.org> |
653 | + * Copyright (C) 2010-2011 Canonical Ltd. |
654 | * |
655 | * This program is free software: you can redistribute it and/or modify it |
656 | * under the terms of the GNU General Public License as published by the |
657 | |
658 | === modified file 'src/gestures-drag.c' |
659 | --- src/gestures-drag.c 2011-03-28 20:04:18 +0000 |
660 | +++ src/gestures-drag.c 2011-03-29 08:01:03 +0000 |
661 | @@ -2,8 +2,7 @@ |
662 | * |
663 | * grail - Gesture Recognition And Instantiation Library |
664 | * |
665 | - * Copyright (C) 2010 Canonical Ltd. |
666 | - * Copyright (C) 2010 Henrik Rydberg <rydberg@bitmath.org> |
667 | + * Copyright (C) 2010-2011 Canonical Ltd. |
668 | * |
669 | * This program is free software: you can redistribute it and/or modify it |
670 | * under the terms of the GNU General Public License as published by the |
671 | |
672 | === modified file 'src/gestures-pinch.c' |
673 | --- src/gestures-pinch.c 2011-03-28 20:04:11 +0000 |
674 | +++ src/gestures-pinch.c 2011-03-29 08:01:03 +0000 |
675 | @@ -2,8 +2,7 @@ |
676 | * |
677 | * grail - Gesture Recognition And Instantiation Library |
678 | * |
679 | - * Copyright (C) 2010 Canonical Ltd. |
680 | - * Copyright (C) 2010 Henrik Rydberg <rydberg@bitmath.org> |
681 | + * Copyright (C) 2010-2011 Canonical Ltd. |
682 | * |
683 | * This program is free software: you can redistribute it and/or modify it |
684 | * under the terms of the GNU General Public License as published by the |
685 | |
686 | === modified file 'src/gestures-rotate.c' |
687 | --- src/gestures-rotate.c 2011-03-28 20:04:11 +0000 |
688 | +++ src/gestures-rotate.c 2011-03-29 08:01:03 +0000 |
689 | @@ -2,8 +2,7 @@ |
690 | * |
691 | * grail - Gesture Recognition And Instantiation Library |
692 | * |
693 | - * Copyright (C) 2010 Canonical Ltd. |
694 | - * Copyright (C) 2010 Henrik Rydberg <rydberg@bitmath.org> |
695 | + * Copyright (C) 2010-2011 Canonical Ltd. |
696 | * |
697 | * This program is free software: you can redistribute it and/or modify it |
698 | * under the terms of the GNU General Public License as published by the |
699 | |
700 | === modified file 'src/gestures-tapping.c' |
701 | --- src/gestures-tapping.c 2011-03-24 21:46:18 +0000 |
702 | +++ src/gestures-tapping.c 2011-03-29 08:01:03 +0000 |
703 | @@ -2,8 +2,7 @@ |
704 | * |
705 | * grail - Gesture Recognition And Instantiation Library |
706 | * |
707 | - * Copyright (C) 2010 Canonical Ltd. |
708 | - * Copyright (C) 2010 Henrik Rydberg <rydberg@bitmath.org> |
709 | + * Copyright (C) 2010-2011 Canonical Ltd. |
710 | * |
711 | * This program is free software: you can redistribute it and/or modify it |
712 | * under the terms of the GNU General Public License as published by the |
713 | |
714 | === modified file 'src/grail-api.c' |
715 | --- src/grail-api.c 2011-03-17 09:46:39 +0000 |
716 | +++ src/grail-api.c 2011-03-29 08:01:03 +0000 |
717 | @@ -2,8 +2,7 @@ |
718 | * |
719 | * grail - Gesture Recognition And Instantiation Library |
720 | * |
721 | - * Copyright (C) 2010 Canonical Ltd. |
722 | - * Copyright (C) 2010 Henrik Rydberg <rydberg@bitmath.org> |
723 | + * Copyright (C) 2010-2011 Canonical Ltd. |
724 | * |
725 | * This program is free software: you can redistribute it and/or modify it |
726 | * under the terms of the GNU General Public License as published by the |
727 | @@ -20,9 +19,9 @@ |
728 | * |
729 | ****************************************************************************/ |
730 | |
731 | +#include "grail-impl.h" |
732 | #include "grail-inserter.h" |
733 | #include "grail-recognizer.h" |
734 | -#include "grail-impl.h" |
735 | #include <string.h> |
736 | #include <stdio.h> |
737 | #include <unistd.h> |
738 | @@ -34,10 +33,9 @@ |
739 | #define DIM_FRAMES 100 |
740 | #define FRAME_RATE 100 |
741 | |
742 | -void grail_filter_abs_events(struct grail *ge, int usage) |
743 | +unsigned int grail_get_version(void) |
744 | { |
745 | - struct grail_impl *x = ge->impl; |
746 | - x->filter_abs = usage; |
747 | + return GRAIL_VERSION; |
748 | } |
749 | |
750 | int grail_open(struct grail *ge, int fd) |
751 | @@ -151,6 +149,11 @@ |
752 | max->y = s->max_y; |
753 | } |
754 | |
755 | +const struct utouch_frame *grail_get_contact_frame(const struct grail *ge) |
756 | +{ |
757 | + return ge->impl->touch; |
758 | +} |
759 | + |
760 | static void flush_events(struct grail *ge) |
761 | { |
762 | struct grail_impl *impl = ge->impl; |
763 | @@ -226,7 +229,7 @@ |
764 | struct grail_impl *impl = ge->impl; |
765 | struct grail_event gev; |
766 | |
767 | - ge->impl->frame = frame; |
768 | + ge->impl->touch = frame; |
769 | |
770 | if (frame->num_active && !frame->prev->num_active) { |
771 | impl->ongoing = 1; |
772 | |
773 | === modified file 'src/grail-bits.c' |
774 | --- src/grail-bits.c 2010-08-06 20:30:20 +0000 |
775 | +++ src/grail-bits.c 2011-03-29 08:01:03 +0000 |
776 | @@ -2,8 +2,7 @@ |
777 | * |
778 | * grail - Gesture Recognition And Instantiation Library |
779 | * |
780 | - * Copyright (C) 2010 Canonical Ltd. |
781 | - * Copyright (C) 2010 Henrik Rydberg <rydberg@bitmath.org> |
782 | + * Copyright (C) 2010-2011 Canonical Ltd. |
783 | * |
784 | * This program is free software: you can redistribute it and/or modify it |
785 | * under the terms of the GNU General Public License as published by the |
786 | |
787 | === modified file 'src/grail-event.c' |
788 | --- src/grail-event.c 2011-03-17 09:48:13 +0000 |
789 | +++ src/grail-event.c 2011-03-29 08:01:03 +0000 |
790 | @@ -2,8 +2,7 @@ |
791 | * |
792 | * grail - Gesture Recognition And Instantiation Library |
793 | * |
794 | - * Copyright (C) 2010 Canonical Ltd. |
795 | - * Copyright (C) 2010 Henrik Rydberg <rydberg@bitmath.org> |
796 | + * Copyright (C) 2010-2011 Canonical Ltd. |
797 | * |
798 | * This program is free software: you can redistribute it and/or modify it |
799 | * under the terms of the GNU General Public License as published by the |
800 | @@ -117,28 +116,3 @@ |
801 | grailbuf_put(&impl->gbuf, &gev); |
802 | } |
803 | } |
804 | - |
805 | -int grail_get_contacts(const struct grail *ge, |
806 | - struct grail_contact *touch, int max_touch) |
807 | -{ |
808 | - const struct gesture_inserter *gin = ge->gin; |
809 | - const struct utouch_frame *frame = ge->impl->frame; |
810 | - int i; |
811 | - if (frame->num_active < max_touch) |
812 | - max_touch = frame->num_active; |
813 | - for (i = 0; i < max_touch; i++) { |
814 | - struct grail_contact *t = &touch[i]; |
815 | - const struct utouch_contact *ct = frame->active[i]; |
816 | - t->id = ct->id; |
817 | - t->tool_type = ct->tool_type; |
818 | - t->pos.x = ct->x; |
819 | - t->pos.y = ct->y; |
820 | - t->touch_major = ct->touch_major; |
821 | - t->touch_minor = ct->touch_minor; |
822 | - t->width_major = ct->width_major; |
823 | - t->width_minor = ct->width_minor; |
824 | - t->angle = ct->orientation; |
825 | - t->pressure = ct->pressure; |
826 | - } |
827 | - return max_touch; |
828 | -} |
829 | |
830 | === added file 'src/grail-frame.c' |
831 | --- src/grail-frame.c 1970-01-01 00:00:00 +0000 |
832 | +++ src/grail-frame.c 2011-03-29 08:01:03 +0000 |
833 | @@ -0,0 +1,372 @@ |
834 | +/***************************************************************************** |
835 | + * |
836 | + * grail - Gesture Recognition And Instantiation Library |
837 | + * |
838 | + * Copyright (C) 2010-2011 Canonical Ltd. |
839 | + * |
840 | + * This program is free software: you can redistribute it and/or modify it |
841 | + * under the terms of the GNU General Public License as published by the |
842 | + * Free Software Foundation, either version 3 of the License, or (at your |
843 | + * option) any later version. |
844 | + * |
845 | + * This program is distributed in the hope that it will be useful, but |
846 | + * WITHOUT ANY WARRANTY; without even the implied warranty of |
847 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
848 | + * General Public License for more details. |
849 | + * |
850 | + * You should have received a copy of the GNU General Public License along |
851 | + * with this program. If not, see <http://www.gnu.org/licenses/>. |
852 | + * |
853 | + ****************************************************************************/ |
854 | + |
855 | +#include "grail-impl.h" |
856 | +#include <stdlib.h> |
857 | +#include <string.h> |
858 | +#include <math.h> |
859 | + |
860 | +static void set_center_velocity_and_radius(struct grail_impl *impl, |
861 | + struct grail_element *slot) |
862 | +{ |
863 | + const struct utouch_contact **tc = slot->touches; |
864 | + double x, y, vx, vy, r2, dx, dy; |
865 | + int i; |
866 | + |
867 | + switch (slot->num_touches) { |
868 | + case 1: |
869 | + x = tc[0]->x; |
870 | + y = tc[0]->y; |
871 | + vx = tc[0]->vx; |
872 | + vy = tc[0]->vy; |
873 | + r2 = 0; |
874 | + break; |
875 | + case 2: |
876 | + dx = 0.5 * (tc[1]->x - tc[0]->x); |
877 | + dy = 0.5 * (tc[1]->y - tc[0]->y); |
878 | + x = tc[0]->x + dx; |
879 | + y = tc[0]->y + dy; |
880 | + vx = 0.5 * (tc[0]->vx + tc[1]->vx); |
881 | + vy = 0.5 * (tc[0]->vy + tc[1]->vy); |
882 | + r2 = dx * dx + dy * dy; |
883 | + break; |
884 | + default: |
885 | + x = y = vx = vy = r2 = 0; |
886 | + for (i = 0; i < slot->num_touches; i++) { |
887 | + x += tc[i]->x; |
888 | + y += tc[i]->y; |
889 | + vx += tc[i]->vx; |
890 | + vy += tc[i]->vy; |
891 | + } |
892 | + x /= slot->num_touches; |
893 | + y /= slot->num_touches; |
894 | + vx /= slot->num_touches; |
895 | + vy /= slot->num_touches; |
896 | + for (i = 0; i < slot->num_touches; i++) { |
897 | + dx = tc[i]->x - x; |
898 | + dy = tc[i]->y - y; |
899 | + r2 += dx * dx + dy * dy; |
900 | + } |
901 | + r2 /= slot->num_touches; |
902 | + break; |
903 | + } |
904 | + |
905 | + slot->center.x = x; |
906 | + slot->center.y = y; |
907 | + slot->velocity.x = 1000 * vx; |
908 | + slot->velocity.y = 1000 * vy; |
909 | + slot->radius2 = r2; |
910 | +} |
911 | + |
912 | +static void set_moveness_pivot_and_drag(struct grail_impl *impl, |
913 | + struct grail_element *slot, |
914 | + double ds, double dc) |
915 | +{ |
916 | + const struct grail_element *pslot = slot->prev; |
917 | + double mx = slot->center.x - pslot->center.x; |
918 | + double my = slot->center.y - pslot->center.y; |
919 | + float *T = slot->transform; |
920 | + |
921 | + slot->moveness = 1; |
922 | + slot->pivot = pslot->center; |
923 | + |
924 | + if (slot->num_touches > 1) { |
925 | + double wx = (1 - dc) * mx + ds * my; |
926 | + double wy = (1 - dc) * my - ds * mx; |
927 | + double w2 = wx * wx + wy * wy; |
928 | + if (w2 > 0) { |
929 | + double s = sqrt(pslot->radius2 / w2); |
930 | + double q = (mx * mx + my * my) / w2; |
931 | + if (s < q) { |
932 | + slot->moveness = 1 - s / q; |
933 | + slot->pivot.x += s * wx; |
934 | + slot->pivot.y += s * wy; |
935 | + } else { |
936 | + slot->moveness = 0; |
937 | + slot->pivot.x += q * wx; |
938 | + slot->pivot.y += q * wy; |
939 | + } |
940 | + } |
941 | + } |
942 | + |
943 | + mx *= slot->moveness; |
944 | + my *= slot->moveness; |
945 | + |
946 | + T[0] = dc; |
947 | + T[1] = ds; |
948 | + T[2] = (1 - dc) * slot->pivot.x - ds * slot->pivot.y + mx; |
949 | + T[3] = -ds; |
950 | + T[4] = dc; |
951 | + T[5] = (1 - dc) * slot->pivot.y + ds * slot->pivot.x + my; |
952 | + |
953 | + slot->drag.x = pslot->drag.x + mx; |
954 | + slot->drag.y = pslot->drag.y + my; |
955 | +} |
956 | + |
957 | +static void start_slot(struct grail_impl *impl, |
958 | + struct grail_element *slot, |
959 | + const struct utouch_frame *touch) |
960 | +{ |
961 | + float *T = slot->transform; |
962 | + |
963 | + slot->id = impl->seqid++ & GRAIL_ID_MAX; |
964 | + slot->expect_mask = GRAIL_EXPECT_MASK; |
965 | + slot->active_mask = 0; |
966 | + slot->start_time = touch->time; |
967 | + set_center_velocity_and_radius(impl, slot); |
968 | + T[0] = T[4] = 1; |
969 | + T[1] = T[2] = T[3] = T[5] = 0; |
970 | + slot->pivot = slot->center; |
971 | + slot->drag.x = 0; |
972 | + slot->drag.y = 0; |
973 | + slot->scale2 = 1; |
974 | + slot->angle = 0; |
975 | +} |
976 | + |
977 | +static void update_slot(struct grail_impl *impl, |
978 | + struct grail_element *slot, |
979 | + double ds, double dc) |
980 | +{ |
981 | + const struct grail_element *pslot = slot->prev; |
982 | + |
983 | + slot->id = pslot->id; |
984 | + slot->expect_mask = pslot->expect_mask; |
985 | + slot->active_mask = pslot->active_mask; |
986 | + slot->start_time = pslot->start_time; |
987 | + |
988 | + set_center_velocity_and_radius(impl, slot); |
989 | + set_moveness_pivot_and_drag(impl, slot, ds, dc); |
990 | + |
991 | + slot->scale2 = pslot->scale2 * (ds * ds + dc * dc); |
992 | + slot->angle = pslot->angle + ds / dc; /* atan2(ds, dc) */ |
993 | +} |
994 | + |
995 | +static void stop_slot(struct grail_impl *impl, |
996 | + struct grail_element *slot) |
997 | +{ |
998 | + slot->id = -1; |
999 | + slot->expect_mask = 0; |
1000 | + slot->num_touches = 0; |
1001 | +} |
1002 | + |
1003 | +static void set_slot_one(struct grail_impl *impl, |
1004 | + struct grail_element *slot, |
1005 | + const struct utouch_frame *touch, |
1006 | + const struct utouch_contact *t1) |
1007 | +{ |
1008 | + const struct grail_element *pslot = slot->prev; |
1009 | + const struct utouch_contact *p1 = pslot->touches[0]; |
1010 | + |
1011 | + if (!t1->active) { |
1012 | + stop_slot(impl, slot); |
1013 | + return; |
1014 | + } |
1015 | + |
1016 | + slot->touches[0] = t1; |
1017 | + slot->num_touches = 1; |
1018 | + |
1019 | + if (pslot->num_touches != slot->num_touches || t1->id != p1->id) { |
1020 | + start_slot(impl, slot, touch); |
1021 | + return; |
1022 | + } |
1023 | + |
1024 | + update_slot(impl, slot, 0, 1); |
1025 | +} |
1026 | + |
1027 | +static void set_slot_two(struct grail_impl *impl, |
1028 | + struct grail_element *slot, |
1029 | + const struct utouch_frame *touch, |
1030 | + const struct utouch_contact *t1, |
1031 | + const struct utouch_contact *t2) |
1032 | +{ |
1033 | + const struct grail_element *pslot = slot->prev; |
1034 | + const struct utouch_contact *p1 = pslot->touches[0]; |
1035 | + const struct utouch_contact *p2 = pslot->touches[1]; |
1036 | + double tx, ty, px, py, d2; |
1037 | + |
1038 | + if (!t1->active || !t2->active) { |
1039 | + stop_slot(impl, slot); |
1040 | + return; |
1041 | + } |
1042 | + |
1043 | + slot->touches[0] = t1; |
1044 | + slot->touches[1] = t2; |
1045 | + slot->num_touches = 2; |
1046 | + |
1047 | + if (pslot->num_touches != slot->num_touches || |
1048 | + t1->id != p1->id || t2->id != p2->id) { |
1049 | + start_slot(impl, slot, touch); |
1050 | + return; |
1051 | + } |
1052 | + |
1053 | + tx = t2->x - t1->x; |
1054 | + ty = t2->y - t1->y; |
1055 | + px = p2->x - p1->x; |
1056 | + py = p2->y - p1->y; |
1057 | + |
1058 | + d2 = px * px + py * py; |
1059 | + if (d2 > 0) { |
1060 | + px /= d2; |
1061 | + py /= d2; |
1062 | + } |
1063 | + |
1064 | + update_slot(impl, slot, tx * py - ty * px, tx * px + ty * py); |
1065 | +} |
1066 | + |
1067 | +static void set_slot_multi(struct grail_impl *impl, |
1068 | + struct grail_element *slot, |
1069 | + struct grail_frame *frame, |
1070 | + const struct utouch_frame *touch) |
1071 | +{ |
1072 | + const struct grail_element *pslot = slot->prev; |
1073 | + struct grail_element **slots = frame->slots; |
1074 | + int i, j, n = impl->num_touches; |
1075 | + struct grail_element *best = 0; |
1076 | + |
1077 | + if (touch->num_active < 3) { |
1078 | + stop_slot(impl, slot); |
1079 | + return; |
1080 | + } |
1081 | + |
1082 | + memcpy(slot->touches, touch->active, |
1083 | + touch->num_active * sizeof(slot->touches[0])); |
1084 | + slot->num_touches = touch->num_active; |
1085 | + |
1086 | + if (pslot->num_touches != slot->num_touches) { |
1087 | + start_slot(impl, slot, touch); |
1088 | + return; |
1089 | + } |
1090 | + |
1091 | + for (i = 0; i < slot->num_touches; i++) { |
1092 | + if (slot->touches[i]->id != pslot->touches[i]->id) { |
1093 | + start_slot(impl, slot, touch); |
1094 | + return; |
1095 | + } |
1096 | + } |
1097 | + |
1098 | + for (i = 0; i < impl->num_touches; i++) { |
1099 | + for (j = i + 1; j < impl->num_touches; j++) { |
1100 | + struct grail_element *s = slots[n++]; |
1101 | + if (!s->num_touches) |
1102 | + continue; |
1103 | + if (!best || s->radius2 > best->radius2) |
1104 | + best = s; |
1105 | + } |
1106 | + } |
1107 | + |
1108 | + update_slot(impl, slot, best->transform[1], best->transform[0]); |
1109 | +} |
1110 | + |
1111 | +static void set_slots(struct grail_impl *impl, |
1112 | + struct grail_frame *frame, |
1113 | + const struct utouch_frame *touch) |
1114 | +{ |
1115 | + struct grail_element **slots = frame->slots; |
1116 | + struct utouch_contact *const *tc = touch->slots; |
1117 | + int i, j, n = 0; |
1118 | + |
1119 | + for (i = 0; i < impl->num_touches; i++) |
1120 | + set_slot_one(impl, slots[n++], touch, tc[i]); |
1121 | + |
1122 | + for (i = 0; i < impl->num_touches; i++) |
1123 | + for (j = i + 1; j < impl->num_touches; j++) |
1124 | + set_slot_two(impl, slots[n++], touch, tc[i], tc[j]); |
1125 | + |
1126 | + set_slot_multi(impl, slots[n++], frame, touch); |
1127 | +} |
1128 | + |
1129 | +static void collect_transforms(struct grail_impl *impl, |
1130 | + struct grail_frame *frame, |
1131 | + const struct utouch_frame *touch) |
1132 | +{ |
1133 | + const struct utouch_surface *s = utouch_frame_get_surface(impl->fh); |
1134 | + const struct grail_control *ctl = impl->ctl; |
1135 | + float dx = ctl->bar_x * (s->mapped_max_x - s->mapped_min_x); |
1136 | + float dy = ctl->bar_y * (s->mapped_max_y - s->mapped_min_y); |
1137 | + float ds2 = ctl->bar_scale * ctl->bar_scale; |
1138 | + float dt; |
1139 | + int i; |
1140 | + |
1141 | + for (i = 0; i < impl->num_slots; i++) { |
1142 | + struct grail_element *s = frame->slots[i]; |
1143 | + |
1144 | + if (!s->expect_mask) |
1145 | + continue; |
1146 | + |
1147 | + dt = touch->time - s->start_time; |
1148 | + if (dt > ctl->glue_ms) { |
1149 | + |
1150 | + if (s->moveness > ctl->thresh_drag) { |
1151 | + if (fabs(s->drag.x) > dx) |
1152 | + s->active_mask |= GRAIL_EXPECT_X; |
1153 | + if (fabs(s->drag.y) > dy) |
1154 | + s->active_mask |= GRAIL_EXPECT_Y; |
1155 | + } |
1156 | + if (s->moveness < ctl->thresh_scale) { |
1157 | + if (fabs(s->scale2 - 1) > ds2) |
1158 | + s->active_mask |= GRAIL_EXPECT_SCALE; |
1159 | + if (fabs(s->angle) > ctl->bar_angle) |
1160 | + s->active_mask |= GRAIL_EXPECT_ANGLE; |
1161 | + } |
1162 | + |
1163 | + s->active_mask &= s->expect_mask; |
1164 | + |
1165 | + if (dt > ctl->drop_x_ms) |
1166 | + s->expect_mask &= ~GRAIL_EXPECT_X; |
1167 | + if (dt > ctl->drop_y_ms) |
1168 | + s->expect_mask &= ~GRAIL_EXPECT_Y; |
1169 | + if (dt > ctl->drop_scale_ms) |
1170 | + s->expect_mask &= ~GRAIL_EXPECT_SCALE; |
1171 | + if (dt > ctl->drop_angle_ms) |
1172 | + s->expect_mask &= ~GRAIL_EXPECT_ANGLE; |
1173 | + |
1174 | + s->expect_mask |= s->active_mask; |
1175 | + } |
1176 | + |
1177 | + if (s->expect_mask) |
1178 | + frame->ongoing[frame->num_ongoing++] = s; |
1179 | + } |
1180 | +} |
1181 | + |
1182 | +const struct grail_frame *grail_pump_frame(grail_handle ge, |
1183 | + const struct utouch_frame *touch) |
1184 | +{ |
1185 | + struct grail_impl *impl = ge->impl; |
1186 | + struct grail_frame *frame = impl->frames[impl->nextframe]; |
1187 | + const struct grail_frame *prev = frame->prev; |
1188 | + int i; |
1189 | + |
1190 | + if (touch->slot_revision == touch->prev->slot_revision && |
1191 | + !prev->num_ongoing) |
1192 | + return 0; |
1193 | + |
1194 | + frame->touch = touch; |
1195 | + frame->num_ongoing = 0; |
1196 | + for (i = 0; i < impl->num_slots; i++) |
1197 | + frame->slots[i]->prev = prev->slots[i]; |
1198 | + |
1199 | + set_slots(impl, frame, touch); |
1200 | + collect_transforms(impl, frame, touch); |
1201 | + |
1202 | + impl->nextframe = (impl->nextframe + 1) % impl->num_frames; |
1203 | + |
1204 | + return frame; |
1205 | +} |
1206 | |
1207 | === modified file 'src/grail-gestures.c' |
1208 | --- src/grail-gestures.c 2011-03-28 20:04:16 +0000 |
1209 | +++ src/grail-gestures.c 2011-03-29 08:01:03 +0000 |
1210 | @@ -2,8 +2,7 @@ |
1211 | * |
1212 | * grail - Gesture Recognition And Instantiation Library |
1213 | * |
1214 | - * Copyright (C) 2010 Canonical Ltd. |
1215 | - * Copyright (C) 2010 Henrik Rydberg <rydberg@bitmath.org> |
1216 | + * Copyright (C) 2010-2011 Canonical Ltd. |
1217 | * |
1218 | * This program is free software: you can redistribute it and/or modify it |
1219 | * under the terms of the GNU General Public License as published by the |
1220 | |
1221 | === modified file 'src/grail-gestures.h' |
1222 | --- src/grail-gestures.h 2011-03-28 20:04:07 +0000 |
1223 | +++ src/grail-gestures.h 2011-03-29 08:01:03 +0000 |
1224 | @@ -2,8 +2,7 @@ |
1225 | * |
1226 | * grail - Gesture Recognition And Instantiation Library |
1227 | * |
1228 | - * Copyright (C) 2010 Canonical Ltd. |
1229 | - * Copyright (C) 2010 Henrik Rydberg <rydberg@bitmath.org> |
1230 | + * Copyright (C) 2010-2011 Canonical Ltd. |
1231 | * |
1232 | * This program is free software: you can redistribute it and/or modify it |
1233 | * under the terms of the GNU General Public License as published by the |
1234 | |
1235 | === modified file 'src/grail-impl.h' |
1236 | --- src/grail-impl.h 2011-03-17 09:46:39 +0000 |
1237 | +++ src/grail-impl.h 2011-03-29 08:01:03 +0000 |
1238 | @@ -2,8 +2,7 @@ |
1239 | * |
1240 | * grail - Gesture Recognition And Instantiation Library |
1241 | * |
1242 | - * Copyright (C) 2010 Canonical Ltd. |
1243 | - * Copyright (C) 2010 Henrik Rydberg <rydberg@bitmath.org> |
1244 | + * Copyright (C) 2010-2011 Canonical Ltd. |
1245 | * |
1246 | * This program is free software: you can redistribute it and/or modify it |
1247 | * under the terms of the GNU General Public License as published by the |
1248 | @@ -33,18 +32,56 @@ |
1249 | |
1250 | #define DIM_TOUCH 32 |
1251 | #define DIM_TOUCH_BYTES ((DIM_TOUCH + 7) >> 3) |
1252 | +#define GRAIL_ID_MAX 0xffff |
1253 | + |
1254 | +#define MIN(a, b) ((a) < (b) ? (a) : (b)) |
1255 | +#define MAX(a, b) ((a) > (b) ? (a) : (b)) |
1256 | + |
1257 | +typedef void *grail_select_callback; |
1258 | + |
1259 | +/* |
1260 | + * In this implementation, there can be N one-gestures, N (N - 1) / 2 |
1261 | + * two-gestures, and one global gesture. |
1262 | + */ |
1263 | +static inline int get_slot_count(int n) |
1264 | +{ |
1265 | + return n + n * (n - 1) / 2 + 1; |
1266 | +} |
1267 | + |
1268 | +int create_grail2(struct grail_impl *x, |
1269 | + utouch_frame_handle fh, |
1270 | + unsigned int num_frames, |
1271 | + void *select, |
1272 | + unsigned int version, |
1273 | + unsigned int control_size, |
1274 | + unsigned int frame_size, |
1275 | + unsigned int slot_size); |
1276 | + |
1277 | +void destroy_grail2(struct grail_impl *x); |
1278 | |
1279 | struct grail_impl { |
1280 | struct evemu_device *evemu; |
1281 | struct mtdev *mtdev; |
1282 | utouch_frame_handle fh; |
1283 | - const struct utouch_frame *frame; |
1284 | + const struct utouch_frame *touch; |
1285 | struct evbuf evbuf; |
1286 | struct grailbuf gbuf; |
1287 | int filter_abs; |
1288 | int ongoing; |
1289 | int gesture; |
1290 | FILE *fptest; |
1291 | + /* new stuff below */ |
1292 | + struct grail_control *ctl; |
1293 | + grail_select_callback select; |
1294 | + int num_frames; |
1295 | + int num_slots; |
1296 | + int num_touches; |
1297 | + int nextframe; |
1298 | + int seqid; |
1299 | + unsigned int control_size; |
1300 | + unsigned int frame_size; |
1301 | + unsigned int slot_size; |
1302 | + struct grail_frame **frames; |
1303 | }; |
1304 | |
1305 | #endif |
1306 | |
1307 | === added file 'src/grail-init.c' |
1308 | --- src/grail-init.c 1970-01-01 00:00:00 +0000 |
1309 | +++ src/grail-init.c 2011-03-29 08:01:03 +0000 |
1310 | @@ -0,0 +1,240 @@ |
1311 | +/***************************************************************************** |
1312 | + * |
1313 | + * grail - Gesture Recognition And Instantiation Library |
1314 | + * |
1315 | + * Copyright (C) 2010-2011 Canonical Ltd. |
1316 | + * |
1317 | + * This program is free software: you can redistribute it and/or modify it |
1318 | + * under the terms of the GNU General Public License as published by the |
1319 | + * Free Software Foundation, either version 3 of the License, or (at your |
1320 | + * option) any later version. |
1321 | + * |
1322 | + * This program is distributed in the hope that it will be useful, but |
1323 | + * WITHOUT ANY WARRANTY; without even the implied warranty of |
1324 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
1325 | + * General Public License for more details. |
1326 | + * |
1327 | + * You should have received a copy of the GNU General Public License along |
1328 | + * with this program. If not, see <http://www.gnu.org/licenses/>. |
1329 | + * |
1330 | + ****************************************************************************/ |
1331 | + |
1332 | +#include "grail-impl.h" |
1333 | +#include <stdlib.h> |
1334 | +#include <string.h> |
1335 | +#include <math.h> |
1336 | + |
1337 | +static struct grail_control *create_control(int size) |
1338 | +{ |
1339 | + struct grail_control *c = calloc(1, size); |
1340 | + |
1341 | + if (!c) |
1342 | + return 0; |
1343 | + |
1344 | + c->glue_ms = 60; |
1345 | + c->thresh_drag = 0.8; |
1346 | + c->thresh_scale = 0.2; |
1347 | + c->bar_x = 0.02; |
1348 | + c->bar_y = 0.02; |
1349 | + c->bar_scale = 0.3; |
1350 | + c->bar_angle = 0.1; |
1351 | + c->drop_x_ms = 300; |
1352 | + c->drop_y_ms = 300; |
1353 | + c->drop_scale_ms = 300; |
1354 | + c->drop_angle_ms = 300; |
1355 | + |
1356 | + return c; |
1357 | +} |
1358 | + |
1359 | +static void destroy_slots(struct grail_element **slots, int nslot) |
1360 | +{ |
1361 | + int i; |
1362 | + |
1363 | + if (slots) { |
1364 | + for (i = nslot - 1; i >= 0; i--) |
1365 | + free(slots[i]); |
1366 | + free(slots); |
1367 | + } |
1368 | +} |
1369 | + |
1370 | +static void destroy_frame(struct grail_frame *frame, int nslot) |
1371 | +{ |
1372 | + if (frame) { |
1373 | + destroy_slots(frame->slots, nslot); |
1374 | + free(frame->ongoing); |
1375 | + free(frame); |
1376 | + } |
1377 | +} |
1378 | + |
1379 | +static void destroy_frames(struct grail_frame **frames, int nframe, int nslot) |
1380 | +{ |
1381 | + int i; |
1382 | + |
1383 | + if (frames) { |
1384 | + for (i = nframe - 1; i >= 0; i--) |
1385 | + destroy_frame(frames[i], nslot); |
1386 | + free(frames); |
1387 | + } |
1388 | +} |
1389 | + |
1390 | +static struct grail_element **create_slots(int nslot, int ntouch, int size) |
1391 | +{ |
1392 | + struct grail_element **slots; |
1393 | + struct grail_element *s; |
1394 | + int i; |
1395 | + |
1396 | + slots = calloc(nslot, sizeof(slots[0])); |
1397 | + if (!slots) |
1398 | + return 0; |
1399 | + |
1400 | + for (i = 0; i < nslot; i++) { |
1401 | + s = calloc(1, size + ntouch * sizeof(void *)); |
1402 | + if (!s) |
1403 | + goto out; |
1404 | + s->slot = i; |
1405 | + s->id = -1; |
1406 | + s->touches = (void *)((char *)s + size); |
1407 | + slots[i] = s; |
1408 | + } |
1409 | + |
1410 | + return slots; |
1411 | + out: |
1412 | + destroy_slots(slots, nslot); |
1413 | + return 0; |
1414 | +} |
1415 | + |
1416 | +static struct grail_frame *create_frame(int nslot, int ntouch, |
1417 | + int frame_size, int slot_size) |
1418 | +{ |
1419 | + struct grail_frame *frame; |
1420 | + int i; |
1421 | + |
1422 | + frame = calloc(1, frame_size); |
1423 | + if (!frame) |
1424 | + return 0; |
1425 | + |
1426 | + frame->ongoing = calloc(nslot, sizeof(frame->ongoing[0])); |
1427 | + frame->slots = create_slots(nslot, ntouch, slot_size); |
1428 | + if (!frame->ongoing || !frame->slots) |
1429 | + goto out; |
1430 | + |
1431 | + return frame; |
1432 | + out: |
1433 | + destroy_frame(frame, nslot); |
1434 | + return 0; |
1435 | +} |
1436 | + |
1437 | +static struct grail_frame **create_frames(int nframe, int nslot, int ntouch, |
1438 | + int frame_size, int slot_size) |
1439 | +{ |
1440 | + struct grail_frame **frames; |
1441 | + struct grail_frame *f; |
1442 | + int i; |
1443 | + |
1444 | + frames = calloc(nframe, sizeof(frames[0])); |
1445 | + if (!frames) |
1446 | + return 0; |
1447 | + |
1448 | + for (i = 0; i < nframe; i++) { |
1449 | + f = create_frame(nslot, ntouch, frame_size, slot_size); |
1450 | + if (!f) |
1451 | + goto out; |
1452 | + frames[i] = f; |
1453 | + } |
1454 | + |
1455 | + return frames; |
1456 | + out: |
1457 | + destroy_frames(frames, nframe, nslot); |
1458 | + return 0; |
1459 | +} |
1460 | + |
1461 | +int create_grail2(struct grail_impl *x, |
1462 | + utouch_frame_handle fh, |
1463 | + unsigned int num_frames, |
1464 | + grail_select_callback select, |
1465 | + unsigned int version, |
1466 | + unsigned int control_size, |
1467 | + unsigned int frame_size, |
1468 | + unsigned int slot_size) |
1469 | +{ |
1470 | + struct utouch_surface *s = utouch_frame_get_surface(fh); |
1471 | + unsigned int ntouch = utouch_frame_get_num_slots(fh); |
1472 | + unsigned int nslot = get_slot_count(ntouch); |
1473 | + int i, j; |
1474 | + |
1475 | + x->select = select; |
1476 | + x->control_size = MAX(control_size, sizeof(struct grail_control)); |
1477 | + x->frame_size = MAX(frame_size, sizeof(struct grail_frame)); |
1478 | + x->slot_size = MAX(slot_size, sizeof(struct grail_element)); |
1479 | + |
1480 | + x->num_frames = num_frames; |
1481 | + x->num_slots = nslot; |
1482 | + x->num_touches = ntouch; |
1483 | + |
1484 | + x->ctl = create_control(x->control_size); |
1485 | + if (!x->ctl) |
1486 | + goto freemem; |
1487 | + |
1488 | + x->frames = create_frames(num_frames, nslot, ntouch, |
1489 | + x->frame_size, x->slot_size); |
1490 | + if (!x->frames) |
1491 | + goto freemem; |
1492 | + |
1493 | + for (i = 0; i < num_frames; i++) |
1494 | + x->frames[(i + 1) % num_frames]->prev = x->frames[i]; |
1495 | + |
1496 | + return 0; |
1497 | + |
1498 | + freemem: |
1499 | + destroy_grail2(x); |
1500 | + return -ENOMEM; |
1501 | +} |
1502 | + |
1503 | +void destroy_grail2(struct grail_impl *x) |
1504 | +{ |
1505 | + destroy_frames(x->frames, x->num_frames, x->num_slots); |
1506 | + free(x->ctl); |
1507 | +} |
1508 | + |
1509 | +grail_handle grail_new_raw(utouch_frame_handle fh, |
1510 | + unsigned int num_frames, |
1511 | + grail_select_callback select, |
1512 | + unsigned int version, |
1513 | + unsigned int control_size, |
1514 | + unsigned int frame_size, |
1515 | + unsigned int slot_size) |
1516 | +{ |
1517 | + struct grail *ge; |
1518 | + struct grail_impl *x; |
1519 | + |
1520 | + ge = calloc(1, sizeof(*ge)); |
1521 | + if (!ge) |
1522 | + return 0; |
1523 | + x = calloc(1, sizeof(*x)); |
1524 | + if (!x) |
1525 | + goto out; |
1526 | + x->fh = fh; |
1527 | + if (create_grail2(x, fh, num_frames, select, |
1528 | + version, control_size, frame_size, slot_size)) |
1529 | + goto out; |
1530 | + |
1531 | + ge->impl = x; |
1532 | + return ge; |
1533 | + |
1534 | + out: |
1535 | + free(x); |
1536 | + free(ge); |
1537 | + return 0; |
1538 | +} |
1539 | + |
1540 | +void grail_delete(grail_handle ge) |
1541 | +{ |
1542 | + destroy_grail2(ge->impl); |
1543 | + free(ge->impl); |
1544 | + free(ge); |
1545 | +} |
1546 | + |
1547 | +struct grail_control *grail_get_control(grail_handle ge) |
1548 | +{ |
1549 | + return ge->impl->ctl; |
1550 | +} |
1551 | |
1552 | === modified file 'src/grail-inserter.c' |
1553 | --- src/grail-inserter.c 2011-03-28 20:04:20 +0000 |
1554 | +++ src/grail-inserter.c 2011-03-29 08:01:03 +0000 |
1555 | @@ -2,8 +2,7 @@ |
1556 | * |
1557 | * grail - Gesture Recognition And Instantiation Library |
1558 | * |
1559 | - * Copyright (C) 2010 Canonical Ltd. |
1560 | - * Copyright (C) 2010 Henrik Rydberg <rydberg@bitmath.org> |
1561 | + * Copyright (C) 2010-2011 Canonical Ltd. |
1562 | * |
1563 | * This program is free software: you can redistribute it and/or modify it |
1564 | * under the terms of the GNU General Public License as published by the |
1565 | |
1566 | === modified file 'src/grail-inserter.h' |
1567 | --- src/grail-inserter.h 2011-03-28 20:04:20 +0000 |
1568 | +++ src/grail-inserter.h 2011-03-29 08:01:03 +0000 |
1569 | @@ -2,8 +2,7 @@ |
1570 | * |
1571 | * grail - Gesture Recognition And Instantiation Library |
1572 | * |
1573 | - * Copyright (C) 2010 Canonical Ltd. |
1574 | - * Copyright (C) 2010 Henrik Rydberg <rydberg@bitmath.org> |
1575 | + * Copyright (C) 2010-2011 Canonical Ltd. |
1576 | * |
1577 | * This program is free software: you can redistribute it and/or modify it |
1578 | * under the terms of the GNU General Public License as published by the |
1579 | |
1580 | === added file 'src/grail-legacy.c' |
1581 | --- src/grail-legacy.c 1970-01-01 00:00:00 +0000 |
1582 | +++ src/grail-legacy.c 2011-03-29 08:01:03 +0000 |
1583 | @@ -0,0 +1,65 @@ |
1584 | +/***************************************************************************** |
1585 | + * |
1586 | + * grail - Gesture Recognition And Instantiation Library |
1587 | + * |
1588 | + * Copyright (C) 2010-2011 Canonical Ltd. |
1589 | + * |
1590 | + * This program is free software: you can redistribute it and/or modify it |
1591 | + * under the terms of the GNU General Public License as published by the |
1592 | + * Free Software Foundation, either version 3 of the License, or (at your |
1593 | + * option) any later version. |
1594 | + * |
1595 | + * This program is distributed in the hope that it will be useful, but |
1596 | + * WITHOUT ANY WARRANTY; without even the implied warranty of |
1597 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
1598 | + * General Public License for more details. |
1599 | + * |
1600 | + * You should have received a copy of the GNU General Public License along |
1601 | + * with this program. If not, see <http://www.gnu.org/licenses/>. |
1602 | + * |
1603 | + ****************************************************************************/ |
1604 | + |
1605 | +#include <grail.h> |
1606 | +#include "grail-inserter.h" |
1607 | +#include <string.h> |
1608 | +#include <stdio.h> |
1609 | +#include <unistd.h> |
1610 | +#include <fcntl.h> |
1611 | +#include <malloc.h> |
1612 | +#include <errno.h> |
1613 | +#include <stdlib.h> |
1614 | + |
1615 | +#ifndef GRAIL_NO_LEGACY_ABI |
1616 | + |
1617 | +void grail_filter_abs_events(struct grail *ge, int usage) |
1618 | +{ |
1619 | + struct grail_impl *x = ge->impl; |
1620 | + x->filter_abs = usage; |
1621 | +} |
1622 | + |
1623 | +int grail_get_contacts(const struct grail *ge, |
1624 | + struct grail_contact *touch, int max_touch) |
1625 | +{ |
1626 | + const struct gesture_inserter *gin = ge->gin; |
1627 | + const struct utouch_frame *frame = ge->impl->touch; |
1628 | + int i; |
1629 | + if (frame->num_active < max_touch) |
1630 | + max_touch = frame->num_active; |
1631 | + for (i = 0; i < max_touch; i++) { |
1632 | + struct grail_contact *t = &touch[i]; |
1633 | + const struct utouch_contact *ct = frame->active[i]; |
1634 | + t->id = ct->id; |
1635 | + t->tool_type = ct->tool_type; |
1636 | + t->pos.x = ct->x; |
1637 | + t->pos.y = ct->y; |
1638 | + t->touch_major = ct->touch_major; |
1639 | + t->touch_minor = ct->touch_minor; |
1640 | + t->width_major = ct->width_major; |
1641 | + t->width_minor = ct->width_minor; |
1642 | + t->angle = ct->orientation; |
1643 | + t->pressure = ct->pressure; |
1644 | + } |
1645 | + return max_touch; |
1646 | +} |
1647 | + |
1648 | +#endif |
1649 | |
1650 | === modified file 'src/grail-recognizer.c' |
1651 | --- src/grail-recognizer.c 2011-03-28 20:04:07 +0000 |
1652 | +++ src/grail-recognizer.c 2011-03-29 08:01:03 +0000 |
1653 | @@ -2,8 +2,7 @@ |
1654 | * |
1655 | * grail - Gesture Recognition And Instantiation Library |
1656 | * |
1657 | - * Copyright (C) 2010 Canonical Ltd. |
1658 | - * Copyright (C) 2010 Henrik Rydberg <rydberg@bitmath.org> |
1659 | + * Copyright (C) 2010-2011 Canonical Ltd. |
1660 | * |
1661 | * This program is free software: you can redistribute it and/or modify it |
1662 | * under the terms of the GNU General Public License as published by the |
1663 | |
1664 | === modified file 'src/grail-recognizer.h' |
1665 | --- src/grail-recognizer.h 2011-03-28 20:04:07 +0000 |
1666 | +++ src/grail-recognizer.h 2011-03-29 08:01:03 +0000 |
1667 | @@ -2,8 +2,7 @@ |
1668 | * |
1669 | * grail - Gesture Recognition And Instantiation Library |
1670 | * |
1671 | - * Copyright (C) 2010 Canonical Ltd. |
1672 | - * Copyright (C) 2010 Henrik Rydberg <rydberg@bitmath.org> |
1673 | + * Copyright (C) 2010-2011 Canonical Ltd. |
1674 | * |
1675 | * This program is free software: you can redistribute it and/or modify it |
1676 | * under the terms of the GNU General Public License as published by the |
1677 | |
1678 | === modified file 'src/grailbuf.h' |
1679 | --- src/grailbuf.h 2011-01-02 12:06:56 +0000 |
1680 | +++ src/grailbuf.h 2011-03-29 08:01:03 +0000 |
1681 | @@ -2,8 +2,7 @@ |
1682 | * |
1683 | * grail - Gesture Recognition And Instantiation Library |
1684 | * |
1685 | - * Copyright (C) 2010 Canonical Ltd. |
1686 | - * Copyright (C) 2010 Henrik Rydberg <rydberg@bitmath.org> |
1687 | + * Copyright (C) 2010-2011 Canonical Ltd. |
1688 | * |
1689 | * This program is free software: you can redistribute it and/or modify it |
1690 | * under the terms of the GNU General Public License as published by the |
1691 | |
1692 | === modified file 'test/Makefile.am' |
1693 | --- test/Makefile.am 2011-03-17 09:47:52 +0000 |
1694 | +++ test/Makefile.am 2011-03-29 08:01:03 +0000 |
1695 | @@ -9,6 +9,7 @@ |
1696 | |
1697 | check_grail_SOURCES = \ |
1698 | check-mapping.c \ |
1699 | + check-transform.c \ |
1700 | check-grail.c |
1701 | |
1702 | check_grail_CFLAGS = \ |
1703 | |
1704 | === modified file 'test/check-grail.c' |
1705 | --- test/check-grail.c 2011-03-17 09:47:52 +0000 |
1706 | +++ test/check-grail.c 2011-03-29 08:01:03 +0000 |
1707 | @@ -3,6 +3,7 @@ |
1708 | #define LOGFILE_PREFIX "" |
1709 | |
1710 | extern Suite *make_mapping_suite(); |
1711 | +extern Suite *make_transform_suite(); |
1712 | |
1713 | int main(int argc CK_ATTRIBUTE_UNUSED, char* argv[] CK_ATTRIBUTE_UNUSED) |
1714 | { |
1715 | @@ -11,6 +12,7 @@ |
1716 | int num_failed; |
1717 | |
1718 | srunner_add_suite(sr, make_mapping_suite()); |
1719 | + srunner_add_suite(sr, make_transform_suite()); |
1720 | |
1721 | srunner_set_log(sr, "check_grail.log"); |
1722 | srunner_set_xml(sr, "check_grail.xml"); |
1723 | |
1724 | === added file 'test/check-transform.c' |
1725 | --- test/check-transform.c 1970-01-01 00:00:00 +0000 |
1726 | +++ test/check-transform.c 2011-03-29 08:01:03 +0000 |
1727 | @@ -0,0 +1,137 @@ |
1728 | +#include <check.h> |
1729 | +#include <utouch/frame-mtdev.h> |
1730 | +#include <grail.h> |
1731 | +#include <string.h> |
1732 | +#include <stdio.h> |
1733 | +#include <unistd.h> |
1734 | +#include <fcntl.h> |
1735 | +#include <stdlib.h> |
1736 | +#include <time.h> |
1737 | +#include <math.h> |
1738 | + |
1739 | +struct test_data { |
1740 | + struct evemu_device *evemu; |
1741 | + utouch_frame_handle fh; |
1742 | + grail_handle ge; |
1743 | + FILE *fp; |
1744 | + struct timeval evtime; |
1745 | +}; |
1746 | + |
1747 | +static int near(const struct grail_coord *p, float x, float y) |
1748 | +{ |
1749 | + double dx = p->x - x; |
1750 | + double dy = p->y - y; |
1751 | + return dx * dx + dy * dy < 1e-8 * (x * x + y * y); |
1752 | +} |
1753 | + |
1754 | +static int init_test_data(struct test_data *data, const char *path) |
1755 | +{ |
1756 | + memset(data, 0, sizeof(*data)); |
1757 | + |
1758 | + data->fp = fopen(path, "r"); |
1759 | + if (!data->fp) |
1760 | + return -1; |
1761 | + |
1762 | + data->evemu = evemu_new(NULL); |
1763 | + if (!data->evemu || evemu_read(data->evemu, data->fp) <= 0) |
1764 | + return -1; |
1765 | + |
1766 | + data->fh = utouch_frame_new_engine(100, 32, 100); |
1767 | + if (!data->fh || utouch_frame_init_mtdev(data->fh, data->evemu)) |
1768 | + return -1; |
1769 | + |
1770 | + data->ge = grail_new(data->fh, 10, 0); |
1771 | + if (!data->ge) |
1772 | + return -1; |
1773 | + |
1774 | + return 0; |
1775 | +} |
1776 | + |
1777 | +static void term_test_data(struct test_data *data) |
1778 | +{ |
1779 | + grail_delete(data->ge); |
1780 | + utouch_frame_delete_engine(data->fh); |
1781 | + evemu_delete(data->evemu); |
1782 | + fclose(data->fp); |
1783 | +} |
1784 | + |
1785 | +static int get_event(struct test_data *data, struct input_event *ev) |
1786 | +{ |
1787 | + return evemu_read_event_realtime(data->fp, ev, &data->evtime) > 0; |
1788 | +} |
1789 | + |
1790 | +static const struct grail_element *get_element(struct test_data *data, |
1791 | + const struct input_event *ev) |
1792 | +{ |
1793 | + const struct utouch_frame *touch; |
1794 | + const struct grail_frame *frame; |
1795 | + |
1796 | + touch = utouch_frame_pump_mtdev(data->fh, ev); |
1797 | + if (!touch) |
1798 | + return 0; |
1799 | + frame = grail_pump_frame(data->ge, touch); |
1800 | + if (!frame || !frame->num_ongoing) |
1801 | + return 0; |
1802 | + |
1803 | + return frame->ongoing[frame->num_ongoing - 1]; |
1804 | +} |
1805 | + |
1806 | +START_TEST(device_coordinates) |
1807 | +{ |
1808 | + struct test_data data; |
1809 | + struct input_event ev; |
1810 | + const struct grail_element *slot; |
1811 | + struct grail_coord pos = { 0, 0 }; |
1812 | + |
1813 | + fail_if(init_test_data(&data, "io/evemu/one-tap.evemu")); |
1814 | + |
1815 | + while (get_event(&data, &ev)) { |
1816 | + slot = get_element(&data, &ev); |
1817 | + if (slot) |
1818 | + pos = slot->center; |
1819 | + } |
1820 | + |
1821 | + fail_unless(near(&pos, 17087, 14790)); |
1822 | + |
1823 | + term_test_data(&data); |
1824 | +} |
1825 | +END_TEST |
1826 | + |
1827 | +START_TEST(mapped_coordinates) |
1828 | +{ |
1829 | + static const struct grail_coord min = { 0, 0 }, max = { 1.6, 1 }; |
1830 | + struct test_data data; |
1831 | + struct input_event ev; |
1832 | + const struct grail_element *slot; |
1833 | + struct grail_coord pos = { 0, 0 }; |
1834 | + |
1835 | + fail_if(init_test_data(&data, "io/evemu/one-tap.evemu")); |
1836 | + grail_set_bbox(data.ge, &min, &max); |
1837 | + |
1838 | + while (get_event(&data, &ev)) { |
1839 | + slot = get_element(&data, &ev); |
1840 | + if (slot) |
1841 | + pos = slot->center; |
1842 | + } |
1843 | + |
1844 | + fail_unless(near(&pos, 0.834303, 0.451338)); |
1845 | + |
1846 | + term_test_data(&data); |
1847 | +} |
1848 | +END_TEST |
1849 | + |
1850 | +Suite *make_transform_suite() |
1851 | +{ |
1852 | + Suite *s = suite_create("grail-solver"); |
1853 | + TCase *test; |
1854 | + |
1855 | + test = tcase_create("device_coordinates"); |
1856 | + tcase_add_test(test, device_coordinates); |
1857 | + suite_add_tcase(s, test); |
1858 | + |
1859 | + test = tcase_create("mapped_coordinates"); |
1860 | + tcase_add_test(test, mapped_coordinates); |
1861 | + suite_add_tcase(s, test); |
1862 | + |
1863 | + return s; |
1864 | +} |
1865 | |
1866 | === modified file 'tools/Makefile.am' |
1867 | --- tools/Makefile.am 2011-01-02 12:08:08 +0000 |
1868 | +++ tools/Makefile.am 2011-03-29 08:01:03 +0000 |
1869 | @@ -1,7 +1,15 @@ |
1870 | -bin_PROGRAMS = grail-gesture |
1871 | +bin_PROGRAMS = grail-gesture grail-test-mtdev |
1872 | + |
1873 | +if HAVE_XI |
1874 | + |
1875 | +bin_PROGRAMS += grail-transform |
1876 | + |
1877 | +endif |
1878 | |
1879 | INCLUDES=-I$(top_srcdir)/include/ |
1880 | |
1881 | -grail_gesture_SOURCES = grail-gesture.c |
1882 | -grail_gesture_LDFLAGS = -L$(top_builddir)/src/.libs/ \ |
1883 | - -lutouch-grail -lutouch-frame -lutouch-evemu -lmtdev -lm |
1884 | +AM_CFLAGS = $(X11_CFLAGS) $(XINPUT_CFLAGS) |
1885 | + |
1886 | +AM_LDFLAGS = -L$(top_builddir)/src/.libs/ \ |
1887 | + -lutouch-grail -lutouch-frame -lutouch-evemu -lmtdev \ |
1888 | + $(X11_LIBS) $(XINPUT_LIBS) -lm |
1889 | |
1890 | === modified file 'tools/grail-gesture.c' |
1891 | --- tools/grail-gesture.c 2011-03-17 09:46:39 +0000 |
1892 | +++ tools/grail-gesture.c 2011-03-29 08:01:03 +0000 |
1893 | @@ -2,7 +2,7 @@ |
1894 | * |
1895 | * grail - Gesture Recognition And Instantiation Library |
1896 | * |
1897 | - * Copyright (C) 2010 Canonical Ltd. |
1898 | + * Copyright (C) 2010-2011 Canonical Ltd. |
1899 | * |
1900 | * This program is free software: you can redistribute it and/or modify it |
1901 | * under the terms of the GNU General Public License as published by the |
1902 | @@ -17,9 +17,6 @@ |
1903 | * You should have received a copy of the GNU General Public License along |
1904 | * with this program. If not, see <http://www.gnu.org/licenses/>. |
1905 | * |
1906 | - * Authors: |
1907 | - * Henrik Rydberg <rydberg@bitmath.org> |
1908 | - * |
1909 | ****************************************************************************/ |
1910 | |
1911 | #include <grail.h> |
1912 | |
1913 | === added file 'tools/grail-test-mtdev.c' |
1914 | --- tools/grail-test-mtdev.c 1970-01-01 00:00:00 +0000 |
1915 | +++ tools/grail-test-mtdev.c 2011-03-29 08:01:03 +0000 |
1916 | @@ -0,0 +1,256 @@ |
1917 | +/***************************************************************************** |
1918 | + * |
1919 | + * grail - Gesture Recognition And Instantiation Library |
1920 | + * |
1921 | + * Copyright (C) 2010-2011 Canonical Ltd. |
1922 | + * |
1923 | + * This program is free software: you can redistribute it and/or modify it |
1924 | + * under the terms of the GNU General Public License as published by the |
1925 | + * Free Software Foundation, either version 3 of the License, or (at your |
1926 | + * option) any later version. |
1927 | + * |
1928 | + * This program is distributed in the hope that it will be useful, but |
1929 | + * WITHOUT ANY WARRANTY; without even the implied warranty of |
1930 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
1931 | + * General Public License for more details. |
1932 | + * |
1933 | + * You should have received a copy of the GNU General Public License along |
1934 | + * with this program. If not, see <http://www.gnu.org/licenses/>. |
1935 | + * |
1936 | + ****************************************************************************/ |
1937 | + |
1938 | +#define MTDEV_NO_LEGACY_API |
1939 | + |
1940 | +#include <utouch/frame-mtdev.h> |
1941 | +#include <grail.h> |
1942 | +#include <string.h> |
1943 | +#include <stdio.h> |
1944 | +#include <unistd.h> |
1945 | +#include <fcntl.h> |
1946 | +#include <math.h> |
1947 | + |
1948 | +struct frame_test { |
1949 | + struct evemu_device *evemu; |
1950 | + struct mtdev *mtdev; |
1951 | + utouch_frame_handle fh; |
1952 | + grail_handle ge; |
1953 | +}; |
1954 | + |
1955 | +static int init_evemu(struct frame_test *test, FILE *fp, int fd) |
1956 | +{ |
1957 | + test->evemu = evemu_new(NULL); |
1958 | + if (!test->evemu) |
1959 | + return -1; |
1960 | + if (fp) |
1961 | + return evemu_read(test->evemu, fp) <= 0; |
1962 | + else |
1963 | + return evemu_extract(test->evemu, fd); |
1964 | +} |
1965 | + |
1966 | +static int init_mtdev(struct frame_test *test, int fd) |
1967 | +{ |
1968 | + test->mtdev = mtdev_new_open(fd); |
1969 | + if (!test->mtdev) |
1970 | + return -1; |
1971 | + return 0; |
1972 | +} |
1973 | + |
1974 | +static int init_frame(struct frame_test *test, int fd) |
1975 | +{ |
1976 | + test->fh = utouch_frame_new_engine(100, 32, 100); |
1977 | + if (!test->fh) |
1978 | + return -1; |
1979 | + return utouch_frame_init_mtdev(test->fh, test->evemu); |
1980 | +} |
1981 | + |
1982 | +static int init_grail(struct frame_test *test) |
1983 | +{ |
1984 | + struct grail_coord min = { 0, 0 }; |
1985 | + struct grail_coord max = { 1, 1 }; |
1986 | + test->ge = grail_new(test->fh, 10, 0); |
1987 | + if (!test->ge) |
1988 | + return -1; |
1989 | + grail_set_bbox(test->ge, &min, &max); |
1990 | + return 0; |
1991 | +} |
1992 | + |
1993 | +static void destroy_all(struct frame_test *test) |
1994 | +{ |
1995 | + grail_delete(test->ge); |
1996 | + utouch_frame_delete_engine(test->fh); |
1997 | + if (test->mtdev) |
1998 | + mtdev_close_delete(test->mtdev); |
1999 | + evemu_delete(test->evemu); |
2000 | + memset(test, 0, sizeof(*test)); |
2001 | +} |
2002 | + |
2003 | +static void report_frame(grail_handle ge, |
2004 | + const struct utouch_frame *touch) |
2005 | +{ |
2006 | + const struct grail_frame *frame = grail_pump_frame(ge, touch); |
2007 | + int i; |
2008 | + |
2009 | + if (!frame) |
2010 | + return; |
2011 | + |
2012 | + fprintf(stderr, "ongoing elements: %d\n", frame->num_ongoing); |
2013 | + |
2014 | + for (i = 0; i < frame->num_ongoing; i++) { |
2015 | + const struct grail_element *slot = frame->ongoing[i]; |
2016 | + if (!slot->active_mask) |
2017 | + continue; |
2018 | + |
2019 | + fprintf(stderr, " element %d\n", i); |
2020 | + fprintf(stderr, " slot: %d\n", slot->slot); |
2021 | + fprintf(stderr, " id: %d\n", slot->id); |
2022 | + fprintf(stderr, " num_touches: %d\n", slot->num_touches); |
2023 | + fprintf(stderr, " expect: %d\n", slot->expect_mask); |
2024 | + fprintf(stderr, " active: %d\n", slot->active_mask); |
2025 | + fprintf(stderr, " start time: %ld\n", slot->start_time); |
2026 | + fprintf(stderr, " center.x: %f\n", slot->center.x); |
2027 | + fprintf(stderr, " center.y: %f\n", slot->center.y); |
2028 | + fprintf(stderr, " velocity.x: %f\n", slot->velocity.x); |
2029 | + fprintf(stderr, " velocity.y: %f\n", slot->velocity.y); |
2030 | + fprintf(stderr, " radius2: %f\n", slot->radius2); |
2031 | + fprintf(stderr, " %+08f %+08f %+08f\n" |
2032 | + " %+08f %+08f %+08f\n" |
2033 | + " %+08f %+08f %+08f\n", |
2034 | + slot->transform[0], slot->transform[1], |
2035 | + slot->transform[2], slot->transform[3], |
2036 | + slot->transform[4], slot->transform[5], |
2037 | + slot->transform[6], slot->transform[7], |
2038 | + slot->transform[8]); |
2039 | + fprintf(stderr, " moveness: %f\n", slot->moveness); |
2040 | + fprintf(stderr, " pivot.x: %f\n", slot->pivot.x); |
2041 | + fprintf(stderr, " pivot.y: %f\n", slot->pivot.y); |
2042 | + fprintf(stderr, " drag.x: %f\n", slot->drag.x); |
2043 | + fprintf(stderr, " drag.y: %f\n", slot->drag.y); |
2044 | + fprintf(stderr, " scale2: %f\n", slot->scale2); |
2045 | + fprintf(stderr, " angle: %f\n", slot->angle); |
2046 | + } |
2047 | +} |
2048 | + |
2049 | +static void loop_device(struct frame_test *test, FILE *fp, int fd) |
2050 | +{ |
2051 | + const struct utouch_frame *frame; |
2052 | + struct input_event ev; |
2053 | + |
2054 | + if (fp) { |
2055 | + struct timeval evtime; |
2056 | + memset(&evtime, 0, sizeof(evtime)); |
2057 | + while (evemu_read_event_realtime(fp, &ev, &evtime) > 0) { |
2058 | + frame = utouch_frame_pump_mtdev(test->fh, &ev); |
2059 | + if (frame) |
2060 | + report_frame(test->ge, frame); |
2061 | + } |
2062 | + } else { |
2063 | + while (!mtdev_idle(test->mtdev, fd, 5000)) { |
2064 | + while (mtdev_get(test->mtdev, fd, &ev, 1) > 0) { |
2065 | + frame = utouch_frame_pump_mtdev(test->fh, &ev); |
2066 | + if (frame) |
2067 | + report_frame(test->ge, frame); |
2068 | + } |
2069 | + } |
2070 | + } |
2071 | +} |
2072 | + |
2073 | +static void report_device_caps(struct frame_test *test) |
2074 | +{ |
2075 | + const struct utouch_surface *s = utouch_frame_get_surface(test->fh); |
2076 | + |
2077 | + fprintf(stderr, "device props:\n"); |
2078 | + if (s->needs_pointer) |
2079 | + fprintf(stderr, "\tpointer\n"); |
2080 | + if (s->is_direct) |
2081 | + fprintf(stderr, "\tdirect\n"); |
2082 | + if (s->is_buttonpad) |
2083 | + fprintf(stderr, "\tbuttonpad\n"); |
2084 | + if (s->is_semi_mt) |
2085 | + fprintf(stderr, "\tsemi_mt\n"); |
2086 | + fprintf(stderr, "device mt events:\n"); |
2087 | + if (s->use_touch_major) |
2088 | + fprintf(stderr, "\ttouch_major\n"); |
2089 | + if (s->use_touch_minor) |
2090 | + fprintf(stderr, "\ttouch_minor\n"); |
2091 | + if (s->use_width_major) |
2092 | + fprintf(stderr, "\twidth_major\n"); |
2093 | + if (s->use_width_minor) |
2094 | + fprintf(stderr, "\twidth_minor\n"); |
2095 | + if (s->use_orientation) |
2096 | + fprintf(stderr, "\torientation\n"); |
2097 | + if (s->use_pressure) |
2098 | + fprintf(stderr, "\tpressure\n"); |
2099 | + if (s->use_distance) |
2100 | + fprintf(stderr, "\tdistance\n"); |
2101 | + |
2102 | + fprintf(stderr, "touch frames: %d\n", |
2103 | + utouch_frame_get_num_frames(test->fh)); |
2104 | + fprintf(stderr, "touch slots: %d\n", |
2105 | + utouch_frame_get_num_slots(test->fh)); |
2106 | +} |
2107 | + |
2108 | +int main(int argc, char *argv[]) |
2109 | +{ |
2110 | + struct frame_test test; |
2111 | + struct stat fs; |
2112 | + FILE *fp = 0; |
2113 | + int fd; |
2114 | + |
2115 | + if (argc < 2) { |
2116 | + fprintf(stderr, "Usage: %s <device>\n", argv[0]); |
2117 | + return -1; |
2118 | + } |
2119 | + |
2120 | + memset(&test, 0, sizeof(test)); |
2121 | + |
2122 | + fd = open(argv[1], O_RDONLY | O_NONBLOCK); |
2123 | + if (fd < 0) { |
2124 | + fprintf(stderr, "error: could not open device\n"); |
2125 | + return -1; |
2126 | + } |
2127 | + if (fstat(fd, &fs)) { |
2128 | + fprintf(stderr, "error: could not stat the device\n"); |
2129 | + return -1; |
2130 | + } |
2131 | + if (!fs.st_rdev) |
2132 | + fp = fdopen(fd, "r"); |
2133 | + |
2134 | + if (!fp && ioctl(fd, EVIOCGRAB, 1)) { |
2135 | + fprintf(stderr, "error: could not grab the device\n"); |
2136 | + return -1; |
2137 | + } |
2138 | + |
2139 | + if (init_evemu(&test, fp, fd)) { |
2140 | + fprintf(stderr, "error: could not describe device\n"); |
2141 | + return -1; |
2142 | + } |
2143 | + if (!utouch_frame_is_supported_mtdev(test.evemu)) { |
2144 | + fprintf(stderr, "error: unsupported device\n"); |
2145 | + return -1; |
2146 | + } |
2147 | + |
2148 | + fprintf(stderr, "device: %s\n", evemu_get_name(test.evemu)); |
2149 | + |
2150 | + if (!fp && init_mtdev(&test, fd)) { |
2151 | + fprintf(stderr, "error: could not init mtdev\n"); |
2152 | + return -1; |
2153 | + } |
2154 | + if (init_frame(&test, fd)) { |
2155 | + fprintf(stderr, "error: could not init frame\n"); |
2156 | + return -1; |
2157 | + } |
2158 | + if (init_grail(&test)) { |
2159 | + fprintf(stderr, "error: could not init grail\n"); |
2160 | + return -1; |
2161 | + } |
2162 | + |
2163 | + report_device_caps(&test); |
2164 | + |
2165 | + loop_device(&test, fp, fd); |
2166 | + |
2167 | + destroy_all(&test); |
2168 | + |
2169 | + if (fs.st_rdev) |
2170 | + ioctl(fd, EVIOCGRAB, 0); |
2171 | + return 0; |
2172 | +} |
2173 | |
2174 | === added file 'tools/grail-transform.c' |
2175 | --- tools/grail-transform.c 1970-01-01 00:00:00 +0000 |
2176 | +++ tools/grail-transform.c 2011-03-29 08:01:03 +0000 |
2177 | @@ -0,0 +1,374 @@ |
2178 | +/***************************************************************************** |
2179 | + * |
2180 | + * grail - Gesture Recognition And Instantiation Library |
2181 | + * |
2182 | + * Copyright (C) 2010-2011 Canonical Ltd. |
2183 | + * |
2184 | + * This program is free software: you can redistribute it and/or modify it |
2185 | + * under the terms of the GNU General Public License as published by the |
2186 | + * Free Software Foundation, either version 3 of the License, or (at your |
2187 | + * option) any later version. |
2188 | + * |
2189 | + * This program is distributed in the hope that it will be useful, but |
2190 | + * WITHOUT ANY WARRANTY; without even the implied warranty of |
2191 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
2192 | + * General Public License for more details. |
2193 | + * |
2194 | + * You should have received a copy of the GNU General Public License along |
2195 | + * with this program. If not, see <http://www.gnu.org/licenses/>. |
2196 | + * |
2197 | + ****************************************************************************/ |
2198 | + |
2199 | +#include "config.h" |
2200 | +#include <evemu.h> |
2201 | +#include <utouch/frame-mtdev.h> |
2202 | +#include <utouch/frame-xi2.h> |
2203 | +#include <grail.h> |
2204 | +#include <stdio.h> |
2205 | +#include <stdlib.h> |
2206 | +#include <unistd.h> |
2207 | +#include <fcntl.h> |
2208 | +#include <string.h> |
2209 | +#include <math.h> |
2210 | + |
2211 | +struct appdata { |
2212 | + int opcode; |
2213 | + struct grail_coord min, max; |
2214 | + int fd; |
2215 | + struct evemu_device *evemu; |
2216 | + struct mtdev *mtdev; |
2217 | + utouch_frame_handle fh; |
2218 | + struct grail *ge; |
2219 | + |
2220 | + struct grail_coord pos[4]; |
2221 | + struct grail_coord touch[32]; |
2222 | + struct grail_coord pivot; |
2223 | + XPoint pts[5]; |
2224 | + int scaling; |
2225 | + int ntouch; |
2226 | + |
2227 | + Display *dsp; |
2228 | + Window win; |
2229 | + GC gc; |
2230 | + int screen; |
2231 | + float off_x, off_y; |
2232 | + unsigned long white, black; |
2233 | +}; |
2234 | + |
2235 | +static void clear_screen(struct appdata *w) |
2236 | +{ |
2237 | + const struct utouch_surface *s = utouch_frame_get_surface(w->fh); |
2238 | + int width = s->mapped_max_x - s->mapped_min_x; |
2239 | + int height = s->mapped_max_y - s->mapped_min_y; |
2240 | + int i; |
2241 | + |
2242 | + XSetForeground(w->dsp, w->gc, w->white); |
2243 | + XFillRectangle(w->dsp, w->win, w->gc, 0, 0, width, height); |
2244 | + |
2245 | + for (i = 0; i < 5; i++) { |
2246 | + w->pts[i].x = w->pos[i % 4].x - w->off_x; |
2247 | + w->pts[i].y = w->pos[i % 4].y - w->off_y; |
2248 | + } |
2249 | + |
2250 | + XSetForeground(w->dsp, w->gc, w->black); |
2251 | + XDrawLines(w->dsp, w->win, w->gc, w->pts, 5, CoordModeOrigin); |
2252 | + |
2253 | +} |
2254 | + |
2255 | +static void draw_object(struct appdata *w) |
2256 | +{ |
2257 | + static const double frac = 0.01; |
2258 | + const struct utouch_surface *s = utouch_frame_get_surface(w->fh); |
2259 | + double d = frac * (s->mapped_max_x - s->mapped_min_x); |
2260 | + int i; |
2261 | + |
2262 | + XDrawLines(w->dsp, w->win, w->gc, w->pts, 5, CoordModeOrigin); |
2263 | + |
2264 | + if (w->scaling) |
2265 | + XFillArc(w->dsp, w->win, w->gc, |
2266 | + w->pivot.x - d / 2, w->pivot.y - d / 2, |
2267 | + d, d, 0, 360 * 64); |
2268 | + |
2269 | + d *= 4; |
2270 | + for (i = 0; i < w->ntouch; i++) |
2271 | + XFillArc(w->dsp, w->win, w->gc, |
2272 | + w->touch[i].x - d / 2, w->touch[i].y - d / 2, |
2273 | + d, d, 0, 360 * 64); |
2274 | +} |
2275 | + |
2276 | +static void report_frame(struct appdata *w, |
2277 | + const struct utouch_frame *touch) |
2278 | +{ |
2279 | + const struct grail_control *ctl = grail_get_control(w->ge); |
2280 | + const struct grail_frame *frame; |
2281 | + const struct grail_element *slot; |
2282 | + struct grail_coord tmp; |
2283 | + int i; |
2284 | + |
2285 | + if (!touch) |
2286 | + return; |
2287 | + |
2288 | + frame = grail_pump_frame(w->ge, touch); |
2289 | + if (!frame || !frame->num_ongoing || !frame->prev->num_ongoing) |
2290 | + return; |
2291 | + |
2292 | + slot = frame->ongoing[frame->num_ongoing - 1]; |
2293 | + if (slot->transform[0] == 0 && slot->transform[1] == 0) |
2294 | + return; |
2295 | + |
2296 | + for (i = 0; i < 4; i++) { |
2297 | + grail_element_transform(slot, &tmp, &w->pos[i]); |
2298 | + w->pos[i] = tmp; |
2299 | + } |
2300 | + |
2301 | + XSetForeground(w->dsp, w->gc, w->white); |
2302 | + draw_object(w); |
2303 | + |
2304 | + w->ntouch = touch->num_active; |
2305 | + for (i = 0; i < w->ntouch; i++) { |
2306 | + w->touch[i].x = touch->active[i]->x - w->off_x; |
2307 | + w->touch[i].y = touch->active[i]->y - w->off_y; |
2308 | + } |
2309 | + |
2310 | + w->scaling = slot->moveness < ctl->thresh_scale; |
2311 | + w->pivot.x = slot->pivot.x - w->off_x; |
2312 | + w->pivot.y = slot->pivot.y - w->off_y; |
2313 | + |
2314 | + for (i = 0; i < 5; i++) { |
2315 | + w->pts[i].x = w->pos[i % 4].x - w->off_x; |
2316 | + w->pts[i].y = w->pos[i % 4].y - w->off_y; |
2317 | + } |
2318 | + |
2319 | + XSetForeground(w->dsp, w->gc, w->black); |
2320 | + draw_object(w); |
2321 | + |
2322 | + XFlush(w->dsp); |
2323 | +} |
2324 | + |
2325 | +static int init_window(struct appdata *w) |
2326 | +{ |
2327 | + int event, err; |
2328 | + |
2329 | + w->pos[0].x = 100; |
2330 | + w->pos[0].y = 100; |
2331 | + w->pos[1].x = 200; |
2332 | + w->pos[1].y = 100; |
2333 | + w->pos[2].x = 200; |
2334 | + w->pos[2].y = 200; |
2335 | + w->pos[3].x = 100; |
2336 | + w->pos[3].y = 200; |
2337 | + |
2338 | + w->dsp = XOpenDisplay(NULL); |
2339 | + if (!w->dsp) |
2340 | + return -1; |
2341 | + if (!XQueryExtension(w->dsp, "XInputExtension", |
2342 | + &w->opcode, &event, &err)) |
2343 | + return -1; |
2344 | + |
2345 | + w->screen = DefaultScreen(w->dsp); |
2346 | + w->white = WhitePixel(w->dsp, w->screen); |
2347 | + w->black = BlackPixel(w->dsp, w->screen); |
2348 | + |
2349 | + w->win = XCreateSimpleWindow(w->dsp, XDefaultRootWindow(w->dsp), |
2350 | + 0, 0, 600, 600, 0, w->black, w->white); |
2351 | + w->gc = DefaultGC(w->dsp, w->screen); |
2352 | + |
2353 | + XMapWindow(w->dsp, w->win); |
2354 | + XFlush(w->dsp); |
2355 | + |
2356 | + return 0; |
2357 | +} |
2358 | + |
2359 | +static void term_window(struct appdata *w) |
2360 | +{ |
2361 | + XDestroyWindow(w->dsp, w->win); |
2362 | + XCloseDisplay(w->dsp); |
2363 | +} |
2364 | + |
2365 | +static void set_screen_size_mtdev(struct appdata *w, XEvent *xev) |
2366 | +{ |
2367 | + struct utouch_surface *s = utouch_frame_get_surface(w->fh); |
2368 | + XConfigureEvent *cev = (XConfigureEvent *)xev; |
2369 | + |
2370 | + s->mapped_min_x = 0; |
2371 | + s->mapped_min_y = 0; |
2372 | + s->mapped_max_x = DisplayWidth(w->dsp, w->screen); |
2373 | + s->mapped_max_y = DisplayHeight(w->dsp, w->screen); |
2374 | + s->mapped_max_pressure = 1; |
2375 | + |
2376 | + if (cev) { |
2377 | + w->off_x = cev->x; |
2378 | + w->off_y = cev->y; |
2379 | + } |
2380 | +} |
2381 | + |
2382 | +static void loop_device_mtdev(struct appdata *w) |
2383 | +{ |
2384 | + const struct utouch_frame *tf; |
2385 | + struct input_event iev; |
2386 | + XEvent xev; |
2387 | + |
2388 | + clear_screen(w); |
2389 | + |
2390 | + set_screen_size_mtdev(w, 0); |
2391 | + XSelectInput(w->dsp, w->win, StructureNotifyMask); |
2392 | + |
2393 | + while (1) { |
2394 | + while (!mtdev_idle(w->mtdev, w->fd, 100)) { |
2395 | + while (mtdev_get(w->mtdev, w->fd, &iev, 1) > 0) { |
2396 | + tf = utouch_frame_pump_mtdev(w->fh, &iev); |
2397 | + report_frame(w, tf); |
2398 | + } |
2399 | + } |
2400 | + while (XPending(w->dsp)) { |
2401 | + XNextEvent(w->dsp, &xev); |
2402 | + set_screen_size_mtdev(w, &xev); |
2403 | + } |
2404 | + } |
2405 | +} |
2406 | + |
2407 | +static int run_mtdev(struct appdata *w, const char *path) |
2408 | +{ |
2409 | + w->fd = open(path, O_RDONLY | O_NONBLOCK); |
2410 | + if (w->fd < 0) { |
2411 | + fprintf(stderr, "error: could not open device\n"); |
2412 | + return -1; |
2413 | + } |
2414 | + if (ioctl(w->fd, EVIOCGRAB, 1)) { |
2415 | + fprintf(stderr, "error: could not grab the device\n"); |
2416 | + return -1; |
2417 | + } |
2418 | + |
2419 | + w->evemu = evemu_new(NULL); |
2420 | + if (!w->evemu) |
2421 | + return -1; |
2422 | + if (evemu_extract(w->evemu, w->fd)) |
2423 | + return -1; |
2424 | + w->mtdev = mtdev_new_open(w->fd); |
2425 | + if (!w->mtdev) |
2426 | + return -1; |
2427 | + w->fh = utouch_frame_new_engine(500, 32, 100); |
2428 | + if (!w->fh) |
2429 | + return -1; |
2430 | + if (utouch_frame_init_mtdev(w->fh, w->evemu)) |
2431 | + return -1; |
2432 | + w->ge = grail_new(w->fh, 100, 0); |
2433 | + if (!w->ge) |
2434 | + return -1; |
2435 | + |
2436 | + grail_get_control(w->ge)->drop_x_ms = 1e8; |
2437 | + grail_get_control(w->ge)->drop_y_ms = 1e8; |
2438 | + grail_get_control(w->ge)->drop_scale_ms = 1e8; |
2439 | + grail_get_control(w->ge)->drop_angle_ms = 1e8; |
2440 | + |
2441 | + loop_device_mtdev(w); |
2442 | + |
2443 | + grail_delete(w->ge); |
2444 | + utouch_frame_delete_engine(w->fh); |
2445 | + mtdev_close_delete(w->mtdev); |
2446 | + evemu_delete(w->evemu); |
2447 | + |
2448 | + ioctl(w->fd, EVIOCGRAB, 0); |
2449 | + close(w->fd); |
2450 | +} |
2451 | + |
2452 | +#if HAVE_XI |
2453 | +static void loop_device_xi2(struct appdata *w, int id) |
2454 | +{ |
2455 | + const struct utouch_frame *tf; |
2456 | + XIEventMask mask; |
2457 | + |
2458 | + mask.deviceid = id; |
2459 | + mask.mask_len = XIMaskLen(XI_LASTEVENT); |
2460 | + mask.mask = calloc(mask.mask_len, sizeof(char)); |
2461 | + |
2462 | + XISetMask(mask.mask, XI_TouchBegin); |
2463 | + XISetMask(mask.mask, XI_TouchUpdate); |
2464 | + XISetMask(mask.mask, XI_TouchEnd); |
2465 | + XISetMask(mask.mask, XI_PropertyEvent); |
2466 | + XISelectEvents(w->dsp, w->win, &mask, 1); |
2467 | + |
2468 | + XSelectInput(w->dsp, DefaultRootWindow(w->dsp), StructureNotifyMask); |
2469 | + |
2470 | + while (1) { |
2471 | + XEvent ev; |
2472 | + XIDeviceEvent *event = (void *)&ev; |
2473 | + XGenericEventCookie *cookie = &ev.xcookie; |
2474 | + XNextEvent(w->dsp, &ev); |
2475 | + |
2476 | + if (XGetEventData(w->dsp, cookie) && |
2477 | + cookie->type == GenericEvent && |
2478 | + cookie->extension == w->opcode) { |
2479 | + tf = utouch_frame_pump_xi2(w->fh, cookie->data); |
2480 | + report_frame(w, tf); |
2481 | + } |
2482 | + XFreeEventData(w->dsp, cookie); |
2483 | + } |
2484 | + |
2485 | +} |
2486 | + |
2487 | +static int run_xi2(struct appdata *w, int id) |
2488 | +{ |
2489 | + XIDeviceInfo *info, *dev; |
2490 | + int ndevices, i; |
2491 | + |
2492 | + info = XIQueryDevice(w->dsp, XIAllDevices, &ndevices); |
2493 | + dev = 0; |
2494 | + for (i = 0; i < ndevices; i++) |
2495 | + if (info[i].deviceid == id) |
2496 | + dev = &info[i]; |
2497 | + if (!dev) |
2498 | + return -1; |
2499 | + |
2500 | + w->fh = utouch_frame_new_engine(500, 32, 100); |
2501 | + if (!w->fh) |
2502 | + return -1; |
2503 | + if (utouch_frame_init_xi2(w->fh, w->dsp, dev)) |
2504 | + return -1; |
2505 | + w->ge = grail_new(w->fh, 100, 0); |
2506 | + if (!w->ge) |
2507 | + return -1; |
2508 | + |
2509 | + loop_device_xi2(w, id); |
2510 | + |
2511 | + grail_delete(w->ge); |
2512 | + utouch_frame_delete_engine(w->fh); |
2513 | + |
2514 | + XIFreeDeviceInfo(info); |
2515 | + |
2516 | + return 0; |
2517 | +} |
2518 | +#else |
2519 | +static int run_xi2(struct appdata *w, int id) |
2520 | +{ |
2521 | + fprintf(stderr, "X not supported in this build (use --with-xi)\n"); |
2522 | + return 0; |
2523 | +} |
2524 | +#endif |
2525 | + |
2526 | +int main(int argc, char **argv) |
2527 | +{ |
2528 | + struct appdata w; |
2529 | + int id, ret; |
2530 | + |
2531 | + if (argc < 2) { |
2532 | + fprintf(stderr, "Usage: %s <device>\n", argv[0]); |
2533 | + return -1; |
2534 | + } |
2535 | + |
2536 | + memset(&w, 0, sizeof(w)); |
2537 | + |
2538 | + if (init_window(&w)) |
2539 | + return -1; |
2540 | + |
2541 | + id = atoi(argv[1]); |
2542 | + |
2543 | + if (id) |
2544 | + ret = run_xi2(&w, id); |
2545 | + else |
2546 | + ret = run_mtdev(&w, argv[1]); |
2547 | + |
2548 | + term_window(&w); |
2549 | + |
2550 | + return ret; |
2551 | +} |
2552 | |
2553 | === modified file 'utouch-grail.sym.in' |
2554 | --- utouch-grail.sym.in 2011-01-02 12:08:42 +0000 |
2555 | +++ utouch-grail.sym.in 2011-03-29 08:01:03 +0000 |
2556 | @@ -1,13 +1,19 @@ |
2557 | grail_close |
2558 | +grail_delete |
2559 | grail_filter_abs_events |
2560 | +grail_get_contact_frame |
2561 | grail_get_contacts |
2562 | +grail_get_control |
2563 | grail_get_units |
2564 | +grail_get_version |
2565 | grail_idle |
2566 | grail_mask_clear_mask |
2567 | grail_mask_count |
2568 | grail_mask_get_first |
2569 | grail_mask_get_next |
2570 | grail_mask_set_mask |
2571 | +grail_new_raw |
2572 | grail_open |
2573 | grail_pull |
2574 | +grail_pump_frame |
2575 | grail_set_bbox |