Status: | Merged |
---|---|
Merged at revision: | 155 |
Proposed branch: | lp:~oif-team/grail/grail2 |
Merge into: | lp:grail |
Diff against target: |
2949 lines (+2320/-155) 36 files modified
AUTHORS (+1/-0) configure.ac (+8/-1) docs/gestures.txt (+58/-0) docs/pivot.txt (+146/-0) include/grail-bits.h (+1/-2) include/grail-types.h (+1/-2) include/grail.h (+254/-49) include/grail.h.orig (+277/-0) 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 (+17/-13) src/grail-bits.c (+1/-2) src/grail-event.c (+1/-27) src/grail-frame.c (+398/-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 (+371/-0) |
To merge this branch: | bzr merge lp:~oif-team/grail/grail2 |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Chase Douglas (community) | Approve | ||
Review via email: mp+59405@code.launchpad.net |
This proposal supersedes a proposal from 2011-04-12.
Commit message
Description of the change
New grail2 branch, rebased to current trunk. This version addresses these points:
* Added reference to Lagrange relaxation and some more comments to the documentation
* Treats center and drag separately in the expectation mask
* Adds the option of using an unbounded pivot
Since this branch only contains additions and the new tools for testing, I suggest we merge this into trunk now, so that we can concentrate on the modifications needed for the grail2-to-grail1 glue.
Henrik Rydberg (rydberg) wrote : Posted in a previous version of this proposal | # |
Chase Douglas (chasedouglas) wrote : Posted in a previous version of this proposal | # |
Henrik,
I'm feeling really good about the architecture of the code. I still have questions about some of the math, but I'll leave that aside for now ;-)
I like the new transform tool quite a bit though; it really helps visualize what is going on.
Initially, I had lots more questions, but my investigations have answered most of those. Here are the remaining comments/questions I have:
* What would you think about passing around complete 3x3 matrices instead of the 3x2 simplified matrices that grail 2 emits right now? If we did something like this, a 3x3 matrix could be thrown into many transformation libraries, like pixman, without any conversion.
* In set_slot_multi(), the touches are deep copied into the grail_element slot. In the other set_slot_*() functions, the touches are shallow copied from the passed in utouch frame. It seems that it would be best for the usage model to be consistent between all the functions... is this left-over from a change, or is there a definite rationale for the difference?
* grail_pump_frame() returns a reference to a new grail frame. The utouch frame may be retrieved by calling grail_get_
pumped. I don't think this could cause a bug if the code calls the frame and grail methods appropriately. However, we could run into issues with folks doing things in odd ways, since the code is non-re-entrant. For instance, if anyone needs to do parallel programming with this interface
it could get very dicey. At the very least, we should add a note in grail.h that the utouch frame data is only valid until the utouch frame is pumped again.
One thing that may help is to add a utouch_frame function that can retrieve the previous frame, if available, instead of giving the client a pointer to memory that may end up modified over time. An even better alternative would be to have reference counting of frames, but that would be a larger architecture change to utouch frame. Do you have any thoughts here?
* Touch gestures seem to be missing from grail 2.
Overall, I'm feeling pretty good about the changes. As I now understand it, the extra freedom of choosing an appropriate pivot point may allow for better touch mapping as well. I really like the work overall!
As a side note, when we go to merge this Duncan has asked that we merge it into a separate series until at least all the dependent pieces are in place to not lose functionality. I set up the lp:utouch-grail/2.x series for this purpose. Once we have this and the next merge proposals approved we can look into merging it into trunk.
Thanks!
Henrik Rydberg (rydberg) wrote : Posted in a previous version of this proposal | # |
Hi Chase,
thanks for your comments!
* Sending 3x3 matrices
The elements store 2x3 for memory reasons. The recipe to create the full 3x3 matrix is simple, so I would prefer to leave it as is.
* Deep copy
All functions copy the pointers, there is no deep copy anywhere. Perhaps the memcpy() in set_slot_multi caused the confusion.
* Pumping
The utouch frames are constructed as a fixed ring, so all pointers are always valid, although they will pointer to the "wrong" data after a while when the data wraps around.
The semantics around prev points could be improved upon, as you suggest. There was originally an idea that a gesture frame could span several touch frames, hence the extra logic around prev pointers for those. The reason for the idea was to be able to skip frames with "unstable" touch configurations, using the glue time. However, since then, this stabilization logic has been moved to
the actual gesture fragment activation, and it seems to me one could again simplify the semantics and say that every touch frame corresponds to a gesture frame. Any thoughts on that?
Regardless of the above, the get_frame methods could be further specified to only be well defined from a callback, for instance. In all other instances, the pointers are known anyways, from the flow of the code.
* Touch gestures
It works in this end, when running grail-gesture
* Merging
The grail2 branch i feel is pretty well tested, so that could in principle go to trunk. It only contains additions, no replacements. No biggie if we do the series for this as well, that is fine. Perhaps the series should be called 1.1, though, since be are not breaking ABI?
The grail2.next branch is not fully complete, agreed. There are test cases missing to guard the replacement patches. Minor behavior changes might also need to be checked and defined. Also, I am working on yet another simplification of the code, that should get rid of two of the three event buffers in use.
So yes, merging everything into a new series sounds good.
Tbanks!
Jussi Pakkanen (jpakkane) wrote : | # |
Gnome's versions of MIN and MAX macros have one more set of parentheses around the condition:
http://
That is, they use
#define MIN(a, b) (((a) < (b)) ? (a) : (b))
rather than
#define MIN(a, b) ((a) < (b) ? (a) : (b))
I can't see how this could lead to errors, but that's the way they do it.
Henrik Rydberg (rydberg) wrote : | # |
Hm... it _looks_ like code that does not trust the operator precedence rules. Thanks for the information, anyways. I think we can safely go with our version. A further interesting example can be found in include/
Chase Douglas (chasedouglas) wrote : | # |
I think the best course of action right now is to merge the changes so we can move on. We can resolve any issues with fixes moving forward.
I still have issues with the code that is in the unstable ppa. Until we get those fixed I would rather not merge the code directly into trunk. For now, lets merge this into lp:utouch-grail/2.x, and once we're sure all regressions are fixed we can redirect the lp:utouch-grail series to lp:utouch-grail/2.x.
(I've updated lp:utouch-grail/2.x to be in sync with lp:utouch-grail).
Henrik Rydberg (rydberg) wrote : | # |
It was a bit of work for all of us to get this one in, now that it is done, thank you.
I will update 2.x to this point also, and remake the remaining branches.
Cheers!
Preview Diff
1 | === added file 'AUTHORS' |
2 | --- AUTHORS 1970-01-01 00:00:00 +0000 |
3 | +++ AUTHORS 2011-04-28 16:58:23 +0000 |
4 | @@ -0,0 +1,1 @@ |
5 | +Henrik Rydberg <rydberg@bitmath.org> |
6 | |
7 | === modified file 'configure.ac' |
8 | --- configure.ac 2011-04-27 08:13:32 +0000 |
9 | +++ configure.ac 2011-04-28 16:58:23 +0000 |
10 | @@ -12,7 +12,7 @@ |
11 | AM_INIT_AUTOMAKE([foreign dist-bzip2]) |
12 | AM_MAINTAINER_MODE |
13 | |
14 | -LIB_VERSION=1:0:0 |
15 | +LIB_VERSION=2:0:1 |
16 | AC_SUBST([LIB_VERSION]) |
17 | |
18 | # Initialize libtool |
19 | @@ -26,6 +26,13 @@ |
20 | PKG_CHECK_MODULES([EVEMU], [utouch-evemu >= 1.0.5]) |
21 | PKG_CHECK_MODULES([FRAME], [utouch-frame >= 1.0]) |
22 | |
23 | +AC_ARG_WITH([xi], AS_HELP_STRING([--with-xi], [Build with XI2.1 support])) |
24 | +AM_CONDITIONAL([HAVE_XI], [test "x$with_xi" != "x"]) |
25 | + |
26 | +AS_IF([test "x$with_xi" = "xyes"], [ |
27 | + PKG_CHECK_MODULES(XINPUT, x11 xext [xi >= 1.4.1.99.1] [inputproto >= 2.0.99.1]) |
28 | + AC_DEFINE([HAVE_XI], [1], [XI2.1 support]) |
29 | +]) |
30 | # Check for TDD tools |
31 | PKG_CHECK_MODULES([CHECK], [check >= 0.9.8], |
32 | [have_check=yes], |
33 | |
34 | === added file 'docs/gestures.txt' |
35 | --- docs/gestures.txt 1970-01-01 00:00:00 +0000 |
36 | +++ docs/gestures.txt 2011-04-28 16:58:23 +0000 |
37 | @@ -0,0 +1,58 @@ |
38 | +Introduction |
39 | +------------ |
40 | + |
41 | +This document describes how the gestures are extracted from multi-finger |
42 | +actions. The process is divided into gestural transformations, gesture |
43 | +recognition, and gesture instantiation. |
44 | + |
45 | +Gestural Transformations |
46 | +------------------------ |
47 | + |
48 | +All two-finger transformations are extracted. These are all exact, in the |
49 | +sense that continuously transforming the original finger positions, frame |
50 | +per frame, will exactly follow the actual finger positions. |
51 | + |
52 | +In addition to two-finger transformations, a global gesture is also |
53 | +extracted. The rotation and scaling is taken from the contact pair with the |
54 | +longest distance between contacts. This approximates the behavior of a |
55 | +region, such that complex transformations could, in principle, be happening |
56 | +inside the region, but at a distance, the transformation will look like it |
57 | +was performed with two fingers. |
58 | + |
59 | +At each time step, a gestural transformation is goverened by rotation, |
60 | +scaling and translation. The point around which rotation and scaling is |
61 | +performed is called the pivot. To form as natural gestures as possible, |
62 | +this point always lies within the area formed by the contacts themselves. |
63 | +It is placed at the point which, after rotation and scaling, leaves the |
64 | +transformed contacts as close to the actual positions as possible. The |
65 | +translation, or drag, is always a fraction of the movement of the center |
66 | +point. The fraction is called moveness, and is related to the distance |
67 | +between the pivot and the center point. When the pivot is at the center |
68 | +point, the moveness is one and the drag is the same as the center movement. |
69 | +When the pivot is at one of the contacts, as in rotation around a finger, |
70 | +the moveness is zero, and consequently the drag is zero. The relations |
71 | +between the pivot, the moveness and the drag are detailed in the document |
72 | +pivot.txt. |
73 | + |
74 | +Gesture Recognition |
75 | +------------------- |
76 | + |
77 | +Each gestural transformation can give rise to one or several gesture |
78 | +primitives. Based on the rotation, scaling, moveness and drag values, the |
79 | +gesture primitives drag, pinch and rotate are recognized. The onset of a |
80 | +gesture primitive is governed by a threshold and a timeout. Basically, if |
81 | +performed distinctly enough, the gesture will be triggered, and will remain |
82 | +active until a finger is lifted or added. |
83 | + |
84 | +Gesture Instantiation |
85 | +--------------------- |
86 | + |
87 | +Given a set of detected gesture primitives, only some will trigger actual |
88 | +gesture events. First, the set of available primitives are matched against |
89 | +available listeners. Primitives not listened for are dropped. The remaining |
90 | +set is arranged according to priority. A pointer gesture has lower priority |
91 | +than a two-finger gesture, which has lower priority than a tap, for |
92 | +instance. As long as the gesture primitives of higher priority are expected |
93 | +but not activated, all gestures are held back. Once one of the highest |
94 | +priority primitives are activated, all primitives of lower priority are |
95 | +cancelled, and events are emitted. |
96 | |
97 | === added file 'docs/pivot.txt' |
98 | --- docs/pivot.txt 1970-01-01 00:00:00 +0000 |
99 | +++ docs/pivot.txt 2011-04-28 16:58:23 +0000 |
100 | @@ -0,0 +1,146 @@ |
101 | +The pivot, p, is defined as the point, within the convex hull of the |
102 | +contacts, which, after rotation and scaling, leaves the transformed |
103 | +contacts as close to the actual positions as possible. |
104 | + |
105 | +Let r_i be the starting points and s_i the actual ending points in a |
106 | +transformation. Let D be the scaling, and R the rotation. Then, minimizing |
107 | + |
108 | +L(p) = sum_i |D R (r_i - p) + p - s_i|^2 / N |
109 | + |
110 | +yields the pivot. Let |
111 | + |
112 | +rm = sum_i r_i / N, |
113 | +p = rm + u, |
114 | +q_i = s_i - rm - D R (r_i - rm), |
115 | + |
116 | +and we get |
117 | + |
118 | +L(p) = sum_i |(1 - D R) u - q_i|^2 / N. |
119 | + |
120 | +With |
121 | + |
122 | +L0 = sum_i norm2(q_i) / N, |
123 | +T = (1 - D R)' (1 - D R), |
124 | +m = sum_i q_i / N, |
125 | + |
126 | +we can write this as |
127 | + |
128 | +L(p) = L0 + u' T u - 2 m' (1 - D R) u. |
129 | + |
130 | +To handle the constraint, we can approximate the hull with a circle |
131 | +centered at rm. If we pick the average radius, P, the constraint becomes |
132 | + |
133 | +|u| < P. |
134 | + |
135 | +Relaxing [1] the expression (h >= 0) yields |
136 | + |
137 | +L(p, h) = L0 + u' T u - 2 m' (1 - D R) u + h (|u|^2 - P^2), |
138 | + |
139 | +leading to the linear equation |
140 | + |
141 | +(T + h) u = (1 - D R)' m. |
142 | + |
143 | +Further, |
144 | + |
145 | +sm = sum_i s_i / N, |
146 | +m = sum_i (s_i - rm - D R (r_i - rm)) / N = sm - rm, |
147 | + |
148 | +thus m is the average displacement. In words, the pivot is the average |
149 | +position plus a correction depending on the average displacement. |
150 | + |
151 | +* |
152 | + |
153 | +Some algebra solves the equation, |
154 | + |
155 | +D' = D, |
156 | +[D, R] = 0, |
157 | +R = S + C, |
158 | +S' = -S, |
159 | +C' = C, |
160 | +R + R' = 2 C, |
161 | +T = (1 - D R)' (1 - D R) = 1 + D^2 - 2 D C, |
162 | + |
163 | +which is a simple diagonal scaling operator. With |
164 | + |
165 | +a = 1 - D C, |
166 | +b = D S, |
167 | + |
168 | +we can write this as |
169 | + |
170 | +T = (1 - DC)^2 + D^2(1 - C^2) = (1 - DC)^2 + D^2 S^2 = a^2 + b^2. |
171 | + |
172 | +Similarly, we can write |
173 | + |
174 | +(1 - D R)' = ((a, b), (-b, a)), |
175 | + |
176 | +and thusly, |
177 | + |
178 | +u = Q(h) m, |
179 | + |
180 | +with |
181 | + |
182 | +Q(h) = ((a, b), (-b, a)) / (a^2 + b^2 + h). |
183 | + |
184 | +When D R = 1, it follows that a^2 + b^2 = 0, and the relaxation ensures |
185 | +that u is finite. |
186 | + |
187 | +* |
188 | + |
189 | +The drag is found by minimizing |
190 | + |
191 | +E(d) = sum_i | D R (r_i - p) + p + d - s_i |^2 / N, |
192 | +E(d) = d^2 + 2 d' ((1 - D R) u - m) + E0, |
193 | + |
194 | +which leads to the linear equation |
195 | + |
196 | +d = m - (1 - D R) u. |
197 | + |
198 | +Explicitly, |
199 | + |
200 | +d = m - (a ux - b uy, a uy + b ux). |
201 | + |
202 | +Inserting the expression for u yields, after some algebra, |
203 | + |
204 | +d = m (1 - (a^2 + b^2) / (a^2 + b^2 + h)). |
205 | + |
206 | +When h = 0, d = 0, as expected. |
207 | + |
208 | +When a^2 + b^2 = 0, d = m, also as expected. |
209 | + |
210 | +For constrained cases, the drag is a fraction of the average displacement. |
211 | + |
212 | +* |
213 | + |
214 | +Time to look at measures for the relaxation parameter. Since d depends on |
215 | +h, we can write the correction u(h) in terms of d instead. After som |
216 | +algebra, |
217 | + |
218 | +|u(h)| = (|m| - |d|) / sqrt(a^2 + b^2). |
219 | + |
220 | +Conversely, d(h) can be written in terms of the constrained u(h) as |
221 | + |
222 | +d(h) = m (1 - sqrt(a^2 + b^2) |u(h)| / |m|). |
223 | + |
224 | +Since |u(0)| = |m| / sqrt(a^2 + b^2), we obtain |
225 | + |
226 | +d(h) = m (1 - |u(h)| / |u(0)|). |
227 | + |
228 | +* |
229 | + |
230 | +We can now write down an explicit recipe for determining the pivot (p) and |
231 | +drag (d), given the transformation parameters a and b. |
232 | + |
233 | +w = (a mx + b my, a my - b mx). |
234 | + |
235 | +If |w| = 0, then u = 0. Consequently p = rm, d = m, and we are done. Else, |
236 | + |
237 | +u = w |m|^2 / |w|^2, |
238 | + |
239 | +t = P / |u|. |
240 | + |
241 | +If t >= 1, then p = rm + u, d = 0, and we are done. Else, |
242 | + |
243 | +p = rm + t u, |
244 | +d = (1 - t) m. |
245 | + |
246 | +[1] See Lagrange relaxation |
247 | |
248 | === modified file 'include/grail-bits.h' |
249 | --- include/grail-bits.h 2011-04-27 16:12:36 +0000 |
250 | +++ include/grail-bits.h 2011-04-28 16:58:23 +0000 |
251 | @@ -2,8 +2,7 @@ |
252 | * |
253 | * grail - Gesture Recognition And Instantiation Library |
254 | * |
255 | - * Copyright (C) 2010 Canonical Ltd. |
256 | - * Copyright (C) 2010 Henrik Rydberg <rydberg@bitmath.org> |
257 | + * Copyright (C) 2010-2011 Canonical Ltd. |
258 | * |
259 | * This program is free software: you can redistribute it and/or modify it |
260 | * under the terms of the GNU General Public License as published by the |
261 | |
262 | === modified file 'include/grail-types.h' |
263 | --- include/grail-types.h 2011-03-28 20:04:07 +0000 |
264 | +++ include/grail-types.h 2011-04-28 16:58:23 +0000 |
265 | @@ -2,8 +2,7 @@ |
266 | * |
267 | * grail - Gesture Recognition And Instantiation Library |
268 | * |
269 | - * Copyright (C) 2010 Canonical Ltd. |
270 | - * Copyright (C) 2010 Henrik Rydberg <rydberg@bitmath.org> |
271 | + * Copyright (C) 2010-2011 Canonical Ltd. |
272 | * |
273 | * This program is free software: you can redistribute it and/or modify it |
274 | * under the terms of the GNU General Public License as published by the |
275 | |
276 | === modified file 'include/grail.h' |
277 | --- include/grail.h 2011-04-27 16:12:36 +0000 |
278 | +++ include/grail.h 2011-04-28 16:58:23 +0000 |
279 | @@ -2,8 +2,7 @@ |
280 | * |
281 | * grail - Gesture Recognition And Instantiation Library |
282 | * |
283 | - * Copyright (C) 2010 Canonical Ltd. |
284 | - * Copyright (C) 2010 Henrik Rydberg <rydberg@bitmath.org> |
285 | + * Copyright (C) 2010-2011 Canonical Ltd. |
286 | * |
287 | * This program is free software: you can redistribute it and/or modify it |
288 | * under the terms of the GNU General Public License as published by the |
289 | @@ -26,11 +25,14 @@ |
290 | #include <linux/input.h> |
291 | #include <grail-bits.h> |
292 | #include <grail-types.h> |
293 | +#include <utouch/frame.h> |
294 | |
295 | #ifdef __cplusplus |
296 | extern "C" { |
297 | #endif |
298 | |
299 | +#define GRAIL_VERSION 0x00011000 |
300 | + |
301 | #define DIM_GRAIL_TYPE 64 |
302 | #define DIM_GRAIL_TYPE_BYTES ((DIM_GRAIL_TYPE + 7) >> 3) |
303 | |
304 | @@ -41,8 +43,30 @@ |
305 | #define GRAIL_STATUS_UPDATE 1 |
306 | #define GRAIL_STATUS_END 2 |
307 | |
308 | -typedef float grail_prop_t; /* gesture properties */ |
309 | -typedef __u64 grail_time_t; /* time in milliseconds */ |
310 | +#define GRAIL_EXPECT_CENTER_X 0x0001 |
311 | +#define GRAIL_EXPECT_CENTER_Y 0x0002 |
312 | +#define GRAIL_EXPECT_DRAG_X 0x0004 |
313 | +#define GRAIL_EXPECT_DRAG_Y 0x0008 |
314 | +#define GRAIL_EXPECT_SCALE 0x0010 |
315 | +#define GRAIL_EXPECT_ANGLE 0x0020 |
316 | +#define GRAIL_EXPECT_MASK 0x003f |
317 | + |
318 | +typedef float grail_prop_t; /* gesture properties */ |
319 | +typedef utouch_frame_time_t grail_time_t; /* time in milliseconds */ |
320 | +typedef struct grail *grail_handle; /* the grail instance handle */ |
321 | + |
322 | +/** |
323 | + * struct grail_get_version - get grail library version |
324 | + * |
325 | + * Report the version of the grail library, which can be different from |
326 | + * the value of GRAIL_VERSION in this header file. |
327 | + * |
328 | + * This function allows for fallback options from major interface |
329 | + * extensions within the same ABI version. For the normal cases of ABI |
330 | + * agnostic or backwards incompatible changes, this function is not |
331 | + * needed. |
332 | + */ |
333 | +unsigned int GRAIL_PUBLIC grail_get_version(void); |
334 | |
335 | /** |
336 | * struct grail_coord - coordinate in bounding box units |
337 | @@ -53,32 +77,63 @@ |
338 | float x, y; |
339 | }; |
340 | |
341 | -/** |
342 | - * struct grail_contact - MT event information in bounding box units |
343 | - * @id: Contact tracking id |
344 | - * @tool_type: Tool type (ABS_MT_TOOL_TYPE) |
345 | - * @pos: Position of contact (bbox units) |
346 | - * @touch_major: Major axis of contact shape (bbox units) |
347 | - * @touch_minor: Minor axis of contact shape (bbox units) |
348 | - * @width_major: Major axis of perimeter (bbox units) |
349 | - * @width_minor: Minor axis of perimeter (bbox units) |
350 | - * @angle: Angle of orientation (vertical: 0 horizontal: +-M_PI_2) |
351 | - * @pressure: Pressure of contact (min: 0 max: 1) |
352 | - * |
353 | - * Depending on the native support of the underlying device, some or all of |
354 | - * the listed properties may be computed. |
355 | - */ |
356 | -struct grail_contact { |
357 | - int id; |
358 | - int tool_type; |
359 | - struct grail_coord pos; |
360 | - float touch_major; |
361 | - float touch_minor; |
362 | - float width_major; |
363 | - float width_minor; |
364 | - float angle; |
365 | - float pressure; |
366 | -}; |
367 | +grail_handle GRAIL_PUBLIC grail_new_raw(utouch_frame_handle fh, |
368 | + unsigned int num_frames, |
369 | + void *select, |
370 | + unsigned int version, |
371 | + unsigned int control_size, |
372 | + unsigned int frame_size, |
373 | + unsigned int slot_size); |
374 | + |
375 | +/** |
376 | + * grail_new - allocate and initialize a new grail instance |
377 | + * @fh: utouch frame handle to use |
378 | + * @num_frames: number of frames in cyclic buffer |
379 | + * @select: client selection callback |
380 | + * |
381 | + * Initialize the internal grail structures. |
382 | + * |
383 | + * Returns zero in case of failure. |
384 | + */ |
385 | +#define grail_new(fh, num_frames, select) \ |
386 | + grail_new_raw(fh, num_frames, select, \ |
387 | + GRAIL_VERSION, \ |
388 | + sizeof(struct grail_control), \ |
389 | + sizeof(struct grail_frame), \ |
390 | + sizeof(struct grail_element)) |
391 | + |
392 | +/** |
393 | + * grail_delete - destroy and delete grail instance |
394 | + * @ge: grail instance in use |
395 | + * |
396 | + * Deallocates all internal memory structures. |
397 | + */ |
398 | +void GRAIL_PUBLIC grail_delete(grail_handle ge); |
399 | + |
400 | +/** |
401 | + * grail_get_control - get mutable control structure |
402 | + * @ge: the grail device in use |
403 | + * |
404 | + * Return the control struct of the grail instance. |
405 | + * |
406 | + * The control pointer is ABI agnostic, owned by the grail instance, and |
407 | + * has grail scope. |
408 | + */ |
409 | +struct grail_control GRAIL_PUBLIC *grail_get_control(grail_handle ge); |
410 | + |
411 | +/** |
412 | + * grail_pump_frame - insert touch frames into grail |
413 | + * @ge: the grail device in use |
414 | + * @frame: the touch frame to insert |
415 | + * |
416 | + * Insert a new touch frame into the grail engine. If the frame induces a |
417 | + * new gesture frame, a pointer to the frame is returned. |
418 | + * |
419 | + * The grail frame pointer is ABI agnostic, owned by the grail instance, and |
420 | + * has grail scope. |
421 | + */ |
422 | +const struct grail_frame GRAIL_PUBLIC * |
423 | +grail_pump_frame(grail_handle ge, const struct utouch_frame *frame); |
424 | |
425 | /** |
426 | * struct grail_client_id - Gesture client information |
427 | @@ -106,6 +161,143 @@ |
428 | }; |
429 | |
430 | /** |
431 | + * struct grail_control - control parameters of grail |
432 | + * @glue_ms: minimum time to hold activation (ms) |
433 | + * @bar_center_x: horizontal distance to activate (surface width fraction) |
434 | + * @bar_center_y: vertical distance to activate (surface height fraction) |
435 | + * @bar_drag_x: horizontal distance to activate (surface width fraction) |
436 | + * @bar_drag_y: vertical distance to activate (surface height fraction) |
437 | + * @bar_scale: minimum scaling to activate (fraction) |
438 | + * @bar_angle: minimum angle to activate (radians) |
439 | + * @drop_x_ms: horizontal expect timeout (ms) |
440 | + * @drop_y_ms: vertical expect timeout (ms) |
441 | + * @drop_scale_ms: scaling expect timeout (ms) |
442 | + * @drop_angle_ms: rotation expect timeout (ms) |
443 | + * @pivot_unbound: when true, the pivot is not bound to the contact area |
444 | + * |
445 | + * The parameters are used to tune the behavior of the gesture recognition. |
446 | + * |
447 | + * The moveness is a number between zero and one denoting the |
448 | + * character of the current transform. Zero means pure rotate and |
449 | + * scale, one means pure drag. |
450 | + * |
451 | + * Later versions of this struct may grow in size, but will remain |
452 | + * binary compatible with older versions. |
453 | + */ |
454 | +struct grail_control { |
455 | + float glue_ms; |
456 | + float bar_center_x; |
457 | + float bar_center_y; |
458 | + float bar_drag_x; |
459 | + float bar_drag_y; |
460 | + float bar_scale; |
461 | + float bar_angle; |
462 | + float drop_x_ms; |
463 | + float drop_y_ms; |
464 | + float drop_scale_ms; |
465 | + float drop_angle_ms; |
466 | + int pivot_unbound; |
467 | +}; |
468 | + |
469 | +/** |
470 | + * struct grail_frame - frame of ongoing elementary transformations |
471 | + * @prev: pointer to the previous gesture frame |
472 | + * @touch: pointer to the touch frame triggering this gesture frame |
473 | + * @num_ongoing: number of elements in the ongoing array |
474 | + * @ongoing: array of ongoing transformation elements |
475 | + * @slots: array of all transformation slots |
476 | + * |
477 | + * A gesture frame consists of one or several touch frames glued |
478 | + * together into a stable transition, combined with information on |
479 | + * ongoing elementary gestural transformations. The array of ongoing |
480 | + * elements contains all elements with a nonzero expect mask. |
481 | + * |
482 | + * Later versions of this struct may grow in size, but will remain |
483 | + * binary compatible with older versions. |
484 | + */ |
485 | +struct grail_frame { |
486 | + const struct grail_frame *prev; |
487 | + const struct utouch_frame *touch; |
488 | + unsigned int num_ongoing; |
489 | + struct grail_element **ongoing; |
490 | + struct grail_element **slots; |
491 | +}; |
492 | + |
493 | +/** |
494 | + * struct grail_element - elementary gesture transformation |
495 | + * @prev: respective element of previous frame |
496 | + * @slot: the transformation slot occupied by this element |
497 | + * @id: unique identifier of the ongoing transformation |
498 | + * @num_touches: number of contacts of this element |
499 | + * @touches: array of contacts of this element |
500 | + * @start_time: start time of this element |
501 | + * @start_center: center position at start of transform (surface units) |
502 | + * @expect_mask: bitmask of expected gestures (grail main types) |
503 | + * @active_mask: bitmask of activated gestures (grail main types) |
504 | + * @center: gesture center position (surface units) |
505 | + * @velocity: current center velocity (surface units per second) |
506 | + * @radius: gesture radius from center (surface units) |
507 | + * @transform: the transformation matrix of the gesture |
508 | + * @pivot: current center of rotate and scale (surface units) |
509 | + * @drag: accumulated transformation displacement (surface units) |
510 | + * @scale: accumulated scale (dimensionless) |
511 | + * @angle: accumulated rotation angle (radians) |
512 | + * |
513 | + * The grail element describes the ongoing gestural transformation of |
514 | + * a particular set of contacts. The expect mask describes which |
515 | + * gestural transformations may become active during the course of |
516 | + * events, and the active mask describes which have passed their |
517 | + * respective activation threshold. The set of expected gestures can |
518 | + * change over time, for instance by exclusion or timeout. |
519 | + * |
520 | + * Applications handling rotation, either by transformation matrix or |
521 | + * angle, should use the drag displacement. For other applications, |
522 | + * the center displacement may be used instead, as to not lose |
523 | + * movement accuracy. |
524 | + * |
525 | + * Later versions of this struct may grow in size, but will remain |
526 | + * binary compatible with older versions. |
527 | + */ |
528 | +struct grail_element { |
529 | + const struct grail_element *prev; |
530 | + int slot; |
531 | + int id; |
532 | + int num_touches; |
533 | + const struct utouch_contact **touches; |
534 | + grail_time_t start_time; |
535 | + struct grail_coord start_center; |
536 | + unsigned int expect_mask; |
537 | + unsigned int active_mask; |
538 | + struct grail_coord center; |
539 | + struct grail_coord velocity; |
540 | + float radius2; |
541 | + float transform[6]; |
542 | + float moveness; |
543 | + struct grail_coord pivot; |
544 | + struct grail_coord drag; |
545 | + float scale2; |
546 | + float angle; |
547 | +}; |
548 | + |
549 | +/** |
550 | + * grail_element_transform - transform coordinates using element |
551 | + * @slot: the transformation element to use |
552 | + * @q: the grail coordinate to fill |
553 | + * @x: the grail coordinate to transform |
554 | + * |
555 | + * Performs the 3x3 transform *q = T *p, where T is the element |
556 | + * transform. |
557 | + */ |
558 | +static inline void grail_element_transform(const struct grail_element *slot, |
559 | + struct grail_coord *q, |
560 | + const struct grail_coord *p) |
561 | +{ |
562 | + const float *T = slot->transform; |
563 | + q->x = T[0] * p->x + T[1] * p->y + T[2]; |
564 | + q->y = T[3] * p->x + T[4] * p->y + T[5]; |
565 | +} |
566 | + |
567 | +/** |
568 | * struct grail_event - Gesture event |
569 | * @type: The gesture type |
570 | * @id: Unique identifier foof the gesture instance |
571 | @@ -231,19 +423,6 @@ |
572 | const struct grail_coord *max); |
573 | |
574 | /** |
575 | - * grail_filter_abs_events - filter kernel motion events |
576 | - * @ge: the grail device in use |
577 | - * @usage: When true, filter kernel motion events. |
578 | - * |
579 | - * Single-finger pointer events are treated as pointer gestures in |
580 | - * grail. When filter_motion_events is non-zero, the kernel events |
581 | - * corresponding to pointer movement are removed from the event |
582 | - * stream. |
583 | - * |
584 | - */ |
585 | -void GRAIL_PUBLIC grail_filter_abs_events(struct grail *ge, int usage); |
586 | - |
587 | -/** |
588 | * grail_get_units - get device coordinate ranges |
589 | * @ge: the grail device in use |
590 | * @min: minimum x and y coordinates |
591 | @@ -259,17 +438,43 @@ |
592 | struct grail_coord *min, struct grail_coord *max); |
593 | |
594 | /** |
595 | - * grail_get_contacts - get current contact state |
596 | + * grail_get_contact_frame - get current contact frame |
597 | * @ge: the grail device in use |
598 | - * @touch: array of contacts to be filled in |
599 | - * @max_touch: maximum number of contacts supported by the array |
600 | - * |
601 | - * Extract the contact state as currently seen by grail. |
602 | - * |
603 | + * |
604 | + * Return the contact frame current being processed. If called from |
605 | + * within a gesture callback, it is guaranteed to return the frame |
606 | + * corresponding to the gesture. |
607 | + * |
608 | + * The returned pointer can be NULL if no input has yet been extracted |
609 | + * through the grail instance. |
610 | + * |
611 | + * The frame pointer is ABI agnostic, owned by the grail instance, and |
612 | + * has grail scope. |
613 | */ |
614 | +const struct utouch_frame GRAIL_PUBLIC * |
615 | +grail_get_contact_frame(const struct grail *ge); |
616 | + |
617 | +#ifndef GRAIL_NO_LEGACY_API |
618 | + |
619 | +struct grail_contact { |
620 | + int id; |
621 | + int tool_type; |
622 | + struct grail_coord pos; |
623 | + float touch_major; |
624 | + float touch_minor; |
625 | + float width_major; |
626 | + float width_minor; |
627 | + float angle; |
628 | + float pressure; |
629 | +}; |
630 | + |
631 | +void GRAIL_PUBLIC grail_filter_abs_events(struct grail *ge, int usage); |
632 | + |
633 | int GRAIL_PUBLIC grail_get_contacts(const struct grail *ge, |
634 | struct grail_contact *touch, int max_touch); |
635 | |
636 | +#endif |
637 | + |
638 | #ifdef __cplusplus |
639 | } |
640 | #endif |
641 | |
642 | === added file 'include/grail.h.orig' |
643 | --- include/grail.h.orig 1970-01-01 00:00:00 +0000 |
644 | +++ include/grail.h.orig 2011-04-28 16:58:23 +0000 |
645 | @@ -0,0 +1,277 @@ |
646 | +/***************************************************************************** |
647 | + * |
648 | + * grail - Gesture Recognition And Instantiation Library |
649 | + * |
650 | + * Copyright (C) 2010 Canonical Ltd. |
651 | + * Copyright (C) 2010 Henrik Rydberg <rydberg@bitmath.org> |
652 | + * |
653 | + * This program is free software: you can redistribute it and/or modify it |
654 | + * under the terms of the GNU General Public License as published by the |
655 | + * Free Software Foundation, either version 3 of the License, or (at your |
656 | + * option) any later version. |
657 | + * |
658 | + * This program is distributed in the hope that it will be useful, but |
659 | + * WITHOUT ANY WARRANTY; without even the implied warranty of |
660 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
661 | + * General Public License for more details. |
662 | + * |
663 | + * You should have received a copy of the GNU General Public License along |
664 | + * with this program. If not, see <http://www.gnu.org/licenses/>. |
665 | + * |
666 | + ****************************************************************************/ |
667 | + |
668 | +#ifndef _GRAIL_H |
669 | +#define _GRAIL_H |
670 | + |
671 | +#include <linux/input.h> |
672 | +#include <grail-bits.h> |
673 | +#include <grail-types.h> |
674 | + |
675 | +#ifdef __cplusplus |
676 | +extern "C" { |
677 | +#endif |
678 | + |
679 | +#define DIM_GRAIL_TYPE 64 |
680 | +#define DIM_GRAIL_TYPE_BYTES ((DIM_GRAIL_TYPE + 7) >> 3) |
681 | + |
682 | +#define DIM_GRAIL_PROP 32 |
683 | +#define DIM_GRAIL_PROP_BYTES ((DIM_GRAIL_PROP + 7) >> 3) |
684 | + |
685 | +#define GRAIL_STATUS_BEGIN 0 |
686 | +#define GRAIL_STATUS_UPDATE 1 |
687 | +#define GRAIL_STATUS_END 2 |
688 | + |
689 | +typedef float grail_prop_t; /* gesture properties */ |
690 | +typedef __u64 grail_time_t; /* time in milliseconds */ |
691 | + |
692 | +/** |
693 | + * struct grail_coord - coordinate in bounding box units |
694 | + * @x: the horizontal position (bbox units) |
695 | + * @y: the vertical position (bbox units) |
696 | + */ |
697 | +struct grail_coord { |
698 | + float x, y; |
699 | +}; |
700 | + |
701 | +/** |
702 | + * struct grail_contact - MT event information in bounding box units |
703 | + * @id: Contact tracking id |
704 | + * @tool_type: Tool type (ABS_MT_TOOL_TYPE) |
705 | + * @pos: Position of contact (bbox units) |
706 | + * @touch_major: Major axis of contact shape (bbox units) |
707 | + * @touch_minor: Minor axis of contact shape (bbox units) |
708 | + * @width_major: Major axis of perimeter (bbox units) |
709 | + * @width_minor: Minor axis of perimeter (bbox units) |
710 | + * @angle: Angle of orientation (vertical: 0 horizontal: +-M_PI_2) |
711 | + * @pressure: Pressure of contact (min: 0 max: 1) |
712 | + * |
713 | + * Depending on the native support of the underlying device, some or all of |
714 | + * the listed properties may be computed. |
715 | + */ |
716 | +struct grail_contact { |
717 | + int id; |
718 | + int tool_type; |
719 | + struct grail_coord pos; |
720 | + float touch_major; |
721 | + float touch_minor; |
722 | + float width_major; |
723 | + float width_minor; |
724 | + float angle; |
725 | + float pressure; |
726 | +}; |
727 | + |
728 | +/** |
729 | + * struct grail_client_id - Gesture client information |
730 | + * @client: Client id |
731 | + * @root: Root window |
732 | + * @event: Window to route events to |
733 | + * @child: Window the event occured in |
734 | + * |
735 | + * This struct is treated opaquely, and only has meaning to the gesture |
736 | + * client. Details are subject to change. |
737 | + */ |
738 | +struct grail_client_id { |
739 | + int client; |
740 | + int root, event, child; |
741 | +}; |
742 | + |
743 | +/** |
744 | + * struct grail_client_info - Gesture request information |
745 | + * @id: Gesture client id |
746 | + * @mask: Gestures the client is listening to |
747 | + */ |
748 | +struct grail_client_info { |
749 | + struct grail_client_id id; |
750 | + grail_mask_t mask[DIM_GRAIL_TYPE_BYTES]; |
751 | +}; |
752 | + |
753 | +/** |
754 | + * struct grail_event - Gesture event |
755 | + * @type: The gesture type |
756 | + * @id: Unique identifier foof the gesture instance |
757 | + * @status: Gesture status (begin, update, end) |
758 | + * @ntouch: Number of current touches |
759 | + * @nprop: Number of properties in the gesture |
760 | + * @pos: Focus point of the gesture (bbox coordinates) |
761 | + * @touch: Array of individual touch information |
762 | + * @client_id: The gesture client to route the gesture to |
763 | + * @time: Time of event (milliseconds) |
764 | + * @prop: Array of properties of the event |
765 | + * |
766 | + * Gesture events are passed to the client via the gesture() callback. |
767 | + */ |
768 | +struct grail_event { |
769 | + int type; |
770 | + int id; |
771 | + int status; |
772 | + int ntouch; |
773 | + int nprop; |
774 | + struct grail_coord pos; |
775 | + struct grail_client_id client_id; |
776 | + grail_time_t time; |
777 | + grail_prop_t prop[DIM_GRAIL_PROP]; |
778 | +}; |
779 | + |
780 | +/** |
781 | + * struct grail - Main grail device |
782 | + * @get_clients: Called at the onset of new gestures to retrieve the list |
783 | + * of listening clients. |
784 | + * @event: Callback for kernel events passing through grail. |
785 | + * @gesture: Main gesture callback. |
786 | + * @impl: Grail implementation details. |
787 | + * @gin: Gesture instatiation details. |
788 | + * @gru: Gesture recognition details. |
789 | + * @priv: Generic pointer to user-defined content. |
790 | + * |
791 | + * The grail device pulls events from the underlying device, detects |
792 | + * gestures, and passes them on to the client via the gesture() |
793 | + * callback. Events that are not gesture or for other reasons held back are |
794 | + * passed on via the event() callback. The user provides information about |
795 | + * windows and listening clients via the get_clients callback, which is |
796 | + * called during gesture instantiation. |
797 | + * |
798 | + */ |
799 | +struct grail { |
800 | + int (*get_clients)(struct grail *ge, |
801 | + struct grail_client_info *client, int max_clients, |
802 | + const struct grail_coord *coords, int num_coords, |
803 | + const grail_mask_t *types, int type_bytes); |
804 | + void (*event)(struct grail *ge, |
805 | + const struct input_event *ev); |
806 | + void (*gesture)(struct grail *ge, |
807 | + const struct grail_event *ev); |
808 | + struct grail_impl *impl; |
809 | + struct gesture_inserter *gin; |
810 | + struct gesture_recognizer *gru; |
811 | + void *priv; |
812 | +}; |
813 | + |
814 | +/** |
815 | + * grail_open - open a grail device |
816 | + * @ge: the grail device to open |
817 | + * @fd: file descriptor of the kernel device |
818 | + * |
819 | + * Initialize the internal grail structures and configure it by reading the |
820 | + * protocol capabilities through the file descriptor. |
821 | + * |
822 | + * The callbacks, parameters and priv pointer should be set prior to this |
823 | + * call. |
824 | + * |
825 | + * Returns zero on success, negative error number otherwise. |
826 | + */ |
827 | +int GRAIL_PUBLIC grail_open(struct grail *ge, int fd); |
828 | + |
829 | +/** |
830 | + * grail_idle - check state of kernel device |
831 | + * @ge: the grail device in use |
832 | + * @fd: file descriptor of the kernel device |
833 | + * @ms: number of milliseconds to wait for activity |
834 | + * |
835 | + * Returns true if the device is idle, i.e., there are no fetched |
836 | + * events in the pipe and there is nothing to fetch from the device. |
837 | + */ |
838 | +int GRAIL_PUBLIC grail_idle(struct grail *ge, int fd, int ms); |
839 | + |
840 | +/** |
841 | + * grail_pull - pull and process available events from the kernel device |
842 | + * @ge: the grail device in use |
843 | + * @fd: file descriptor of the kernel device |
844 | + * |
845 | + * Pull all available events and process them. The grail callbacks are |
846 | + * invoked during this call. |
847 | + * |
848 | + * The underlying file descriptor must have O_NONBLOCK set, or this method |
849 | + * will not return until the file is closed. |
850 | + * |
851 | + * On success, returns the number of events read. Otherwise, |
852 | + * a standard negative error number is returned. |
853 | + */ |
854 | +int GRAIL_PUBLIC grail_pull(struct grail *ge, int fd); |
855 | + |
856 | +/** |
857 | + * grail_close - close the grail device |
858 | + * @ge: the grail device to close |
859 | + * @fd: file descriptor of the kernel device |
860 | + * |
861 | + * Deallocates all memory associated with grail, and clears the grail |
862 | + * structure. |
863 | + */ |
864 | +void GRAIL_PUBLIC grail_close(struct grail *ge, int fd); |
865 | + |
866 | +/** |
867 | + * grail_set_bbox - set the grail unit bounding box |
868 | + * @ge: the grail device in use |
869 | + * @min: the minimum (lower-left) corner of the bounding box |
870 | + * @max: the maximum (upper-right) corner of the bounding box |
871 | + * |
872 | + * Sets the box within which the device coordinates should be presented. |
873 | + */ |
874 | +void GRAIL_PUBLIC grail_set_bbox(struct grail *ge, |
875 | + const struct grail_coord *min, |
876 | + const struct grail_coord *max); |
877 | + |
878 | +/** |
879 | + * grail_filter_abs_events - filter kernel motion events |
880 | + * @ge: the grail device in use |
881 | + * @usage: When true, filter kernel motion events. |
882 | + * |
883 | + * Single-finger pointer events are treated as pointer gestures in |
884 | + * grail. When filter_motion_events is non-zero, the kernel events |
885 | + * corresponding to pointer movement are removed from the event |
886 | + * stream. |
887 | + * |
888 | + */ |
889 | +void GRAIL_PUBLIC grail_filter_abs_events(struct grail *ge, int usage); |
890 | + |
891 | +/** |
892 | + * grail_get_units - get device coordinate ranges |
893 | + * @ge: the grail device in use |
894 | + * @min: minimum x and y coordinates |
895 | + * @max: maximum x and y coordinates |
896 | + * |
897 | + * The grail event attributes pos, touch_major, touch_minor, |
898 | + * width_major, and width_minor are all given in device coordinate |
899 | + * units, unless specified otherwise using the grail_set_bbox() |
900 | + * function. This function reports the device coordinate ranges. |
901 | + * |
902 | + */ |
903 | +void GRAIL_PUBLIC grail_get_units(const struct grail *ge, |
904 | + struct grail_coord *min, struct grail_coord *max); |
905 | + |
906 | +/** |
907 | + * grail_get_contacts - get current contact state |
908 | + * @ge: the grail device in use |
909 | + * @touch: array of contacts to be filled in |
910 | + * @max_touch: maximum number of contacts supported by the array |
911 | + * |
912 | + * Extract the contact state as currently seen by grail. |
913 | + * |
914 | + */ |
915 | +int GRAIL_PUBLIC grail_get_contacts(const struct grail *ge, |
916 | + struct grail_contact *touch, int max_touch); |
917 | + |
918 | +#ifdef __cplusplus |
919 | +} |
920 | +#endif |
921 | + |
922 | +#endif |
923 | |
924 | === modified file 'src/Makefile.am' |
925 | --- src/Makefile.am 2011-04-27 16:12:36 +0000 |
926 | +++ src/Makefile.am 2011-04-28 16:58:23 +0000 |
927 | @@ -25,7 +25,10 @@ |
928 | grail-recognizer.h \ |
929 | grail-event.c \ |
930 | grail-impl.h \ |
931 | - grail-api.c |
932 | + grail-api.c \ |
933 | + grail-legacy.c \ |
934 | + grail-init.c \ |
935 | + grail-frame.c |
936 | |
937 | # These are flags required to properly set up |
938 | # the build. -fvisibility requires GCC > 4 (or clang) |
939 | |
940 | === modified file 'src/evbuf.h' |
941 | --- src/evbuf.h 2011-02-24 22:50:31 +0000 |
942 | +++ src/evbuf.h 2011-04-28 16:58:23 +0000 |
943 | @@ -1,28 +1,21 @@ |
944 | /***************************************************************************** |
945 | * |
946 | - * mtdev - Multitouch Protocol Translation Library (MIT license) |
947 | - * |
948 | - * Copyright (C) 2010 Canonical Ltd. |
949 | - * Copyright (C) 2010 Henrik Rydberg <rydberg@bitmath.org> |
950 | - * |
951 | - * Permission is hereby granted, free of charge, to any person obtaining a |
952 | - * copy of this software and associated documentation files (the "Software"), |
953 | - * to deal in the Software without restriction, including without limitation |
954 | - * the rights to use, copy, modify, merge, publish, distribute, sublicense, |
955 | - * and/or sell copies of the Software, and to permit persons to whom the |
956 | - * Software is furnished to do so, subject to the following conditions: |
957 | - * |
958 | - * The above copyright notice and this permission notice (including the next |
959 | - * paragraph) shall be included in all copies or substantial portions of the |
960 | - * Software. |
961 | - * |
962 | - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
963 | - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
964 | - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL |
965 | - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
966 | - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING |
967 | - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER |
968 | - * DEALINGS IN THE SOFTWARE. |
969 | + * grail - Gesture Recognition And Instantiation Library |
970 | + * |
971 | + * Copyright (C) 2010-2011 Canonical Ltd. |
972 | + * |
973 | + * This program is free software: you can redistribute it and/or modify it |
974 | + * under the terms of the GNU General Public License as published by the |
975 | + * Free Software Foundation, either version 3 of the License, or (at your |
976 | + * option) any later version. |
977 | + * |
978 | + * This program is distributed in the hope that it will be useful, but |
979 | + * WITHOUT ANY WARRANTY; without even the implied warranty of |
980 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
981 | + * General Public License for more details. |
982 | + * |
983 | + * You should have received a copy of the GNU General Public License along |
984 | + * with this program. If not, see <http://www.gnu.org/licenses/>. |
985 | * |
986 | ****************************************************************************/ |
987 | |
988 | |
989 | === modified file 'src/gebuf.h' |
990 | --- src/gebuf.h 2011-01-02 12:08:08 +0000 |
991 | +++ src/gebuf.h 2011-04-28 16:58:23 +0000 |
992 | @@ -2,8 +2,7 @@ |
993 | * |
994 | * grail - Gesture Recognition And Instantiation Library |
995 | * |
996 | - * Copyright (C) 2010 Canonical Ltd. |
997 | - * Copyright (C) 2010 Henrik Rydberg <rydberg@bitmath.org> |
998 | + * Copyright (C) 2010-2011 Canonical Ltd. |
999 | * |
1000 | * This program is free software: you can redistribute it and/or modify it |
1001 | * under the terms of the GNU General Public License as published by the |
1002 | |
1003 | === modified file 'src/gestures-drag.c' |
1004 | --- src/gestures-drag.c 2011-03-28 20:04:18 +0000 |
1005 | +++ src/gestures-drag.c 2011-04-28 16:58:23 +0000 |
1006 | @@ -2,8 +2,7 @@ |
1007 | * |
1008 | * grail - Gesture Recognition And Instantiation Library |
1009 | * |
1010 | - * Copyright (C) 2010 Canonical Ltd. |
1011 | - * Copyright (C) 2010 Henrik Rydberg <rydberg@bitmath.org> |
1012 | + * Copyright (C) 2010-2011 Canonical Ltd. |
1013 | * |
1014 | * This program is free software: you can redistribute it and/or modify it |
1015 | * under the terms of the GNU General Public License as published by the |
1016 | |
1017 | === modified file 'src/gestures-pinch.c' |
1018 | --- src/gestures-pinch.c 2011-03-28 20:04:11 +0000 |
1019 | +++ src/gestures-pinch.c 2011-04-28 16:58:23 +0000 |
1020 | @@ -2,8 +2,7 @@ |
1021 | * |
1022 | * grail - Gesture Recognition And Instantiation Library |
1023 | * |
1024 | - * Copyright (C) 2010 Canonical Ltd. |
1025 | - * Copyright (C) 2010 Henrik Rydberg <rydberg@bitmath.org> |
1026 | + * Copyright (C) 2010-2011 Canonical Ltd. |
1027 | * |
1028 | * This program is free software: you can redistribute it and/or modify it |
1029 | * under the terms of the GNU General Public License as published by the |
1030 | |
1031 | === modified file 'src/gestures-rotate.c' |
1032 | --- src/gestures-rotate.c 2011-03-28 20:04:11 +0000 |
1033 | +++ src/gestures-rotate.c 2011-04-28 16:58:23 +0000 |
1034 | @@ -2,8 +2,7 @@ |
1035 | * |
1036 | * grail - Gesture Recognition And Instantiation Library |
1037 | * |
1038 | - * Copyright (C) 2010 Canonical Ltd. |
1039 | - * Copyright (C) 2010 Henrik Rydberg <rydberg@bitmath.org> |
1040 | + * Copyright (C) 2010-2011 Canonical Ltd. |
1041 | * |
1042 | * This program is free software: you can redistribute it and/or modify it |
1043 | * under the terms of the GNU General Public License as published by the |
1044 | |
1045 | === modified file 'src/gestures-tapping.c' |
1046 | --- src/gestures-tapping.c 2011-03-24 21:46:18 +0000 |
1047 | +++ src/gestures-tapping.c 2011-04-28 16:58:23 +0000 |
1048 | @@ -2,8 +2,7 @@ |
1049 | * |
1050 | * grail - Gesture Recognition And Instantiation Library |
1051 | * |
1052 | - * Copyright (C) 2010 Canonical Ltd. |
1053 | - * Copyright (C) 2010 Henrik Rydberg <rydberg@bitmath.org> |
1054 | + * Copyright (C) 2010-2011 Canonical Ltd. |
1055 | * |
1056 | * This program is free software: you can redistribute it and/or modify it |
1057 | * under the terms of the GNU General Public License as published by the |
1058 | |
1059 | === modified file 'src/grail-api.c' |
1060 | --- src/grail-api.c 2011-04-28 08:20:04 +0000 |
1061 | +++ src/grail-api.c 2011-04-28 16:58:23 +0000 |
1062 | @@ -2,8 +2,7 @@ |
1063 | * |
1064 | * grail - Gesture Recognition And Instantiation Library |
1065 | * |
1066 | - * Copyright (C) 2010 Canonical Ltd. |
1067 | - * Copyright (C) 2010 Henrik Rydberg <rydberg@bitmath.org> |
1068 | + * Copyright (C) 2010-2011 Canonical Ltd. |
1069 | * |
1070 | * This program is free software: you can redistribute it and/or modify it |
1071 | * under the terms of the GNU General Public License as published by the |
1072 | @@ -20,9 +19,9 @@ |
1073 | * |
1074 | ****************************************************************************/ |
1075 | |
1076 | +#include "grail-impl.h" |
1077 | #include "grail-inserter.h" |
1078 | #include "grail-recognizer.h" |
1079 | -#include "grail-impl.h" |
1080 | #include <string.h> |
1081 | #include <stdio.h> |
1082 | #include <unistd.h> |
1083 | @@ -35,10 +34,9 @@ |
1084 | #define DIM_FRAMES 100 |
1085 | #define FRAME_RATE 100 |
1086 | |
1087 | -void GRAIL_PUBLIC grail_filter_abs_events(struct grail *ge, int usage) |
1088 | +unsigned int GRAIL_PUBLIC grail_get_version(void) |
1089 | { |
1090 | - struct grail_impl *x = ge->impl; |
1091 | - x->filter_abs = usage; |
1092 | + return GRAIL_VERSION; |
1093 | } |
1094 | |
1095 | int GRAIL_PUBLIC grail_open(struct grail *ge, int fd) |
1096 | @@ -152,6 +150,12 @@ |
1097 | max->y = s->max_y; |
1098 | } |
1099 | |
1100 | +const struct utouch_frame GRAIL_PUBLIC * |
1101 | +grail_get_contact_frame(const struct grail *ge) |
1102 | +{ |
1103 | + return ge->impl->touch; |
1104 | +} |
1105 | + |
1106 | static void flush_events(struct grail *ge) |
1107 | { |
1108 | struct grail_impl *impl = ge->impl; |
1109 | @@ -221,15 +225,15 @@ |
1110 | } |
1111 | |
1112 | static void report_frame(struct grail *ge, |
1113 | - const struct utouch_frame *frame, |
1114 | + const struct utouch_frame *touch, |
1115 | const struct input_event *syn) |
1116 | { |
1117 | struct grail_impl *impl = ge->impl; |
1118 | struct grail_event gev; |
1119 | |
1120 | - ge->impl->frame = frame; |
1121 | + impl->touch = touch; |
1122 | |
1123 | - if (frame->num_active && !frame->prev->num_active) { |
1124 | + if (touch->num_active && !touch->prev->num_active) { |
1125 | impl->ongoing = 1; |
1126 | impl->gesture = 0; |
1127 | } |
1128 | @@ -237,14 +241,14 @@ |
1129 | if (!impl->ongoing) |
1130 | return; |
1131 | |
1132 | - gin_frame_begin(ge, frame); |
1133 | - gru_recognize(ge, frame); |
1134 | - gin_frame_end(ge, frame); |
1135 | + gin_frame_begin(ge, touch); |
1136 | + gru_recognize(ge, touch); |
1137 | + gin_frame_end(ge, touch); |
1138 | |
1139 | if (!grailbuf_empty(&impl->gbuf)) |
1140 | impl->gesture = 1; |
1141 | |
1142 | - if (frame->num_active == 0 || gesture_timeout(ge, frame)) |
1143 | + if (touch->num_active == 0 || gesture_timeout(ge, touch)) |
1144 | impl->ongoing &= impl->gesture; |
1145 | } |
1146 | |
1147 | |
1148 | === modified file 'src/grail-bits.c' |
1149 | --- src/grail-bits.c 2011-04-27 16:12:36 +0000 |
1150 | +++ src/grail-bits.c 2011-04-28 16:58:23 +0000 |
1151 | @@ -2,8 +2,7 @@ |
1152 | * |
1153 | * grail - Gesture Recognition And Instantiation Library |
1154 | * |
1155 | - * Copyright (C) 2010 Canonical Ltd. |
1156 | - * Copyright (C) 2010 Henrik Rydberg <rydberg@bitmath.org> |
1157 | + * Copyright (C) 2010-2011 Canonical Ltd. |
1158 | * |
1159 | * This program is free software: you can redistribute it and/or modify it |
1160 | * under the terms of the GNU General Public License as published by the |
1161 | |
1162 | === modified file 'src/grail-event.c' |
1163 | --- src/grail-event.c 2011-04-27 08:13:32 +0000 |
1164 | +++ src/grail-event.c 2011-04-28 16:58:23 +0000 |
1165 | @@ -2,8 +2,7 @@ |
1166 | * |
1167 | * grail - Gesture Recognition And Instantiation Library |
1168 | * |
1169 | - * Copyright (C) 2010 Canonical Ltd. |
1170 | - * Copyright (C) 2010 Henrik Rydberg <rydberg@bitmath.org> |
1171 | + * Copyright (C) 2010-2011 Canonical Ltd. |
1172 | * |
1173 | * This program is free software: you can redistribute it and/or modify it |
1174 | * under the terms of the GNU General Public License as published by the |
1175 | @@ -117,28 +116,3 @@ |
1176 | grailbuf_put(&impl->gbuf, &gev); |
1177 | } |
1178 | } |
1179 | - |
1180 | -int GRAIL_PUBLIC grail_get_contacts(const struct grail *ge, |
1181 | - struct grail_contact *touch, int max_touch) |
1182 | -{ |
1183 | - const struct gesture_inserter *gin = ge->gin; |
1184 | - const struct utouch_frame *frame = ge->impl->frame; |
1185 | - int i; |
1186 | - if (frame->num_active < max_touch) |
1187 | - max_touch = frame->num_active; |
1188 | - for (i = 0; i < max_touch; i++) { |
1189 | - struct grail_contact *t = &touch[i]; |
1190 | - const struct utouch_contact *ct = frame->active[i]; |
1191 | - t->id = ct->id; |
1192 | - t->tool_type = ct->tool_type; |
1193 | - t->pos.x = ct->x; |
1194 | - t->pos.y = ct->y; |
1195 | - t->touch_major = ct->touch_major; |
1196 | - t->touch_minor = ct->touch_minor; |
1197 | - t->width_major = ct->width_major; |
1198 | - t->width_minor = ct->width_minor; |
1199 | - t->angle = ct->orientation; |
1200 | - t->pressure = ct->pressure; |
1201 | - } |
1202 | - return max_touch; |
1203 | -} |
1204 | |
1205 | === added file 'src/grail-frame.c' |
1206 | --- src/grail-frame.c 1970-01-01 00:00:00 +0000 |
1207 | +++ src/grail-frame.c 2011-04-28 16:58:23 +0000 |
1208 | @@ -0,0 +1,398 @@ |
1209 | +/***************************************************************************** |
1210 | + * |
1211 | + * grail - Gesture Recognition And Instantiation Library |
1212 | + * |
1213 | + * Copyright (C) 2010-2011 Canonical Ltd. |
1214 | + * |
1215 | + * This program is free software: you can redistribute it and/or modify it |
1216 | + * under the terms of the GNU General Public License as published by the |
1217 | + * Free Software Foundation, either version 3 of the License, or (at your |
1218 | + * option) any later version. |
1219 | + * |
1220 | + * This program is distributed in the hope that it will be useful, but |
1221 | + * WITHOUT ANY WARRANTY; without even the implied warranty of |
1222 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
1223 | + * General Public License for more details. |
1224 | + * |
1225 | + * You should have received a copy of the GNU General Public License along |
1226 | + * with this program. If not, see <http://www.gnu.org/licenses/>. |
1227 | + * |
1228 | + ****************************************************************************/ |
1229 | + |
1230 | +#include "grail-impl.h" |
1231 | +#include <stdlib.h> |
1232 | +#include <string.h> |
1233 | +#include <math.h> |
1234 | + |
1235 | +static void set_center_velocity_and_radius(struct grail_impl *impl, |
1236 | + struct grail_element *slot) |
1237 | +{ |
1238 | + const struct utouch_contact **tc = slot->touches; |
1239 | + double x, y, vx, vy, r2, dx, dy; |
1240 | + int i; |
1241 | + |
1242 | + switch (slot->num_touches) { |
1243 | + case 1: |
1244 | + x = tc[0]->x; |
1245 | + y = tc[0]->y; |
1246 | + vx = tc[0]->vx; |
1247 | + vy = tc[0]->vy; |
1248 | + r2 = 0; |
1249 | + break; |
1250 | + case 2: |
1251 | + dx = 0.5 * (tc[1]->x - tc[0]->x); |
1252 | + dy = 0.5 * (tc[1]->y - tc[0]->y); |
1253 | + x = tc[0]->x + dx; |
1254 | + y = tc[0]->y + dy; |
1255 | + vx = 0.5 * (tc[0]->vx + tc[1]->vx); |
1256 | + vy = 0.5 * (tc[0]->vy + tc[1]->vy); |
1257 | + r2 = dx * dx + dy * dy; |
1258 | + break; |
1259 | + default: |
1260 | + x = y = vx = vy = r2 = 0; |
1261 | + for (i = 0; i < slot->num_touches; i++) { |
1262 | + x += tc[i]->x; |
1263 | + y += tc[i]->y; |
1264 | + vx += tc[i]->vx; |
1265 | + vy += tc[i]->vy; |
1266 | + } |
1267 | + x /= slot->num_touches; |
1268 | + y /= slot->num_touches; |
1269 | + vx /= slot->num_touches; |
1270 | + vy /= slot->num_touches; |
1271 | + for (i = 0; i < slot->num_touches; i++) { |
1272 | + dx = tc[i]->x - x; |
1273 | + dy = tc[i]->y - y; |
1274 | + r2 += dx * dx + dy * dy; |
1275 | + } |
1276 | + r2 /= slot->num_touches; |
1277 | + break; |
1278 | + } |
1279 | + |
1280 | + slot->center.x = x; |
1281 | + slot->center.y = y; |
1282 | + slot->velocity.x = 1000 * vx; |
1283 | + slot->velocity.y = 1000 * vy; |
1284 | + slot->radius2 = r2; |
1285 | +} |
1286 | + |
1287 | +static void set_moveness_pivot_and_drag(struct grail_impl *impl, |
1288 | + struct grail_element *slot, |
1289 | + double ds, double dc) |
1290 | +{ |
1291 | + const struct grail_control *ctl = impl->ctl; |
1292 | + const struct grail_element *pslot = slot->prev; |
1293 | + double mx = slot->center.x - pslot->center.x; |
1294 | + double my = slot->center.y - pslot->center.y; |
1295 | + float *T = slot->transform; |
1296 | + |
1297 | + slot->moveness = 1; |
1298 | + slot->pivot = pslot->center; |
1299 | + |
1300 | + if (slot->num_touches > 1) { |
1301 | + double wx = (1 - dc) * mx + ds * my; |
1302 | + double wy = (1 - dc) * my - ds * mx; |
1303 | + double w2 = wx * wx + wy * wy; |
1304 | + if (w2 > 0) { |
1305 | + double q = (mx * mx + my * my) / w2; |
1306 | + double s = ctl->pivot_unbound ? |
1307 | + q : sqrt(pslot->radius2 / w2); |
1308 | + if (s < q) { |
1309 | + slot->moveness = 1 - s / q; |
1310 | + slot->pivot.x += s * wx; |
1311 | + slot->pivot.y += s * wy; |
1312 | + } else { |
1313 | + slot->moveness = 0; |
1314 | + slot->pivot.x += q * wx; |
1315 | + slot->pivot.y += q * wy; |
1316 | + } |
1317 | + } |
1318 | + } |
1319 | + |
1320 | + mx *= slot->moveness; |
1321 | + my *= slot->moveness; |
1322 | + |
1323 | + T[0] = dc; |
1324 | + T[1] = ds; |
1325 | + T[2] = (1 - dc) * slot->pivot.x - ds * slot->pivot.y + mx; |
1326 | + T[3] = -ds; |
1327 | + T[4] = dc; |
1328 | + T[5] = (1 - dc) * slot->pivot.y + ds * slot->pivot.x + my; |
1329 | + |
1330 | + slot->drag.x = pslot->drag.x + mx; |
1331 | + slot->drag.y = pslot->drag.y + my; |
1332 | +} |
1333 | + |
1334 | +static void start_slot(struct grail_impl *impl, |
1335 | + struct grail_element *slot, |
1336 | + const struct utouch_frame *touch) |
1337 | +{ |
1338 | + float *T = slot->transform; |
1339 | + |
1340 | + slot->id = impl->seqid++ & GRAIL_ID_MAX; |
1341 | + slot->expect_mask = GRAIL_EXPECT_MASK; |
1342 | + slot->active_mask = 0; |
1343 | + slot->start_time = touch->time; |
1344 | + set_center_velocity_and_radius(impl, slot); |
1345 | + slot->start_center = slot->center; |
1346 | + T[0] = T[4] = 1; |
1347 | + T[1] = T[2] = T[3] = T[5] = 0; |
1348 | + slot->pivot = slot->center; |
1349 | + slot->drag.x = 0; |
1350 | + slot->drag.y = 0; |
1351 | + slot->scale2 = 1; |
1352 | + slot->angle = 0; |
1353 | +} |
1354 | + |
1355 | +static void update_slot(struct grail_impl *impl, |
1356 | + struct grail_element *slot, |
1357 | + double ds, double dc) |
1358 | +{ |
1359 | + const struct grail_element *pslot = slot->prev; |
1360 | + |
1361 | + slot->id = pslot->id; |
1362 | + slot->start_time = pslot->start_time; |
1363 | + slot->start_center = pslot->start_center; |
1364 | + slot->expect_mask = pslot->expect_mask; |
1365 | + slot->active_mask = pslot->active_mask; |
1366 | + |
1367 | + set_center_velocity_and_radius(impl, slot); |
1368 | + set_moveness_pivot_and_drag(impl, slot, ds, dc); |
1369 | + |
1370 | + slot->scale2 = pslot->scale2 * (ds * ds + dc * dc); |
1371 | + slot->angle = pslot->angle + ds / dc; /* atan2(ds, dc) */ |
1372 | +} |
1373 | + |
1374 | +static void stop_slot(struct grail_impl *impl, |
1375 | + struct grail_element *slot) |
1376 | +{ |
1377 | + const struct grail_element *pslot = slot->prev; |
1378 | + float *T = slot->transform; |
1379 | + |
1380 | + slot->id = -1; |
1381 | + slot->num_touches = 0; |
1382 | + slot->start_time = pslot->start_time; |
1383 | + slot->start_center = pslot->start_center; |
1384 | + slot->expect_mask = 0; |
1385 | + slot->active_mask = pslot->active_mask; |
1386 | + slot->center = pslot->center; |
1387 | + slot->velocity = pslot->velocity; |
1388 | + slot->radius2 = pslot->radius2; |
1389 | + T[0] = T[4] = 1; |
1390 | + T[1] = T[2] = T[3] = T[5] = 0; |
1391 | + slot->moveness = 1; |
1392 | + slot->pivot = pslot->pivot; |
1393 | + slot->drag = pslot->drag; |
1394 | + slot->scale2 = pslot->scale2; |
1395 | + slot->angle = pslot->angle; |
1396 | +} |
1397 | + |
1398 | +static void set_slot_one(struct grail_impl *impl, |
1399 | + struct grail_element *slot, |
1400 | + const struct utouch_frame *touch, |
1401 | + const struct utouch_contact *t1) |
1402 | +{ |
1403 | + const struct grail_element *pslot = slot->prev; |
1404 | + const struct utouch_contact *p1 = pslot->touches[0]; |
1405 | + |
1406 | + if (!t1->active) { |
1407 | + stop_slot(impl, slot); |
1408 | + return; |
1409 | + } |
1410 | + |
1411 | + slot->touches[0] = t1; |
1412 | + slot->num_touches = 1; |
1413 | + |
1414 | + if (pslot->num_touches != slot->num_touches || t1->id != p1->id) { |
1415 | + start_slot(impl, slot, touch); |
1416 | + return; |
1417 | + } |
1418 | + |
1419 | + update_slot(impl, slot, 0, 1); |
1420 | +} |
1421 | + |
1422 | +static void set_slot_two(struct grail_impl *impl, |
1423 | + struct grail_element *slot, |
1424 | + const struct utouch_frame *touch, |
1425 | + const struct utouch_contact *t1, |
1426 | + const struct utouch_contact *t2) |
1427 | +{ |
1428 | + const struct grail_element *pslot = slot->prev; |
1429 | + const struct utouch_contact *p1 = pslot->touches[0]; |
1430 | + const struct utouch_contact *p2 = pslot->touches[1]; |
1431 | + double tx, ty, px, py, d2; |
1432 | + |
1433 | + if (!t1->active || !t2->active) { |
1434 | + stop_slot(impl, slot); |
1435 | + return; |
1436 | + } |
1437 | + |
1438 | + slot->touches[0] = t1; |
1439 | + slot->touches[1] = t2; |
1440 | + slot->num_touches = 2; |
1441 | + |
1442 | + if (pslot->num_touches != slot->num_touches || |
1443 | + t1->id != p1->id || t2->id != p2->id) { |
1444 | + start_slot(impl, slot, touch); |
1445 | + return; |
1446 | + } |
1447 | + |
1448 | + tx = t2->x - t1->x; |
1449 | + ty = t2->y - t1->y; |
1450 | + px = p2->x - p1->x; |
1451 | + py = p2->y - p1->y; |
1452 | + |
1453 | + d2 = px * px + py * py; |
1454 | + if (d2 > 0) { |
1455 | + px /= d2; |
1456 | + py /= d2; |
1457 | + } |
1458 | + |
1459 | + update_slot(impl, slot, tx * py - ty * px, tx * px + ty * py); |
1460 | +} |
1461 | + |
1462 | +static void set_slot_multi(struct grail_impl *impl, |
1463 | + struct grail_element *slot, |
1464 | + struct grail_frame *frame, |
1465 | + const struct utouch_frame *touch) |
1466 | +{ |
1467 | + const struct grail_element *pslot = slot->prev; |
1468 | + struct grail_element **slots = frame->slots; |
1469 | + int i, j, n = impl->num_touches; |
1470 | + struct grail_element *best = 0; |
1471 | + |
1472 | + if (touch->num_active < 3) { |
1473 | + stop_slot(impl, slot); |
1474 | + return; |
1475 | + } |
1476 | + |
1477 | + memcpy(slot->touches, touch->active, |
1478 | + touch->num_active * sizeof(slot->touches[0])); |
1479 | + slot->num_touches = touch->num_active; |
1480 | + |
1481 | + if (pslot->num_touches != slot->num_touches) { |
1482 | + start_slot(impl, slot, touch); |
1483 | + return; |
1484 | + } |
1485 | + |
1486 | + for (i = 0; i < slot->num_touches; i++) { |
1487 | + if (slot->touches[i]->id != pslot->touches[i]->id) { |
1488 | + start_slot(impl, slot, touch); |
1489 | + return; |
1490 | + } |
1491 | + } |
1492 | + |
1493 | + for (i = 0; i < impl->num_touches; i++) { |
1494 | + for (j = i + 1; j < impl->num_touches; j++) { |
1495 | + struct grail_element *s = slots[n++]; |
1496 | + if (!s->num_touches) |
1497 | + continue; |
1498 | + if (!best || s->radius2 > best->radius2) |
1499 | + best = s; |
1500 | + } |
1501 | + } |
1502 | + |
1503 | + update_slot(impl, slot, best->transform[1], best->transform[0]); |
1504 | +} |
1505 | + |
1506 | +static void set_slots(struct grail_impl *impl, |
1507 | + struct grail_frame *frame, |
1508 | + const struct utouch_frame *touch) |
1509 | +{ |
1510 | + struct grail_element **slots = frame->slots; |
1511 | + struct utouch_contact *const *tc = touch->slots; |
1512 | + int i, j, n = 0; |
1513 | + |
1514 | + for (i = 0; i < impl->num_touches; i++) |
1515 | + set_slot_one(impl, slots[n++], touch, tc[i]); |
1516 | + |
1517 | + for (i = 0; i < impl->num_touches; i++) |
1518 | + for (j = i + 1; j < impl->num_touches; j++) |
1519 | + set_slot_two(impl, slots[n++], touch, tc[i], tc[j]); |
1520 | + |
1521 | + set_slot_multi(impl, slots[n++], frame, touch); |
1522 | +} |
1523 | + |
1524 | +static void collect_transforms(struct grail_impl *impl, |
1525 | + struct grail_frame *frame, |
1526 | + const struct utouch_frame *touch) |
1527 | +{ |
1528 | + const struct utouch_surface *s = utouch_frame_get_surface(impl->fh); |
1529 | + const struct grail_control *ctl = impl->ctl; |
1530 | + float c_x = ctl->bar_center_x * (s->mapped_max_x - s->mapped_min_x); |
1531 | + float c_y = ctl->bar_center_y * (s->mapped_max_y - s->mapped_min_y); |
1532 | + float d_x = ctl->bar_drag_x * (s->mapped_max_x - s->mapped_min_x); |
1533 | + float d_y = ctl->bar_drag_y * (s->mapped_max_y - s->mapped_min_y); |
1534 | + float ds2 = ctl->bar_scale * ctl->bar_scale; |
1535 | + float dt; |
1536 | + int i; |
1537 | + |
1538 | + for (i = 0; i < impl->num_slots; i++) { |
1539 | + struct grail_element *s = frame->slots[i]; |
1540 | + |
1541 | + if (!s->num_touches) |
1542 | + continue; |
1543 | + |
1544 | + dt = touch->time - s->start_time; |
1545 | + if (dt > ctl->glue_ms) { |
1546 | + unsigned int mask = s->active_mask; |
1547 | + |
1548 | + if (fabs(s->center.x - s->start_center.x) > c_x) |
1549 | + mask |= GRAIL_EXPECT_CENTER_X; |
1550 | + if (fabs(s->center.y - s->start_center.y) > c_y) |
1551 | + mask |= GRAIL_EXPECT_CENTER_Y; |
1552 | + if (fabs(s->drag.x) > d_x) |
1553 | + mask |= GRAIL_EXPECT_DRAG_X; |
1554 | + if (fabs(s->drag.y) > d_y) |
1555 | + mask |= GRAIL_EXPECT_DRAG_Y; |
1556 | + if (fabs(s->scale2 - 1) > ds2) |
1557 | + mask |= GRAIL_EXPECT_SCALE; |
1558 | + if (fabs(s->angle) > ctl->bar_angle) |
1559 | + mask |= GRAIL_EXPECT_ANGLE; |
1560 | + |
1561 | + s->active_mask = mask; |
1562 | + |
1563 | + if (dt < ctl->drop_x_ms) |
1564 | + mask |= GRAIL_EXPECT_CENTER_X; |
1565 | + if (dt < ctl->drop_y_ms) |
1566 | + mask |= GRAIL_EXPECT_CENTER_Y; |
1567 | + if (dt < ctl->drop_x_ms) |
1568 | + mask |= GRAIL_EXPECT_DRAG_X; |
1569 | + if (dt < ctl->drop_y_ms) |
1570 | + mask |= GRAIL_EXPECT_DRAG_Y; |
1571 | + if (dt < ctl->drop_scale_ms) |
1572 | + mask |= GRAIL_EXPECT_SCALE; |
1573 | + if (dt < ctl->drop_angle_ms) |
1574 | + mask |= GRAIL_EXPECT_ANGLE; |
1575 | + |
1576 | + s->expect_mask &= mask; |
1577 | + } |
1578 | + |
1579 | + frame->ongoing[frame->num_ongoing++] = s; |
1580 | + } |
1581 | +} |
1582 | + |
1583 | +const struct grail_frame GRAIL_PUBLIC * |
1584 | +grail_pump_frame(grail_handle ge, const struct utouch_frame *touch) |
1585 | +{ |
1586 | + struct grail_impl *impl = ge->impl; |
1587 | + struct grail_frame *frame = impl->frames[impl->nextframe]; |
1588 | + const struct grail_frame *prev = frame->prev; |
1589 | + int i; |
1590 | + |
1591 | + if (touch->slot_revision == touch->prev->slot_revision && |
1592 | + !prev->num_ongoing) |
1593 | + return 0; |
1594 | + |
1595 | + frame->touch = touch; |
1596 | + frame->num_ongoing = 0; |
1597 | + for (i = 0; i < impl->num_slots; i++) |
1598 | + frame->slots[i]->prev = prev->slots[i]; |
1599 | + |
1600 | + set_slots(impl, frame, touch); |
1601 | + collect_transforms(impl, frame, touch); |
1602 | + |
1603 | + impl->nextframe = (impl->nextframe + 1) % impl->num_frames; |
1604 | + |
1605 | + return frame; |
1606 | +} |
1607 | |
1608 | === modified file 'src/grail-gestures.c' |
1609 | --- src/grail-gestures.c 2011-04-07 20:46:30 +0000 |
1610 | +++ src/grail-gestures.c 2011-04-28 16:58:23 +0000 |
1611 | @@ -2,8 +2,7 @@ |
1612 | * |
1613 | * grail - Gesture Recognition And Instantiation Library |
1614 | * |
1615 | - * Copyright (C) 2010 Canonical Ltd. |
1616 | - * Copyright (C) 2010 Henrik Rydberg <rydberg@bitmath.org> |
1617 | + * Copyright (C) 2010-2011 Canonical Ltd. |
1618 | * |
1619 | * This program is free software: you can redistribute it and/or modify it |
1620 | * under the terms of the GNU General Public License as published by the |
1621 | |
1622 | === modified file 'src/grail-gestures.h' |
1623 | --- src/grail-gestures.h 2011-03-28 20:04:07 +0000 |
1624 | +++ src/grail-gestures.h 2011-04-28 16:58:23 +0000 |
1625 | @@ -2,8 +2,7 @@ |
1626 | * |
1627 | * grail - Gesture Recognition And Instantiation Library |
1628 | * |
1629 | - * Copyright (C) 2010 Canonical Ltd. |
1630 | - * Copyright (C) 2010 Henrik Rydberg <rydberg@bitmath.org> |
1631 | + * Copyright (C) 2010-2011 Canonical Ltd. |
1632 | * |
1633 | * This program is free software: you can redistribute it and/or modify it |
1634 | * under the terms of the GNU General Public License as published by the |
1635 | |
1636 | === modified file 'src/grail-impl.h' |
1637 | --- src/grail-impl.h 2011-03-17 09:46:39 +0000 |
1638 | +++ src/grail-impl.h 2011-04-28 16:58:23 +0000 |
1639 | @@ -2,8 +2,7 @@ |
1640 | * |
1641 | * grail - Gesture Recognition And Instantiation Library |
1642 | * |
1643 | - * Copyright (C) 2010 Canonical Ltd. |
1644 | - * Copyright (C) 2010 Henrik Rydberg <rydberg@bitmath.org> |
1645 | + * Copyright (C) 2010-2011 Canonical Ltd. |
1646 | * |
1647 | * This program is free software: you can redistribute it and/or modify it |
1648 | * under the terms of the GNU General Public License as published by the |
1649 | @@ -33,18 +32,56 @@ |
1650 | |
1651 | #define DIM_TOUCH 32 |
1652 | #define DIM_TOUCH_BYTES ((DIM_TOUCH + 7) >> 3) |
1653 | +#define GRAIL_ID_MAX 0xffff |
1654 | + |
1655 | +#define MIN(a, b) ((a) < (b) ? (a) : (b)) |
1656 | +#define MAX(a, b) ((a) > (b) ? (a) : (b)) |
1657 | + |
1658 | +typedef void *grail_select_callback; |
1659 | + |
1660 | +/* |
1661 | + * In this implementation, there can be N one-gestures, N (N - 1) / 2 |
1662 | + * two-gestures, and one global gesture. |
1663 | + */ |
1664 | +static inline int get_slot_count(int n) |
1665 | +{ |
1666 | + return n + n * (n - 1) / 2 + 1; |
1667 | +} |
1668 | + |
1669 | +int create_grail2(struct grail_impl *x, |
1670 | + utouch_frame_handle fh, |
1671 | + unsigned int num_frames, |
1672 | + void *select, |
1673 | + unsigned int version, |
1674 | + unsigned int control_size, |
1675 | + unsigned int frame_size, |
1676 | + unsigned int slot_size); |
1677 | + |
1678 | +void destroy_grail2(struct grail_impl *x); |
1679 | |
1680 | struct grail_impl { |
1681 | struct evemu_device *evemu; |
1682 | struct mtdev *mtdev; |
1683 | utouch_frame_handle fh; |
1684 | - const struct utouch_frame *frame; |
1685 | + const struct utouch_frame *touch; |
1686 | struct evbuf evbuf; |
1687 | struct grailbuf gbuf; |
1688 | int filter_abs; |
1689 | int ongoing; |
1690 | int gesture; |
1691 | FILE *fptest; |
1692 | + /* new stuff below */ |
1693 | + struct grail_control *ctl; |
1694 | + grail_select_callback select; |
1695 | + int num_frames; |
1696 | + int num_slots; |
1697 | + int num_touches; |
1698 | + int nextframe; |
1699 | + int seqid; |
1700 | + unsigned int control_size; |
1701 | + unsigned int frame_size; |
1702 | + unsigned int slot_size; |
1703 | + struct grail_frame **frames; |
1704 | }; |
1705 | |
1706 | #endif |
1707 | |
1708 | === added file 'src/grail-init.c' |
1709 | --- src/grail-init.c 1970-01-01 00:00:00 +0000 |
1710 | +++ src/grail-init.c 2011-04-28 16:58:23 +0000 |
1711 | @@ -0,0 +1,240 @@ |
1712 | +/***************************************************************************** |
1713 | + * |
1714 | + * grail - Gesture Recognition And Instantiation Library |
1715 | + * |
1716 | + * Copyright (C) 2010-2011 Canonical Ltd. |
1717 | + * |
1718 | + * This program is free software: you can redistribute it and/or modify it |
1719 | + * under the terms of the GNU General Public License as published by the |
1720 | + * Free Software Foundation, either version 3 of the License, or (at your |
1721 | + * option) any later version. |
1722 | + * |
1723 | + * This program is distributed in the hope that it will be useful, but |
1724 | + * WITHOUT ANY WARRANTY; without even the implied warranty of |
1725 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
1726 | + * General Public License for more details. |
1727 | + * |
1728 | + * You should have received a copy of the GNU General Public License along |
1729 | + * with this program. If not, see <http://www.gnu.org/licenses/>. |
1730 | + * |
1731 | + ****************************************************************************/ |
1732 | + |
1733 | +#include "grail-impl.h" |
1734 | +#include <stdlib.h> |
1735 | +#include <string.h> |
1736 | +#include <math.h> |
1737 | + |
1738 | +static struct grail_control *create_control(int size) |
1739 | +{ |
1740 | + struct grail_control *c = calloc(1, size); |
1741 | + |
1742 | + if (!c) |
1743 | + return 0; |
1744 | + |
1745 | + c->glue_ms = 60; |
1746 | + c->bar_center_x = 0.03; |
1747 | + c->bar_center_y = 0.03; |
1748 | + c->bar_drag_x = 0.03; |
1749 | + c->bar_drag_y = 0.03; |
1750 | + c->bar_scale = 0.3; |
1751 | + c->bar_angle = 0.1; |
1752 | + c->drop_x_ms = 300; |
1753 | + c->drop_y_ms = 300; |
1754 | + c->drop_scale_ms = 300; |
1755 | + c->drop_angle_ms = 300; |
1756 | + |
1757 | + return c; |
1758 | +} |
1759 | + |
1760 | +static void destroy_slots(struct grail_element **slots, int nslot) |
1761 | +{ |
1762 | + int i; |
1763 | + |
1764 | + if (slots) { |
1765 | + for (i = nslot - 1; i >= 0; i--) |
1766 | + free(slots[i]); |
1767 | + free(slots); |
1768 | + } |
1769 | +} |
1770 | + |
1771 | +static void destroy_frame(struct grail_frame *frame, int nslot) |
1772 | +{ |
1773 | + if (frame) { |
1774 | + destroy_slots(frame->slots, nslot); |
1775 | + free(frame->ongoing); |
1776 | + free(frame); |
1777 | + } |
1778 | +} |
1779 | + |
1780 | +static void destroy_frames(struct grail_frame **frames, int nframe, int nslot) |
1781 | +{ |
1782 | + int i; |
1783 | + |
1784 | + if (frames) { |
1785 | + for (i = nframe - 1; i >= 0; i--) |
1786 | + destroy_frame(frames[i], nslot); |
1787 | + free(frames); |
1788 | + } |
1789 | +} |
1790 | + |
1791 | +static struct grail_element **create_slots(int nslot, int ntouch, int size) |
1792 | +{ |
1793 | + struct grail_element **slots; |
1794 | + struct grail_element *s; |
1795 | + int i; |
1796 | + |
1797 | + slots = calloc(nslot, sizeof(slots[0])); |
1798 | + if (!slots) |
1799 | + return 0; |
1800 | + |
1801 | + for (i = 0; i < nslot; i++) { |
1802 | + s = calloc(1, size + ntouch * sizeof(void *)); |
1803 | + if (!s) |
1804 | + goto out; |
1805 | + s->slot = i; |
1806 | + s->id = -1; |
1807 | + s->touches = (void *)((char *)s + size); |
1808 | + slots[i] = s; |
1809 | + } |
1810 | + |
1811 | + return slots; |
1812 | + out: |
1813 | + destroy_slots(slots, nslot); |
1814 | + return 0; |
1815 | +} |
1816 | + |
1817 | +static struct grail_frame *create_frame(int nslot, int ntouch, |
1818 | + int frame_size, int slot_size) |
1819 | +{ |
1820 | + struct grail_frame *frame; |
1821 | + int i; |
1822 | + |
1823 | + frame = calloc(1, frame_size); |
1824 | + if (!frame) |
1825 | + return 0; |
1826 | + |
1827 | + frame->ongoing = calloc(nslot, sizeof(frame->ongoing[0])); |
1828 | + frame->slots = create_slots(nslot, ntouch, slot_size); |
1829 | + if (!frame->ongoing || !frame->slots) |
1830 | + goto out; |
1831 | + |
1832 | + return frame; |
1833 | + out: |
1834 | + destroy_frame(frame, nslot); |
1835 | + return 0; |
1836 | +} |
1837 | + |
1838 | +static struct grail_frame **create_frames(int nframe, int nslot, int ntouch, |
1839 | + int frame_size, int slot_size) |
1840 | +{ |
1841 | + struct grail_frame **frames; |
1842 | + struct grail_frame *f; |
1843 | + int i; |
1844 | + |
1845 | + frames = calloc(nframe, sizeof(frames[0])); |
1846 | + if (!frames) |
1847 | + return 0; |
1848 | + |
1849 | + for (i = 0; i < nframe; i++) { |
1850 | + f = create_frame(nslot, ntouch, frame_size, slot_size); |
1851 | + if (!f) |
1852 | + goto out; |
1853 | + frames[i] = f; |
1854 | + } |
1855 | + |
1856 | + return frames; |
1857 | + out: |
1858 | + destroy_frames(frames, nframe, nslot); |
1859 | + return 0; |
1860 | +} |
1861 | + |
1862 | +int create_grail2(struct grail_impl *x, |
1863 | + utouch_frame_handle fh, |
1864 | + unsigned int num_frames, |
1865 | + grail_select_callback select, |
1866 | + unsigned int version, |
1867 | + unsigned int control_size, |
1868 | + unsigned int frame_size, |
1869 | + unsigned int slot_size) |
1870 | +{ |
1871 | + struct utouch_surface *s = utouch_frame_get_surface(fh); |
1872 | + unsigned int ntouch = utouch_frame_get_num_slots(fh); |
1873 | + unsigned int nslot = get_slot_count(ntouch); |
1874 | + int i, j; |
1875 | + |
1876 | + x->select = select; |
1877 | + x->control_size = MAX(control_size, sizeof(struct grail_control)); |
1878 | + x->frame_size = MAX(frame_size, sizeof(struct grail_frame)); |
1879 | + x->slot_size = MAX(slot_size, sizeof(struct grail_element)); |
1880 | + |
1881 | + x->num_frames = num_frames; |
1882 | + x->num_slots = nslot; |
1883 | + x->num_touches = ntouch; |
1884 | + |
1885 | + x->ctl = create_control(x->control_size); |
1886 | + if (!x->ctl) |
1887 | + goto freemem; |
1888 | + |
1889 | + x->frames = create_frames(num_frames, nslot, ntouch, |
1890 | + x->frame_size, x->slot_size); |
1891 | + if (!x->frames) |
1892 | + goto freemem; |
1893 | + |
1894 | + for (i = 0; i < num_frames; i++) |
1895 | + x->frames[(i + 1) % num_frames]->prev = x->frames[i]; |
1896 | + |
1897 | + return 0; |
1898 | + |
1899 | + freemem: |
1900 | + destroy_grail2(x); |
1901 | + return -ENOMEM; |
1902 | +} |
1903 | + |
1904 | +void destroy_grail2(struct grail_impl *x) |
1905 | +{ |
1906 | + destroy_frames(x->frames, x->num_frames, x->num_slots); |
1907 | + free(x->ctl); |
1908 | +} |
1909 | + |
1910 | +grail_handle GRAIL_PUBLIC grail_new_raw(utouch_frame_handle fh, |
1911 | + unsigned int num_frames, |
1912 | + grail_select_callback select, |
1913 | + unsigned int version, |
1914 | + unsigned int control_size, |
1915 | + unsigned int frame_size, |
1916 | + unsigned int slot_size) |
1917 | +{ |
1918 | + struct grail *ge; |
1919 | + struct grail_impl *x; |
1920 | + |
1921 | + ge = calloc(1, sizeof(*ge)); |
1922 | + if (!ge) |
1923 | + return 0; |
1924 | + x = calloc(1, sizeof(*x)); |
1925 | + if (!x) |
1926 | + goto out; |
1927 | + x->fh = fh; |
1928 | + if (create_grail2(x, fh, num_frames, select, |
1929 | + version, control_size, frame_size, slot_size)) |
1930 | + goto out; |
1931 | + |
1932 | + ge->impl = x; |
1933 | + return ge; |
1934 | + |
1935 | + out: |
1936 | + free(x); |
1937 | + free(ge); |
1938 | + return 0; |
1939 | +} |
1940 | + |
1941 | +void GRAIL_PUBLIC grail_delete(grail_handle ge) |
1942 | +{ |
1943 | + destroy_grail2(ge->impl); |
1944 | + free(ge->impl); |
1945 | + free(ge); |
1946 | +} |
1947 | + |
1948 | +struct grail_control GRAIL_PUBLIC *grail_get_control(grail_handle ge) |
1949 | +{ |
1950 | + return ge->impl->ctl; |
1951 | +} |
1952 | |
1953 | === modified file 'src/grail-inserter.c' |
1954 | --- src/grail-inserter.c 2011-04-28 08:20:04 +0000 |
1955 | +++ src/grail-inserter.c 2011-04-28 16:58:23 +0000 |
1956 | @@ -2,8 +2,7 @@ |
1957 | * |
1958 | * grail - Gesture Recognition And Instantiation Library |
1959 | * |
1960 | - * Copyright (C) 2010 Canonical Ltd. |
1961 | - * Copyright (C) 2010 Henrik Rydberg <rydberg@bitmath.org> |
1962 | + * Copyright (C) 2010-2011 Canonical Ltd. |
1963 | * |
1964 | * This program is free software: you can redistribute it and/or modify it |
1965 | * under the terms of the GNU General Public License as published by the |
1966 | |
1967 | === modified file 'src/grail-inserter.h' |
1968 | --- src/grail-inserter.h 2011-03-28 20:04:20 +0000 |
1969 | +++ src/grail-inserter.h 2011-04-28 16:58:23 +0000 |
1970 | @@ -2,8 +2,7 @@ |
1971 | * |
1972 | * grail - Gesture Recognition And Instantiation Library |
1973 | * |
1974 | - * Copyright (C) 2010 Canonical Ltd. |
1975 | - * Copyright (C) 2010 Henrik Rydberg <rydberg@bitmath.org> |
1976 | + * Copyright (C) 2010-2011 Canonical Ltd. |
1977 | * |
1978 | * This program is free software: you can redistribute it and/or modify it |
1979 | * under the terms of the GNU General Public License as published by the |
1980 | |
1981 | === added file 'src/grail-legacy.c' |
1982 | --- src/grail-legacy.c 1970-01-01 00:00:00 +0000 |
1983 | +++ src/grail-legacy.c 2011-04-28 16:58:23 +0000 |
1984 | @@ -0,0 +1,65 @@ |
1985 | +/***************************************************************************** |
1986 | + * |
1987 | + * grail - Gesture Recognition And Instantiation Library |
1988 | + * |
1989 | + * Copyright (C) 2010-2011 Canonical Ltd. |
1990 | + * |
1991 | + * This program is free software: you can redistribute it and/or modify it |
1992 | + * under the terms of the GNU General Public License as published by the |
1993 | + * Free Software Foundation, either version 3 of the License, or (at your |
1994 | + * option) any later version. |
1995 | + * |
1996 | + * This program is distributed in the hope that it will be useful, but |
1997 | + * WITHOUT ANY WARRANTY; without even the implied warranty of |
1998 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
1999 | + * General Public License for more details. |
2000 | + * |
2001 | + * You should have received a copy of the GNU General Public License along |
2002 | + * with this program. If not, see <http://www.gnu.org/licenses/>. |
2003 | + * |
2004 | + ****************************************************************************/ |
2005 | + |
2006 | +#include <grail.h> |
2007 | +#include "grail-inserter.h" |
2008 | +#include <string.h> |
2009 | +#include <stdio.h> |
2010 | +#include <unistd.h> |
2011 | +#include <fcntl.h> |
2012 | +#include <malloc.h> |
2013 | +#include <errno.h> |
2014 | +#include <stdlib.h> |
2015 | + |
2016 | +#ifndef GRAIL_NO_LEGACY_ABI |
2017 | + |
2018 | +void GRAIL_PUBLIC grail_filter_abs_events(struct grail *ge, int usage) |
2019 | +{ |
2020 | + struct grail_impl *x = ge->impl; |
2021 | + x->filter_abs = usage; |
2022 | +} |
2023 | + |
2024 | +int GRAIL_PUBLIC grail_get_contacts(const struct grail *ge, |
2025 | + struct grail_contact *touch, int max_touch) |
2026 | +{ |
2027 | + const struct gesture_inserter *gin = ge->gin; |
2028 | + const struct utouch_frame *frame = ge->impl->touch; |
2029 | + int i; |
2030 | + if (frame->num_active < max_touch) |
2031 | + max_touch = frame->num_active; |
2032 | + for (i = 0; i < max_touch; i++) { |
2033 | + struct grail_contact *t = &touch[i]; |
2034 | + const struct utouch_contact *ct = frame->active[i]; |
2035 | + t->id = ct->id; |
2036 | + t->tool_type = ct->tool_type; |
2037 | + t->pos.x = ct->x; |
2038 | + t->pos.y = ct->y; |
2039 | + t->touch_major = ct->touch_major; |
2040 | + t->touch_minor = ct->touch_minor; |
2041 | + t->width_major = ct->width_major; |
2042 | + t->width_minor = ct->width_minor; |
2043 | + t->angle = ct->orientation; |
2044 | + t->pressure = ct->pressure; |
2045 | + } |
2046 | + return max_touch; |
2047 | +} |
2048 | + |
2049 | +#endif |
2050 | |
2051 | === modified file 'src/grail-recognizer.c' |
2052 | --- src/grail-recognizer.c 2011-03-28 20:04:07 +0000 |
2053 | +++ src/grail-recognizer.c 2011-04-28 16:58:23 +0000 |
2054 | @@ -2,8 +2,7 @@ |
2055 | * |
2056 | * grail - Gesture Recognition And Instantiation Library |
2057 | * |
2058 | - * Copyright (C) 2010 Canonical Ltd. |
2059 | - * Copyright (C) 2010 Henrik Rydberg <rydberg@bitmath.org> |
2060 | + * Copyright (C) 2010-2011 Canonical Ltd. |
2061 | * |
2062 | * This program is free software: you can redistribute it and/or modify it |
2063 | * under the terms of the GNU General Public License as published by the |
2064 | |
2065 | === modified file 'src/grail-recognizer.h' |
2066 | --- src/grail-recognizer.h 2011-03-28 20:04:07 +0000 |
2067 | +++ src/grail-recognizer.h 2011-04-28 16:58:23 +0000 |
2068 | @@ -2,8 +2,7 @@ |
2069 | * |
2070 | * grail - Gesture Recognition And Instantiation Library |
2071 | * |
2072 | - * Copyright (C) 2010 Canonical Ltd. |
2073 | - * Copyright (C) 2010 Henrik Rydberg <rydberg@bitmath.org> |
2074 | + * Copyright (C) 2010-2011 Canonical Ltd. |
2075 | * |
2076 | * This program is free software: you can redistribute it and/or modify it |
2077 | * under the terms of the GNU General Public License as published by the |
2078 | |
2079 | === modified file 'src/grailbuf.h' |
2080 | --- src/grailbuf.h 2011-01-02 12:06:56 +0000 |
2081 | +++ src/grailbuf.h 2011-04-28 16:58:23 +0000 |
2082 | @@ -2,8 +2,7 @@ |
2083 | * |
2084 | * grail - Gesture Recognition And Instantiation Library |
2085 | * |
2086 | - * Copyright (C) 2010 Canonical Ltd. |
2087 | - * Copyright (C) 2010 Henrik Rydberg <rydberg@bitmath.org> |
2088 | + * Copyright (C) 2010-2011 Canonical Ltd. |
2089 | * |
2090 | * This program is free software: you can redistribute it and/or modify it |
2091 | * under the terms of the GNU General Public License as published by the |
2092 | |
2093 | === modified file 'test/Makefile.am' |
2094 | --- test/Makefile.am 2011-03-17 09:47:52 +0000 |
2095 | +++ test/Makefile.am 2011-04-28 16:58:23 +0000 |
2096 | @@ -9,6 +9,7 @@ |
2097 | |
2098 | check_grail_SOURCES = \ |
2099 | check-mapping.c \ |
2100 | + check-transform.c \ |
2101 | check-grail.c |
2102 | |
2103 | check_grail_CFLAGS = \ |
2104 | |
2105 | === modified file 'test/check-grail.c' |
2106 | --- test/check-grail.c 2011-03-17 09:47:52 +0000 |
2107 | +++ test/check-grail.c 2011-04-28 16:58:23 +0000 |
2108 | @@ -3,6 +3,7 @@ |
2109 | #define LOGFILE_PREFIX "" |
2110 | |
2111 | extern Suite *make_mapping_suite(); |
2112 | +extern Suite *make_transform_suite(); |
2113 | |
2114 | int main(int argc CK_ATTRIBUTE_UNUSED, char* argv[] CK_ATTRIBUTE_UNUSED) |
2115 | { |
2116 | @@ -11,6 +12,7 @@ |
2117 | int num_failed; |
2118 | |
2119 | srunner_add_suite(sr, make_mapping_suite()); |
2120 | + srunner_add_suite(sr, make_transform_suite()); |
2121 | |
2122 | srunner_set_log(sr, "check_grail.log"); |
2123 | srunner_set_xml(sr, "check_grail.xml"); |
2124 | |
2125 | === added file 'test/check-transform.c' |
2126 | --- test/check-transform.c 1970-01-01 00:00:00 +0000 |
2127 | +++ test/check-transform.c 2011-04-28 16:58:23 +0000 |
2128 | @@ -0,0 +1,137 @@ |
2129 | +#include <check.h> |
2130 | +#include <utouch/frame-mtdev.h> |
2131 | +#include <grail.h> |
2132 | +#include <string.h> |
2133 | +#include <stdio.h> |
2134 | +#include <unistd.h> |
2135 | +#include <fcntl.h> |
2136 | +#include <stdlib.h> |
2137 | +#include <time.h> |
2138 | +#include <math.h> |
2139 | + |
2140 | +struct test_data { |
2141 | + struct evemu_device *evemu; |
2142 | + utouch_frame_handle fh; |
2143 | + grail_handle ge; |
2144 | + FILE *fp; |
2145 | + struct timeval evtime; |
2146 | +}; |
2147 | + |
2148 | +static int near(const struct grail_coord *p, float x, float y) |
2149 | +{ |
2150 | + double dx = p->x - x; |
2151 | + double dy = p->y - y; |
2152 | + return dx * dx + dy * dy < 1e-8 * (x * x + y * y); |
2153 | +} |
2154 | + |
2155 | +static int init_test_data(struct test_data *data, const char *path) |
2156 | +{ |
2157 | + memset(data, 0, sizeof(*data)); |
2158 | + |
2159 | + data->fp = fopen(path, "r"); |
2160 | + if (!data->fp) |
2161 | + return -1; |
2162 | + |
2163 | + data->evemu = evemu_new(NULL); |
2164 | + if (!data->evemu || evemu_read(data->evemu, data->fp) <= 0) |
2165 | + return -1; |
2166 | + |
2167 | + data->fh = utouch_frame_new_engine(100, 32, 100); |
2168 | + if (!data->fh || utouch_frame_init_mtdev(data->fh, data->evemu)) |
2169 | + return -1; |
2170 | + |
2171 | + data->ge = grail_new(data->fh, 10, 0); |
2172 | + if (!data->ge) |
2173 | + return -1; |
2174 | + |
2175 | + return 0; |
2176 | +} |
2177 | + |
2178 | +static void term_test_data(struct test_data *data) |
2179 | +{ |
2180 | + grail_delete(data->ge); |
2181 | + utouch_frame_delete_engine(data->fh); |
2182 | + evemu_delete(data->evemu); |
2183 | + fclose(data->fp); |
2184 | +} |
2185 | + |
2186 | +static int get_event(struct test_data *data, struct input_event *ev) |
2187 | +{ |
2188 | + return evemu_read_event_realtime(data->fp, ev, &data->evtime) > 0; |
2189 | +} |
2190 | + |
2191 | +static const struct grail_element *get_element(struct test_data *data, |
2192 | + const struct input_event *ev) |
2193 | +{ |
2194 | + const struct utouch_frame *touch; |
2195 | + const struct grail_frame *frame; |
2196 | + |
2197 | + touch = utouch_frame_pump_mtdev(data->fh, ev); |
2198 | + if (!touch) |
2199 | + return 0; |
2200 | + frame = grail_pump_frame(data->ge, touch); |
2201 | + if (!frame || !frame->num_ongoing) |
2202 | + return 0; |
2203 | + |
2204 | + return frame->ongoing[frame->num_ongoing - 1]; |
2205 | +} |
2206 | + |
2207 | +START_TEST(device_coordinates) |
2208 | +{ |
2209 | + struct test_data data; |
2210 | + struct input_event ev; |
2211 | + const struct grail_element *slot; |
2212 | + struct grail_coord pos = { 0, 0 }; |
2213 | + |
2214 | + fail_if(init_test_data(&data, "io/evemu/one-tap.evemu")); |
2215 | + |
2216 | + while (get_event(&data, &ev)) { |
2217 | + slot = get_element(&data, &ev); |
2218 | + if (slot) |
2219 | + pos = slot->center; |
2220 | + } |
2221 | + |
2222 | + fail_unless(near(&pos, 17087, 14790)); |
2223 | + |
2224 | + term_test_data(&data); |
2225 | +} |
2226 | +END_TEST |
2227 | + |
2228 | +START_TEST(mapped_coordinates) |
2229 | +{ |
2230 | + static const struct grail_coord min = { 0, 0 }, max = { 1.6, 1 }; |
2231 | + struct test_data data; |
2232 | + struct input_event ev; |
2233 | + const struct grail_element *slot; |
2234 | + struct grail_coord pos = { 0, 0 }; |
2235 | + |
2236 | + fail_if(init_test_data(&data, "io/evemu/one-tap.evemu")); |
2237 | + grail_set_bbox(data.ge, &min, &max); |
2238 | + |
2239 | + while (get_event(&data, &ev)) { |
2240 | + slot = get_element(&data, &ev); |
2241 | + if (slot) |
2242 | + pos = slot->center; |
2243 | + } |
2244 | + |
2245 | + fail_unless(near(&pos, 0.834303, 0.451338)); |
2246 | + |
2247 | + term_test_data(&data); |
2248 | +} |
2249 | +END_TEST |
2250 | + |
2251 | +Suite *make_transform_suite() |
2252 | +{ |
2253 | + Suite *s = suite_create("grail-solver"); |
2254 | + TCase *test; |
2255 | + |
2256 | + test = tcase_create("device_coordinates"); |
2257 | + tcase_add_test(test, device_coordinates); |
2258 | + suite_add_tcase(s, test); |
2259 | + |
2260 | + test = tcase_create("mapped_coordinates"); |
2261 | + tcase_add_test(test, mapped_coordinates); |
2262 | + suite_add_tcase(s, test); |
2263 | + |
2264 | + return s; |
2265 | +} |
2266 | |
2267 | === modified file 'tools/Makefile.am' |
2268 | --- tools/Makefile.am 2011-01-02 12:08:08 +0000 |
2269 | +++ tools/Makefile.am 2011-04-28 16:58:23 +0000 |
2270 | @@ -1,7 +1,15 @@ |
2271 | -bin_PROGRAMS = grail-gesture |
2272 | +bin_PROGRAMS = grail-gesture grail-test-mtdev |
2273 | + |
2274 | +if HAVE_XI |
2275 | + |
2276 | +bin_PROGRAMS += grail-transform |
2277 | + |
2278 | +endif |
2279 | |
2280 | INCLUDES=-I$(top_srcdir)/include/ |
2281 | |
2282 | -grail_gesture_SOURCES = grail-gesture.c |
2283 | -grail_gesture_LDFLAGS = -L$(top_builddir)/src/.libs/ \ |
2284 | - -lutouch-grail -lutouch-frame -lutouch-evemu -lmtdev -lm |
2285 | +AM_CFLAGS = $(X11_CFLAGS) $(XINPUT_CFLAGS) |
2286 | + |
2287 | +AM_LDFLAGS = -L$(top_builddir)/src/.libs/ \ |
2288 | + -lutouch-grail -lutouch-frame -lutouch-evemu -lmtdev \ |
2289 | + $(X11_LIBS) $(XINPUT_LIBS) -lm |
2290 | |
2291 | === modified file 'tools/grail-gesture.c' |
2292 | --- tools/grail-gesture.c 2011-04-28 08:20:04 +0000 |
2293 | +++ tools/grail-gesture.c 2011-04-28 16:58:23 +0000 |
2294 | @@ -2,7 +2,7 @@ |
2295 | * |
2296 | * grail - Gesture Recognition And Instantiation Library |
2297 | * |
2298 | - * Copyright (C) 2010 Canonical Ltd. |
2299 | + * Copyright (C) 2010-2011 Canonical Ltd. |
2300 | * |
2301 | * This program is free software: you can redistribute it and/or modify it |
2302 | * under the terms of the GNU General Public License as published by the |
2303 | @@ -17,9 +17,6 @@ |
2304 | * You should have received a copy of the GNU General Public License along |
2305 | * with this program. If not, see <http://www.gnu.org/licenses/>. |
2306 | * |
2307 | - * Authors: |
2308 | - * Henrik Rydberg <rydberg@bitmath.org> |
2309 | - * |
2310 | ****************************************************************************/ |
2311 | |
2312 | #include <grail.h> |
2313 | |
2314 | === added file 'tools/grail-test-mtdev.c' |
2315 | --- tools/grail-test-mtdev.c 1970-01-01 00:00:00 +0000 |
2316 | +++ tools/grail-test-mtdev.c 2011-04-28 16:58:23 +0000 |
2317 | @@ -0,0 +1,256 @@ |
2318 | +/***************************************************************************** |
2319 | + * |
2320 | + * grail - Gesture Recognition And Instantiation Library |
2321 | + * |
2322 | + * Copyright (C) 2010-2011 Canonical Ltd. |
2323 | + * |
2324 | + * This program is free software: you can redistribute it and/or modify it |
2325 | + * under the terms of the GNU General Public License as published by the |
2326 | + * Free Software Foundation, either version 3 of the License, or (at your |
2327 | + * option) any later version. |
2328 | + * |
2329 | + * This program is distributed in the hope that it will be useful, but |
2330 | + * WITHOUT ANY WARRANTY; without even the implied warranty of |
2331 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
2332 | + * General Public License for more details. |
2333 | + * |
2334 | + * You should have received a copy of the GNU General Public License along |
2335 | + * with this program. If not, see <http://www.gnu.org/licenses/>. |
2336 | + * |
2337 | + ****************************************************************************/ |
2338 | + |
2339 | +#define MTDEV_NO_LEGACY_API |
2340 | + |
2341 | +#include <utouch/frame-mtdev.h> |
2342 | +#include <grail.h> |
2343 | +#include <string.h> |
2344 | +#include <stdio.h> |
2345 | +#include <unistd.h> |
2346 | +#include <fcntl.h> |
2347 | +#include <math.h> |
2348 | + |
2349 | +struct frame_test { |
2350 | + struct evemu_device *evemu; |
2351 | + struct mtdev *mtdev; |
2352 | + utouch_frame_handle fh; |
2353 | + grail_handle ge; |
2354 | +}; |
2355 | + |
2356 | +static int init_evemu(struct frame_test *test, FILE *fp, int fd) |
2357 | +{ |
2358 | + test->evemu = evemu_new(NULL); |
2359 | + if (!test->evemu) |
2360 | + return -1; |
2361 | + if (fp) |
2362 | + return evemu_read(test->evemu, fp) <= 0; |
2363 | + else |
2364 | + return evemu_extract(test->evemu, fd); |
2365 | +} |
2366 | + |
2367 | +static int init_mtdev(struct frame_test *test, int fd) |
2368 | +{ |
2369 | + test->mtdev = mtdev_new_open(fd); |
2370 | + if (!test->mtdev) |
2371 | + return -1; |
2372 | + return 0; |
2373 | +} |
2374 | + |
2375 | +static int init_frame(struct frame_test *test, int fd) |
2376 | +{ |
2377 | + test->fh = utouch_frame_new_engine(100, 32, 100); |
2378 | + if (!test->fh) |
2379 | + return -1; |
2380 | + return utouch_frame_init_mtdev(test->fh, test->evemu); |
2381 | +} |
2382 | + |
2383 | +static int init_grail(struct frame_test *test) |
2384 | +{ |
2385 | + struct grail_coord min = { 0, 0 }; |
2386 | + struct grail_coord max = { 1, 1 }; |
2387 | + test->ge = grail_new(test->fh, 10, 0); |
2388 | + if (!test->ge) |
2389 | + return -1; |
2390 | + grail_set_bbox(test->ge, &min, &max); |
2391 | + return 0; |
2392 | +} |
2393 | + |
2394 | +static void destroy_all(struct frame_test *test) |
2395 | +{ |
2396 | + grail_delete(test->ge); |
2397 | + utouch_frame_delete_engine(test->fh); |
2398 | + if (test->mtdev) |
2399 | + mtdev_close_delete(test->mtdev); |
2400 | + evemu_delete(test->evemu); |
2401 | + memset(test, 0, sizeof(*test)); |
2402 | +} |
2403 | + |
2404 | +static void report_frame(grail_handle ge, |
2405 | + const struct utouch_frame *touch) |
2406 | +{ |
2407 | + const struct grail_frame *frame = grail_pump_frame(ge, touch); |
2408 | + int i; |
2409 | + |
2410 | + if (!frame) |
2411 | + return; |
2412 | + |
2413 | + fprintf(stderr, "ongoing elements: %d\n", frame->num_ongoing); |
2414 | + |
2415 | + for (i = 0; i < frame->num_ongoing; i++) { |
2416 | + const struct grail_element *slot = frame->ongoing[i]; |
2417 | + if (!slot->expect_mask) |
2418 | + continue; |
2419 | + |
2420 | + fprintf(stderr, " element %d\n", i); |
2421 | + fprintf(stderr, " slot: %d\n", slot->slot); |
2422 | + fprintf(stderr, " id: %d\n", slot->id); |
2423 | + fprintf(stderr, " num_touches: %d\n", slot->num_touches); |
2424 | + fprintf(stderr, " expect: %d\n", slot->expect_mask); |
2425 | + fprintf(stderr, " active: %d\n", slot->active_mask); |
2426 | + fprintf(stderr, " start time: %ld\n", slot->start_time); |
2427 | + fprintf(stderr, " center.x: %f\n", slot->center.x); |
2428 | + fprintf(stderr, " center.y: %f\n", slot->center.y); |
2429 | + fprintf(stderr, " velocity.x: %f\n", slot->velocity.x); |
2430 | + fprintf(stderr, " velocity.y: %f\n", slot->velocity.y); |
2431 | + fprintf(stderr, " radius2: %f\n", slot->radius2); |
2432 | + fprintf(stderr, " %+08f %+08f %+08f\n" |
2433 | + " %+08f %+08f %+08f\n" |
2434 | + " %+08f %+08f %+08f\n", |
2435 | + slot->transform[0], slot->transform[1], |
2436 | + slot->transform[2], slot->transform[3], |
2437 | + slot->transform[4], slot->transform[5], |
2438 | + slot->transform[6], slot->transform[7], |
2439 | + slot->transform[8]); |
2440 | + fprintf(stderr, " moveness: %f\n", slot->moveness); |
2441 | + fprintf(stderr, " pivot.x: %f\n", slot->pivot.x); |
2442 | + fprintf(stderr, " pivot.y: %f\n", slot->pivot.y); |
2443 | + fprintf(stderr, " drag.x: %f\n", slot->drag.x); |
2444 | + fprintf(stderr, " drag.y: %f\n", slot->drag.y); |
2445 | + fprintf(stderr, " scale2: %f\n", slot->scale2); |
2446 | + fprintf(stderr, " angle: %f\n", slot->angle); |
2447 | + } |
2448 | +} |
2449 | + |
2450 | +static void loop_device(struct frame_test *test, FILE *fp, int fd) |
2451 | +{ |
2452 | + const struct utouch_frame *frame; |
2453 | + struct input_event ev; |
2454 | + |
2455 | + if (fp) { |
2456 | + struct timeval evtime; |
2457 | + memset(&evtime, 0, sizeof(evtime)); |
2458 | + while (evemu_read_event_realtime(fp, &ev, &evtime) > 0) { |
2459 | + frame = utouch_frame_pump_mtdev(test->fh, &ev); |
2460 | + if (frame) |
2461 | + report_frame(test->ge, frame); |
2462 | + } |
2463 | + } else { |
2464 | + while (!mtdev_idle(test->mtdev, fd, 5000)) { |
2465 | + while (mtdev_get(test->mtdev, fd, &ev, 1) > 0) { |
2466 | + frame = utouch_frame_pump_mtdev(test->fh, &ev); |
2467 | + if (frame) |
2468 | + report_frame(test->ge, frame); |
2469 | + } |
2470 | + } |
2471 | + } |
2472 | +} |
2473 | + |
2474 | +static void report_device_caps(struct frame_test *test) |
2475 | +{ |
2476 | + const struct utouch_surface *s = utouch_frame_get_surface(test->fh); |
2477 | + |
2478 | + fprintf(stderr, "device props:\n"); |
2479 | + if (s->needs_pointer) |
2480 | + fprintf(stderr, "\tpointer\n"); |
2481 | + if (s->is_direct) |
2482 | + fprintf(stderr, "\tdirect\n"); |
2483 | + if (s->is_buttonpad) |
2484 | + fprintf(stderr, "\tbuttonpad\n"); |
2485 | + if (s->is_semi_mt) |
2486 | + fprintf(stderr, "\tsemi_mt\n"); |
2487 | + fprintf(stderr, "device mt events:\n"); |
2488 | + if (s->use_touch_major) |
2489 | + fprintf(stderr, "\ttouch_major\n"); |
2490 | + if (s->use_touch_minor) |
2491 | + fprintf(stderr, "\ttouch_minor\n"); |
2492 | + if (s->use_width_major) |
2493 | + fprintf(stderr, "\twidth_major\n"); |
2494 | + if (s->use_width_minor) |
2495 | + fprintf(stderr, "\twidth_minor\n"); |
2496 | + if (s->use_orientation) |
2497 | + fprintf(stderr, "\torientation\n"); |
2498 | + if (s->use_pressure) |
2499 | + fprintf(stderr, "\tpressure\n"); |
2500 | + if (s->use_distance) |
2501 | + fprintf(stderr, "\tdistance\n"); |
2502 | + |
2503 | + fprintf(stderr, "touch frames: %d\n", |
2504 | + utouch_frame_get_num_frames(test->fh)); |
2505 | + fprintf(stderr, "touch slots: %d\n", |
2506 | + utouch_frame_get_num_slots(test->fh)); |
2507 | +} |
2508 | + |
2509 | +int main(int argc, char *argv[]) |
2510 | +{ |
2511 | + struct frame_test test; |
2512 | + struct stat fs; |
2513 | + FILE *fp = 0; |
2514 | + int fd; |
2515 | + |
2516 | + if (argc < 2) { |
2517 | + fprintf(stderr, "Usage: %s <device>\n", argv[0]); |
2518 | + return -1; |
2519 | + } |
2520 | + |
2521 | + memset(&test, 0, sizeof(test)); |
2522 | + |
2523 | + fd = open(argv[1], O_RDONLY | O_NONBLOCK); |
2524 | + if (fd < 0) { |
2525 | + fprintf(stderr, "error: could not open device\n"); |
2526 | + return -1; |
2527 | + } |
2528 | + if (fstat(fd, &fs)) { |
2529 | + fprintf(stderr, "error: could not stat the device\n"); |
2530 | + return -1; |
2531 | + } |
2532 | + if (!fs.st_rdev) |
2533 | + fp = fdopen(fd, "r"); |
2534 | + |
2535 | + if (!fp && ioctl(fd, EVIOCGRAB, 1)) { |
2536 | + fprintf(stderr, "error: could not grab the device\n"); |
2537 | + return -1; |
2538 | + } |
2539 | + |
2540 | + if (init_evemu(&test, fp, fd)) { |
2541 | + fprintf(stderr, "error: could not describe device\n"); |
2542 | + return -1; |
2543 | + } |
2544 | + if (!utouch_frame_is_supported_mtdev(test.evemu)) { |
2545 | + fprintf(stderr, "error: unsupported device\n"); |
2546 | + return -1; |
2547 | + } |
2548 | + |
2549 | + fprintf(stderr, "device: %s\n", evemu_get_name(test.evemu)); |
2550 | + |
2551 | + if (!fp && init_mtdev(&test, fd)) { |
2552 | + fprintf(stderr, "error: could not init mtdev\n"); |
2553 | + return -1; |
2554 | + } |
2555 | + if (init_frame(&test, fd)) { |
2556 | + fprintf(stderr, "error: could not init frame\n"); |
2557 | + return -1; |
2558 | + } |
2559 | + if (init_grail(&test)) { |
2560 | + fprintf(stderr, "error: could not init grail\n"); |
2561 | + return -1; |
2562 | + } |
2563 | + |
2564 | + report_device_caps(&test); |
2565 | + |
2566 | + loop_device(&test, fp, fd); |
2567 | + |
2568 | + destroy_all(&test); |
2569 | + |
2570 | + if (fs.st_rdev) |
2571 | + ioctl(fd, EVIOCGRAB, 0); |
2572 | + return 0; |
2573 | +} |
2574 | |
2575 | === added file 'tools/grail-transform.c' |
2576 | --- tools/grail-transform.c 1970-01-01 00:00:00 +0000 |
2577 | +++ tools/grail-transform.c 2011-04-28 16:58:23 +0000 |
2578 | @@ -0,0 +1,371 @@ |
2579 | +/***************************************************************************** |
2580 | + * |
2581 | + * grail - Gesture Recognition And Instantiation Library |
2582 | + * |
2583 | + * Copyright (C) 2010-2011 Canonical Ltd. |
2584 | + * |
2585 | + * This program is free software: you can redistribute it and/or modify it |
2586 | + * under the terms of the GNU General Public License as published by the |
2587 | + * Free Software Foundation, either version 3 of the License, or (at your |
2588 | + * option) any later version. |
2589 | + * |
2590 | + * This program is distributed in the hope that it will be useful, but |
2591 | + * WITHOUT ANY WARRANTY; without even the implied warranty of |
2592 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
2593 | + * General Public License for more details. |
2594 | + * |
2595 | + * You should have received a copy of the GNU General Public License along |
2596 | + * with this program. If not, see <http://www.gnu.org/licenses/>. |
2597 | + * |
2598 | + ****************************************************************************/ |
2599 | + |
2600 | +#include "config.h" |
2601 | +#include <evemu.h> |
2602 | +#include <utouch/frame-mtdev.h> |
2603 | +#include <utouch/frame-xi2.h> |
2604 | +#include <grail.h> |
2605 | +#include <stdio.h> |
2606 | +#include <stdlib.h> |
2607 | +#include <unistd.h> |
2608 | +#include <fcntl.h> |
2609 | +#include <string.h> |
2610 | +#include <math.h> |
2611 | + |
2612 | +struct appdata { |
2613 | + int opcode; |
2614 | + struct grail_coord min, max; |
2615 | + int fd; |
2616 | + struct evemu_device *evemu; |
2617 | + struct mtdev *mtdev; |
2618 | + utouch_frame_handle fh; |
2619 | + struct grail *ge; |
2620 | + |
2621 | + struct grail_coord pos[4]; |
2622 | + struct grail_coord touch[32]; |
2623 | + struct grail_coord pivot; |
2624 | + XPoint pts[5]; |
2625 | + int ntouch; |
2626 | + |
2627 | + Display *dsp; |
2628 | + Window win; |
2629 | + GC gc; |
2630 | + int screen; |
2631 | + float off_x, off_y; |
2632 | + unsigned long white, black; |
2633 | +}; |
2634 | + |
2635 | +static void clear_screen(struct appdata *w) |
2636 | +{ |
2637 | + const struct utouch_surface *s = utouch_frame_get_surface(w->fh); |
2638 | + int width = s->mapped_max_x - s->mapped_min_x; |
2639 | + int height = s->mapped_max_y - s->mapped_min_y; |
2640 | + int i; |
2641 | + |
2642 | + XSetForeground(w->dsp, w->gc, w->white); |
2643 | + XFillRectangle(w->dsp, w->win, w->gc, 0, 0, width, height); |
2644 | + |
2645 | + for (i = 0; i < 5; i++) { |
2646 | + w->pts[i].x = w->pos[i % 4].x - w->off_x; |
2647 | + w->pts[i].y = w->pos[i % 4].y - w->off_y; |
2648 | + } |
2649 | + |
2650 | + XSetForeground(w->dsp, w->gc, w->black); |
2651 | + XDrawLines(w->dsp, w->win, w->gc, w->pts, 5, CoordModeOrigin); |
2652 | + |
2653 | +} |
2654 | + |
2655 | +static void draw_object(struct appdata *w) |
2656 | +{ |
2657 | + static const double frac = 0.01; |
2658 | + const struct utouch_surface *s = utouch_frame_get_surface(w->fh); |
2659 | + double d = frac * (s->mapped_max_x - s->mapped_min_x); |
2660 | + int i; |
2661 | + |
2662 | + XDrawLines(w->dsp, w->win, w->gc, w->pts, 5, CoordModeOrigin); |
2663 | + |
2664 | + XFillArc(w->dsp, w->win, w->gc, |
2665 | + w->pivot.x - d / 2, w->pivot.y - d / 2, |
2666 | + d, d, 0, 360 * 64); |
2667 | + |
2668 | + d *= 4; |
2669 | + for (i = 0; i < w->ntouch; i++) |
2670 | + XFillArc(w->dsp, w->win, w->gc, |
2671 | + w->touch[i].x - d / 2, w->touch[i].y - d / 2, |
2672 | + d, d, 0, 360 * 64); |
2673 | +} |
2674 | + |
2675 | +static void report_frame(struct appdata *w, |
2676 | + const struct utouch_frame *touch) |
2677 | +{ |
2678 | + const struct grail_control *ctl = grail_get_control(w->ge); |
2679 | + const struct grail_frame *frame; |
2680 | + const struct grail_element *slot; |
2681 | + struct grail_coord tmp; |
2682 | + int i; |
2683 | + |
2684 | + if (!touch) |
2685 | + return; |
2686 | + |
2687 | + frame = grail_pump_frame(w->ge, touch); |
2688 | + if (!frame || !frame->num_ongoing || !frame->prev->num_ongoing) |
2689 | + return; |
2690 | + |
2691 | + slot = frame->ongoing[frame->num_ongoing - 1]; |
2692 | + if (slot->transform[0] == 0 && slot->transform[1] == 0) |
2693 | + return; |
2694 | + |
2695 | + for (i = 0; i < 4; i++) { |
2696 | + grail_element_transform(slot, &tmp, &w->pos[i]); |
2697 | + w->pos[i] = tmp; |
2698 | + } |
2699 | + |
2700 | + XSetForeground(w->dsp, w->gc, w->white); |
2701 | + draw_object(w); |
2702 | + |
2703 | + w->ntouch = touch->num_active; |
2704 | + for (i = 0; i < w->ntouch; i++) { |
2705 | + w->touch[i].x = touch->active[i]->x - w->off_x; |
2706 | + w->touch[i].y = touch->active[i]->y - w->off_y; |
2707 | + } |
2708 | + |
2709 | + w->pivot.x = slot->pivot.x - w->off_x; |
2710 | + w->pivot.y = slot->pivot.y - w->off_y; |
2711 | + |
2712 | + for (i = 0; i < 5; i++) { |
2713 | + w->pts[i].x = w->pos[i % 4].x - w->off_x; |
2714 | + w->pts[i].y = w->pos[i % 4].y - w->off_y; |
2715 | + } |
2716 | + |
2717 | + XSetForeground(w->dsp, w->gc, w->black); |
2718 | + draw_object(w); |
2719 | + |
2720 | + XFlush(w->dsp); |
2721 | +} |
2722 | + |
2723 | +static int init_window(struct appdata *w) |
2724 | +{ |
2725 | + int event, err; |
2726 | + |
2727 | + w->pos[0].x = 100; |
2728 | + w->pos[0].y = 100; |
2729 | + w->pos[1].x = 200; |
2730 | + w->pos[1].y = 100; |
2731 | + w->pos[2].x = 200; |
2732 | + w->pos[2].y = 200; |
2733 | + w->pos[3].x = 100; |
2734 | + w->pos[3].y = 200; |
2735 | + |
2736 | + w->dsp = XOpenDisplay(NULL); |
2737 | + if (!w->dsp) |
2738 | + return -1; |
2739 | + if (!XQueryExtension(w->dsp, "XInputExtension", |
2740 | + &w->opcode, &event, &err)) |
2741 | + return -1; |
2742 | + |
2743 | + w->screen = DefaultScreen(w->dsp); |
2744 | + w->white = WhitePixel(w->dsp, w->screen); |
2745 | + w->black = BlackPixel(w->dsp, w->screen); |
2746 | + |
2747 | + w->win = XCreateSimpleWindow(w->dsp, XDefaultRootWindow(w->dsp), |
2748 | + 0, 0, 600, 600, 0, w->black, w->white); |
2749 | + w->gc = DefaultGC(w->dsp, w->screen); |
2750 | + |
2751 | + XMapWindow(w->dsp, w->win); |
2752 | + XFlush(w->dsp); |
2753 | + |
2754 | + return 0; |
2755 | +} |
2756 | + |
2757 | +static void term_window(struct appdata *w) |
2758 | +{ |
2759 | + XDestroyWindow(w->dsp, w->win); |
2760 | + XCloseDisplay(w->dsp); |
2761 | +} |
2762 | + |
2763 | +static void set_screen_size_mtdev(struct appdata *w, XEvent *xev) |
2764 | +{ |
2765 | + struct utouch_surface *s = utouch_frame_get_surface(w->fh); |
2766 | + XConfigureEvent *cev = (XConfigureEvent *)xev; |
2767 | + |
2768 | + s->mapped_min_x = 0; |
2769 | + s->mapped_min_y = 0; |
2770 | + s->mapped_max_x = DisplayWidth(w->dsp, w->screen); |
2771 | + s->mapped_max_y = DisplayHeight(w->dsp, w->screen); |
2772 | + s->mapped_max_pressure = 1; |
2773 | + |
2774 | + if (cev) { |
2775 | + w->off_x = cev->x; |
2776 | + w->off_y = cev->y; |
2777 | + } |
2778 | +} |
2779 | + |
2780 | +static void loop_device_mtdev(struct appdata *w) |
2781 | +{ |
2782 | + const struct utouch_frame *tf; |
2783 | + struct input_event iev; |
2784 | + XEvent xev; |
2785 | + |
2786 | + clear_screen(w); |
2787 | + |
2788 | + set_screen_size_mtdev(w, 0); |
2789 | + XSelectInput(w->dsp, w->win, StructureNotifyMask); |
2790 | + |
2791 | + while (1) { |
2792 | + while (!mtdev_idle(w->mtdev, w->fd, 100)) { |
2793 | + while (mtdev_get(w->mtdev, w->fd, &iev, 1) > 0) { |
2794 | + tf = utouch_frame_pump_mtdev(w->fh, &iev); |
2795 | + report_frame(w, tf); |
2796 | + } |
2797 | + } |
2798 | + while (XPending(w->dsp)) { |
2799 | + XNextEvent(w->dsp, &xev); |
2800 | + set_screen_size_mtdev(w, &xev); |
2801 | + } |
2802 | + } |
2803 | +} |
2804 | + |
2805 | +static int run_mtdev(struct appdata *w, const char *path) |
2806 | +{ |
2807 | + w->fd = open(path, O_RDONLY | O_NONBLOCK); |
2808 | + if (w->fd < 0) { |
2809 | + fprintf(stderr, "error: could not open device\n"); |
2810 | + return -1; |
2811 | + } |
2812 | + if (ioctl(w->fd, EVIOCGRAB, 1)) { |
2813 | + fprintf(stderr, "error: could not grab the device\n"); |
2814 | + return -1; |
2815 | + } |
2816 | + |
2817 | + w->evemu = evemu_new(NULL); |
2818 | + if (!w->evemu) |
2819 | + return -1; |
2820 | + if (evemu_extract(w->evemu, w->fd)) |
2821 | + return -1; |
2822 | + w->mtdev = mtdev_new_open(w->fd); |
2823 | + if (!w->mtdev) |
2824 | + return -1; |
2825 | + w->fh = utouch_frame_new_engine(500, 32, 100); |
2826 | + if (!w->fh) |
2827 | + return -1; |
2828 | + if (utouch_frame_init_mtdev(w->fh, w->evemu)) |
2829 | + return -1; |
2830 | + w->ge = grail_new(w->fh, 100, 0); |
2831 | + if (!w->ge) |
2832 | + return -1; |
2833 | + |
2834 | + grail_get_control(w->ge)->drop_x_ms = 1e8; |
2835 | + grail_get_control(w->ge)->drop_y_ms = 1e8; |
2836 | + grail_get_control(w->ge)->drop_scale_ms = 1e8; |
2837 | + grail_get_control(w->ge)->drop_angle_ms = 1e8; |
2838 | + |
2839 | + loop_device_mtdev(w); |
2840 | + |
2841 | + grail_delete(w->ge); |
2842 | + utouch_frame_delete_engine(w->fh); |
2843 | + mtdev_close_delete(w->mtdev); |
2844 | + evemu_delete(w->evemu); |
2845 | + |
2846 | + ioctl(w->fd, EVIOCGRAB, 0); |
2847 | + close(w->fd); |
2848 | +} |
2849 | + |
2850 | +#if HAVE_XI |
2851 | +static void loop_device_xi2(struct appdata *w, int id) |
2852 | +{ |
2853 | + const struct utouch_frame *tf; |
2854 | + XIEventMask mask; |
2855 | + |
2856 | + mask.deviceid = id; |
2857 | + mask.mask_len = XIMaskLen(XI_LASTEVENT); |
2858 | + mask.mask = calloc(mask.mask_len, sizeof(char)); |
2859 | + |
2860 | + XISetMask(mask.mask, XI_TouchBegin); |
2861 | + XISetMask(mask.mask, XI_TouchUpdate); |
2862 | + XISetMask(mask.mask, XI_TouchEnd); |
2863 | + XISetMask(mask.mask, XI_PropertyEvent); |
2864 | + XISelectEvents(w->dsp, w->win, &mask, 1); |
2865 | + |
2866 | + XSelectInput(w->dsp, DefaultRootWindow(w->dsp), StructureNotifyMask); |
2867 | + |
2868 | + while (1) { |
2869 | + XEvent ev; |
2870 | + XIDeviceEvent *event = (void *)&ev; |
2871 | + XGenericEventCookie *cookie = &ev.xcookie; |
2872 | + XNextEvent(w->dsp, &ev); |
2873 | + |
2874 | + if (XGetEventData(w->dsp, cookie) && |
2875 | + cookie->type == GenericEvent && |
2876 | + cookie->extension == w->opcode) { |
2877 | + tf = utouch_frame_pump_xi2(w->fh, cookie->data); |
2878 | + report_frame(w, tf); |
2879 | + } |
2880 | + XFreeEventData(w->dsp, cookie); |
2881 | + } |
2882 | + |
2883 | +} |
2884 | + |
2885 | +static int run_xi2(struct appdata *w, int id) |
2886 | +{ |
2887 | + XIDeviceInfo *info, *dev; |
2888 | + int ndevices, i; |
2889 | + |
2890 | + info = XIQueryDevice(w->dsp, XIAllDevices, &ndevices); |
2891 | + dev = 0; |
2892 | + for (i = 0; i < ndevices; i++) |
2893 | + if (info[i].deviceid == id) |
2894 | + dev = &info[i]; |
2895 | + if (!dev) |
2896 | + return -1; |
2897 | + |
2898 | + w->fh = utouch_frame_new_engine(500, 32, 100); |
2899 | + if (!w->fh) |
2900 | + return -1; |
2901 | + if (utouch_frame_init_xi2(w->fh, w->dsp, dev)) |
2902 | + return -1; |
2903 | + w->ge = grail_new(w->fh, 100, 0); |
2904 | + if (!w->ge) |
2905 | + return -1; |
2906 | + |
2907 | + loop_device_xi2(w, id); |
2908 | + |
2909 | + grail_delete(w->ge); |
2910 | + utouch_frame_delete_engine(w->fh); |
2911 | + |
2912 | + XIFreeDeviceInfo(info); |
2913 | + |
2914 | + return 0; |
2915 | +} |
2916 | +#else |
2917 | +static int run_xi2(struct appdata *w, int id) |
2918 | +{ |
2919 | + fprintf(stderr, "X not supported in this build (use --with-xi)\n"); |
2920 | + return 0; |
2921 | +} |
2922 | +#endif |
2923 | + |
2924 | +int main(int argc, char **argv) |
2925 | +{ |
2926 | + struct appdata w; |
2927 | + int id, ret; |
2928 | + |
2929 | + if (argc < 2) { |
2930 | + fprintf(stderr, "Usage: %s <device>\n", argv[0]); |
2931 | + return -1; |
2932 | + } |
2933 | + |
2934 | + memset(&w, 0, sizeof(w)); |
2935 | + |
2936 | + if (init_window(&w)) |
2937 | + return -1; |
2938 | + |
2939 | + id = atoi(argv[1]); |
2940 | + |
2941 | + if (id) |
2942 | + ret = run_xi2(&w, id); |
2943 | + else |
2944 | + ret = run_mtdev(&w, argv[1]); |
2945 | + |
2946 | + term_window(&w); |
2947 | + |
2948 | + return ret; |
2949 | +} |
Another rebase, triggered by stuff that went into trunk already. Gesture documentation augmentation folded into this series as well.