Merge lp:~bijanbina/ginn/GIR into lp:ginn

Proposed by Bijan Binaee
Status: Rejected
Rejected by: Stephen M. Webb
Proposed branch: lp:~bijanbina/ginn/GIR
Merge into: lp:ginn
Diff against target: 2447 lines (+1339/-977)
18 files modified
.directory (+6/-0)
configure.ac (+1/-0)
src/Makefile.am (+3/-2)
src/README (+5/-0)
src/bamf.c (+0/-48)
src/bamf.cpp (+48/-0)
src/config.c (+0/-200)
src/config.cpp (+202/-0)
src/config.h (+70/-27)
src/ginn.c (+0/-592)
src/ginn.cpp (+555/-0)
src/ginn.h (+60/-0)
src/gir.cpp (+47/-0)
src/gir.h (+70/-0)
src/header.h (+38/-0)
src/main.cpp (+137/-0)
src/xt.c (+0/-108)
src/xt.cpp (+97/-0)
To merge this branch: bzr merge lp:~bijanbina/ginn/GIR
Reviewer Review Type Date Requested Status
Chase Douglas (community) Disapprove
Stephen M. Webb (community) Needs Fixing
Review via email: mp+72521@code.launchpad.net

Description of the change

1. port GINN to c++
2. use string instead of char *
3. fix all error with c++ compiler
4. create Gwish class instead of wish struct
5. add Gwish Type (geusture Type) instead of config_attr[0] to make code more readable and replace it in all part of code
6. add Gwish TouchNum (Number of finger for gesture) instead of config_attr[1] to make code more readable and replace it to all part of code
5. create GINN object and create a dynamic callback for GINN object
6. use "new" instead of memloc
7. remove all global variable and embed all of them in class
8. create qt project file for ginn
9. use cout and cerr instead of fprintf
10. abstract the main file and create the code more functionally
11. test all new changes and check are they stable or not
12. create constractor for apps and make Gapps object instead it
13. create callback for device add , remove and change with object oriented concept
14. create GD_att struct to save and access device attributes
15. create device list vector
16. find device attribute with just having device ID!(perfectly useful)
17. make code more readable
18. add comment to code and use simple name for variable
19. add some option to wish.xml to define some gesture for only touchscreen
20. add some option to wish.xml to define some gesture for only touchpad
21. compatible fully with last GINN branch
---------------------------------------------------------------------------------------------------------------------------------------
##################<Define Gesture Run On Which Device>#####################
1. open wish.xml
2. find what gesture you want to classify for example you select some thing like this:

    <wish gesture="Drag" fingers="2">
      <action name="action5" when="update">
        <trigger prop="delta y" min="20" max="80"/>
        <button>4</button>
      </action>
    </wish>

3. change <wish gesture="Drag" fingers="2"> to
<wish gesture="Drag" fingers="2" screen="true">
4. if you want to your gesture run only on touchpad change screen prop to false else now your
gesture only run on touch screen
-------------------------------------------------------------------------------------------------------------------------------------

To post a comment you must log in.
Revision history for this message
Stephen M. Webb (bregma) wrote :

I have a number of issues with this proposal.

(1) You need to explicitly justify moving from C to C++. In particular, renaming all existing C sources to C++. What does the project gain from this? What are the possible repercussions (ie. what new problems are introduced and what new potential for error is obtained)? The renaming introduces a lot of noise that makes it difficult to evaluate the rest of the change.

(2) This merge marks most sources as executable. That is undesirable.

(3) What is the .directory file? It does not appear to be necessary to build the project.

(4) Please do not use ///-style or //!-style comments, use Javadoc-style (/**) comments for consistency with the style of other uTouch projects.

(5) The various classes implement their own containers. Is there a good reason not to use the (tested, dependable) standard library instead? One of the main advantages to porting to C++ is the ability to use the C++ library.

(6) None of this code is exception safe. When errors are encountered, resources are leaked or undefined behaviour is encountered.

(7) There is no cleanup: objects are created using new but never deleted.

(8) Class constructors are assigning initial values to members in the constructor body instead of using initializer lists. Most of the classes are C structs that rely on external code to maintain their invariants: what is the point of converting to C++ if the code is just non-OO style C? See http://en.wikipedia.org/wiki/Class_invariant.

(9) Why add a capital G or D to classes and function names? This does not contribute to readability in a positive way. If this is to represent words like "device" or "gesture", use those words. We are not experiencing a shortage of ASCII.

(10) Some variable names could reflect their purpose better: for example, what is "local" used for?

(11) "header.h" is not an acceptable header file name. Also, please do not create a single header file to include all other header files any source file might need. Headers should pull in only the minimal subset of headers they need to compile on their own. Never put a "using namespace" directive in a header file.

(12) GINN::Dadded catches an exception of type error_t, but there is no code inside the try-block that can throw such a type. The only exception possible from the try-block is std::bad_alloc.

(13) Please leave at least one blank line between function definitions for readability.

review: Needs Fixing
Revision history for this message
Bijan Binaee (bijanbina) wrote :
Download full text (3.4 KiB)

> I have a number of issues with this proposal.
>
> (1) You need to explicitly justify moving from C to C++. In particular,
> renaming all existing C sources to C++. What does the project gain from this?
> What are the possible repercussions (ie. what new problems are introduced and
> what new potential for error is obtained)? The renaming introduces a lot of
> noise that makes it difficult to evaluate the rest of the change.
>
> (2) This merge marks most sources as executable. That is undesirable.
>
> (3) What is the .directory file? It does not appear to be necessary to build
> the project.
>
> (4) Please do not use ///-style or //!-style comments, use Javadoc-style (/**)
> comments for consistency with the style of other uTouch projects.
>
> (5) The various classes implement their own containers. Is there a good
> reason not to use the (tested, dependable) standard library instead? One of
> the main advantages to porting to C++ is the ability to use the C++ library.
>
> (6) None of this code is exception safe. When errors are encountered,
> resources are leaked or undefined behaviour is encountered.
>
> (7) There is no cleanup: objects are created using new but never deleted.
>
> (8) Class constructors are assigning initial values to members in the
> constructor body instead of using initializer lists. Most of the classes are
> C structs that rely on external code to maintain their invariants: what is
> the point of converting to C++ if the code is just non-OO style C? See
> http://en.wikipedia.org/wiki/Class_invariant.
>
> (9) Why add a capital G or D to classes and function names? This does not
> contribute to readability in a positive way. If this is to represent words
> like "device" or "gesture", use those words. We are not experiencing a
> shortage of ASCII.
>
> (10) Some variable names could reflect their purpose better: for example,
> what is "local" used for?
>
> (11) "header.h" is not an acceptable header file name. Also, please do not
> create a single header file to include all other header files any source file
> might need. Headers should pull in only the minimal subset of headers they
> need to compile on their own. Never put a "using namespace" directive in a
> header file.
>
> (12) GINN::Dadded catches an exception of type error_t, but there is no code
> inside the try-block that can throw such a type. The only exception possible
> from the try-block is std::bad_alloc.
>
> (13) Please leave at least one blank line between function definitions for
> readability.

1: if you think renaming is getting you to trouble so i must do what to port to c++
2: No why you think so
3: i remove it if the code accepted
4: the comment is not part of code! please review the code not comment!
5: can you make instance in my code
6: can you make instance in my code
7: it's the c++ advantage unlike C it delete them automatically
8: it's only on some classes and it is because if we change it need to recreate a code fuly again!!
9: if you use a very long function name you made the developer get to pitfall it's the best way to simple the develop process and have various advantage
10: it use to create a local copy ...

Read more...

Revision history for this message
Chase Douglas (chasedouglas) wrote :
Download full text (3.5 KiB)

First, Stephen has noted many issues with the changes. I agree with all of them, so it makes sense to have them fixed before doing any further review of the code.

> 1: if you think renaming is getting you to trouble so i must do what to port
> to c++

It's not the renaming that is the problem. If the renaming provided some benefits it would be acceptable. However, the renaming here is to allow for C++ compilation. Thus, there needs to be worthwhile C++ usage or else we could just leave it as C.

This hits at a big issue with the changes. I don't think you fully understand C++, how to use it properly, and how to make code better and more readable with it. Ginn could benefit greatly from being converted to C++. However, these changes do not make the code better.

> 2: No why you think so

See the preview diff below. There are lines like:

=== modified file 'COPYING' (properties changed: -x to +x)

> 3: i remove it if the code accepted

The way to fix this is to remove it in your branch, commit the change, and then push it to this branch on launchpad.net. That will update the merge proposal.

> 4: the comment is not part of code! please review the code not comment!

Comments are just as important as the code. Style matters in keeping things readable. Thus, we review comments too.

> 5: can you make instance in my code
> 6: can you make instance in my code

These are very basic and fundamental concepts of how to write C++. You are asking us to teach you C++. Unfortunately, we don't have enough time to do that. Instead, please try to learn C++ best practices by reading books or searching online for information.

> 7: it's the c++ advantage unlike C it delete them automatically

No, that is incorrect. You must delete C++ objects created with new.

> 8: it's only on some classes and it is because if we change it need to
> recreate a code fuly again!!

This is part of the fundamental aspects of C++. It needs to conform to normal C++ coding standards.

> 9: if you use a very long function name you made the developer get to pitfall
> it's the best way to simple the develop process and have various advantage

There are many possible ways to name functions, with many different reasons for why they are named a certain way. Normally, you should try to stay consistent with the existing code, and ensure that the names are obvious. Adding 'G' and 'D' to the beginning of function names does not have an obvious meaning.

> 10: it use to create a local copy of ginn object that is load for device .it's
> show the duty fully

You can name it "ginn" or something more descriptive. "local" is too generic for a variable name.

> 11: i like this way;also adding header not make your software slow!

You can add a header, that's not the issue. The issue is that the name of the header is too generic. The name needs to give some idea as to what is defined in the header.

> 12: it's an static error ,add error_t is for just through of the compiler
> error. also use error_t for dynamic error.

I don't think you understand how exceptions work. Please look up C++ exception handling.

> 13: the comment is not part of code! please review the code not comment!

This has nothing t...

Read more...

review: Disapprove

Unmerged revisions

90. By Bijan Binaee

GIR

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file '.bzrignore' (properties changed: -x to +x)
2=== added file '.directory'
3--- .directory 1970-01-01 00:00:00 +0000
4+++ .directory 2011-08-23 04:19:23 +0000
5@@ -0,0 +1,6 @@
6+[Dolphin]
7+Timestamp=2011,8,23,8,9,6
8+Version=2
9+
10+[Settings]
11+ShowDotFiles=true
12
13=== modified file 'COPYING' (properties changed: -x to +x)
14=== modified file 'INSTALL' (properties changed: -x to +x)
15=== modified file 'Makefile.am' (properties changed: -x to +x)
16=== modified file 'README' (properties changed: -x to +x)
17=== modified file 'configure.ac' (properties changed: -x to +x)
18--- configure.ac 2011-05-17 12:46:31 +0000
19+++ configure.ac 2011-08-23 04:19:23 +0000
20@@ -20,6 +20,7 @@
21
22 # Checks for programs.
23 AC_PROG_CC
24+AC_PROG_CXX
25 AC_PROG_INSTALL
26
27 PKG_CHECK_MODULES([GEIS], [libutouch-geis >= 1.0.10])
28
29=== modified file 'etc/Makefile.am' (properties changed: -x to +x)
30=== modified file 'etc/appNames' (properties changed: -x to +x)
31=== modified file 'etc/attributes' (properties changed: -x to +x)
32=== modified file 'etc/buttons' (properties changed: -x to +x)
33=== modified file 'etc/ginn.desktop' (properties changed: -x to +x)
34=== modified file 'etc/keys' (properties changed: -x to +x)
35=== modified file 'etc/wishes.xml' (properties changed: -x to +x)
36=== modified file 'ginn.pc.in' (properties changed: -x to +x)
37=== modified file 'src/Makefile.am' (properties changed: -x to +x)
38--- src/Makefile.am 2011-02-04 16:04:30 +0000
39+++ src/Makefile.am 2011-08-23 04:19:23 +0000
40@@ -1,8 +1,9 @@
41 bin_PROGRAMS = ginn
42 man1_MANS = ginn.1
43
44-ginn_SOURCES = ginn.c config.h config.c xt.c bamf.c
45-ginn_CFLAGS = \
46+ginn_SOURCES = bamf.cpp config.cpp ginn.cpp gir.cpp main.cpp xt.cpp
47+
48+ginn_CXXFLAGS = \
49 -DGINN_CONFIG_DIR=\"$(sysconfdir)/ginn\" \
50 $(GEIS_CFLAGS) $(XTST_CFLAGS) $(X11_CFLAGS) $(XML2_CFLAGS) $(BAMF_CFLAGS)
51 ginn_LDFLAGS = $(GEIS_LIBS) $(XTST_LIBS) $(X11_LIBS) $(XML2_LIBS) $(BAMF_LIBS)
52
53=== added file 'src/README'
54--- src/README 1970-01-01 00:00:00 +0000
55+++ src/README 2011-08-23 04:19:23 +0000
56@@ -0,0 +1,5 @@
57+To compile GIR you need some packages to install theme simply execute install.sh
58+
59+note: this install script work for just debian base system
60+
61+Enjoy!!
62\ No newline at end of file
63
64=== removed file 'src/bamf.c'
65--- src/bamf.c 2011-05-20 19:34:26 +0000
66+++ src/bamf.c 1970-01-01 00:00:00 +0000
67@@ -1,48 +0,0 @@
68-/*
69- * Copyright 2010 Canonical Ltd.
70- *
71- * This library is free software; you can redistribute it and/or modify it under
72- * the terms of the GNU General Public License as published by the Free Software
73- * Foundation; either version 3 of the License, or (at your option) any later
74- * version.
75- *
76- * This library is distributed in the hope that it will be useful, but WITHOUT
77- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
78- * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
79- * details.
80- *
81- * You should have received a copy of the GNU General Public License along with
82- * this program; if not, write to the Free Software Foundation, Inc., 51
83- * Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
84- */
85-
86-#include <libbamf/bamf-matcher.h>
87-#include <string.h>
88-
89-char *getName(char *deskfile)
90-{
91- char *temp;
92- temp = strdup(strrchr(deskfile, '/'));
93- return strndup(temp + 1, strlen(temp) - 9);
94-}
95-
96-char *getCurrentApp()
97-{
98- g_type_init();
99- char *deskfile, *appName;
100- char *temp;
101-
102- BamfApplication *app =
103- bamf_matcher_get_active_application(bamf_matcher_get_default());
104- if (app) {
105- appName = (char *) bamf_view_get_name(BAMF_VIEW(app));
106- temp = bamf_application_get_desktop_file(app);
107-
108- if (strchr(appName, ' ') && temp && strlen(temp) > 1)
109- return getName((char *) temp);
110- else
111- return appName;
112- } else
113- return "";
114-
115-}
116
117=== added file 'src/bamf.cpp'
118--- src/bamf.cpp 1970-01-01 00:00:00 +0000
119+++ src/bamf.cpp 2011-08-23 04:19:23 +0000
120@@ -0,0 +1,48 @@
121+/*
122+ * Copyright 2010 Canonical Ltd.
123+ *
124+ * This library is free software; you can redistribute it and/or modify it under
125+ * the terms of the GNU General Public License as published by the Free Software
126+ * Foundation; either version 3 of the License, or (at your option) any later
127+ * version.
128+ *
129+ * This library is distributed in the hope that it will be useful, but WITHOUT
130+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
131+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
132+ * details.
133+ *
134+ * You should have received a copy of the GNU General Public License along with
135+ * this program; if not, write to the Free Software Foundation, Inc., 51
136+ * Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
137+ */
138+
139+#include <libbamf/bamf-matcher.h>
140+#include <string.h>
141+
142+char *getName(char *deskfile)
143+{
144+ char *temp;
145+ temp = strdup(strrchr(deskfile, '/'));
146+ return strndup(temp + 1, strlen(temp) - 9);
147+}
148+
149+char *getCurrentApp()
150+{
151+ g_type_init();
152+ char *deskfile, *appName;
153+ char *temp;
154+
155+ BamfApplication *app =
156+ bamf_matcher_get_active_application(bamf_matcher_get_default());
157+ if (app) {
158+ appName = (char *) bamf_view_get_name(BAMF_VIEW(app));
159+ temp = (char *) bamf_application_get_desktop_file(app);
160+
161+ if (strchr(appName, ' ') && temp && strlen(temp) > 1)
162+ return getName((char *) temp);
163+ else
164+ return appName;
165+ } else
166+ return "";
167+
168+}
169
170=== removed file 'src/config.c'
171--- src/config.c 2011-03-16 16:19:13 +0000
172+++ src/config.c 1970-01-01 00:00:00 +0000
173@@ -1,200 +0,0 @@
174-/*
175- * Copyright 2010 Canonical Ltd.
176- *
177- * This library is free software; you can redistribute it and/or modify it under
178- * the terms of the GNU General Public License as published by the Free Software
179- * Foundation; either version 3 of the License, or (at your option) any later
180- * version.
181- *
182- * This library is distributed in the hope that it will be useful, but WITHOUT
183- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
184- * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
185- * details.
186- *
187- * You should have received a copy of the GNU General Public License along with
188- * this program; if not, write to the Free Software Foundation, Inc., 51
189- * Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
190- */
191-
192-#include "config.h"
193-#include <libxml/parser.h>
194-
195-void debugOut(struct wish *wp)
196-{
197- int i;
198- printf("\n key : %s ", wp->key);
199- printf("\n button : %d ", wp->button);
200- for (i = 0; i < 4; i++)
201- printf("\t mod%d : %s ", i, wp->modifiers[i]);
202- for (i = 0; i < 4; i++) {
203- printf("\n attrName : %s ", wp->config_attr[i].attrName);
204- printf("\t val : %.2f ", wp->config_attr[i].val);
205- printf("\t valMax : %.2f", wp->config_attr[i].valMax);
206- }
207- printf("\n pMe : %x pNext : %x ", wp, wp->next);
208- printf("\n===================================================");
209-}
210-
211-int ginn_config_open(struct ginn_config *cfg, const char *path)
212-{
213- memset(cfg, 0, sizeof(*cfg));
214- cfg->doc = xmlReadFile(path, NULL, 0);
215- if (cfg->doc == NULL) {
216- fprintf(stderr, "Failed to parse %s\n", path);
217- return -1;
218- }
219- return 0;
220-}
221-
222-void ginn_config_close(struct ginn_config *cfg)
223-{
224- xmlFreeDoc(cfg->doc);
225-}
226-
227-static void print_node(const xmlNode * root, int depth)
228-{
229- xmlNode *node;
230- for (node = root; node; node = node->next) {
231- int i;
232- if (node->type != XML_ELEMENT_NODE)
233- continue;
234- for (i = 0; i < depth; i++)
235- printf(" ");
236- printf("%s\n", node->name);
237- print_node(node->children, depth + 1);
238- }
239-}
240-
241-static int ginn_str2state(const char *str)
242-{
243- if (str == NULL)
244- return -1;
245- if (strcmp(str, "start") == 0)
246- return GINN_START;
247- if (strcmp(str, "update") == 0)
248- return GINN_UPDATE;
249- if (strcmp(str, "finish") == 0)
250- return GINN_FINISH;
251- fprintf(stderr, "ERROR: Undefined state: %s\n", str);
252- return -2;
253-}
254-
255-static int ginn_str2bool(const char *str)
256-{
257- if (str == NULL)
258- return -1;
259- if (strcmp(str, "true") == 0)
260- return 1;
261- if (strcmp(str, "false") == 0)
262- return 0;
263- fprintf(stderr, "ERROR: Invalid value for boolean attribute: %s\n",
264- str);
265- return -2;
266-}
267-
268-void store_1config(xmlNode * node, struct wish *wp, int *position)
269-{
270- if (0 == strcmp(node->name, "wish")) {
271- // printf(" gesture %s fingers %s ",(xmlGetProp(node, "gesture")),(xmlGetProp(node, "fingers")));
272- wp->config_attr[0].attrName = "gesture name";
273- switch (xmlGetProp(node, "gesture")[0]) {
274- case 'D':
275- wp->config_attr[0].val = wp->config_attr[0].valMax = 0;
276- break;
277- case 'P':
278- wp->config_attr[0].val = wp->config_attr[0].valMax = 1;
279- break;
280- case 'R':
281- wp->config_attr[0].val = wp->config_attr[0].valMax = 2;
282- break;
283- case 'T':
284- wp->config_attr[0].val = wp->config_attr[0].valMax = 15;
285- break;
286- }
287- wp->config_attr[1].attrName = "touches";
288- wp->config_attr[1].val = atoi(xmlGetProp(node, "fingers"));
289- wp->config_attr[1].valMax = atoi(xmlGetProp(node, "fingers"));
290- }
291- if (0 == strcmp(node->name, "action")) {
292- wp->when = ginn_str2state(xmlGetProp(node, "when"));
293- if (wp->when < 0)
294- fprintf(stderr,
295- "ERROR: you must provide property 'when' to the action: %s\n",
296- xmlGetProp(node, "name"));
297- }
298- if (0 == strcmp(node->name, "trigger")) {
299- wp->config_attr[*position].attrName = xmlGetProp(node, "prop");
300- wp->config_attr[*position].val = atof(xmlGetProp(node, "min"));
301- wp->config_attr[*position].valMax = atof(xmlGetProp(node, "max"));
302- int acc = ginn_str2bool(xmlGetProp(node, "accumulate"));
303- wp->config_attr[*position].accumulate =
304- acc == -1 ? GINN_DEFAULT_ACCUMULATE : acc;
305- wp->config_attr[*position].accumVal = 0;
306- (*position)++;
307- }
308- if (0 == strcmp(node->name, "key")
309- || 0 == strcmp(node->name, "button")) {
310- if (xmlGetProp(node, "modifier1"))
311- wp->modifiers[0] = xmlGetProp(node, "modifier1");
312- if (xmlGetProp(node, "modifier2"))
313- wp->modifiers[1] = xmlGetProp(node, "modifier2");
314- if (xmlGetProp(node, "modifier3"))
315- wp->modifiers[2] = xmlGetProp(node, "modifier3");
316- if (xmlGetProp(node, "modifier4"))
317- wp->modifiers[3] = xmlGetProp(node, "modifier4");
318- }
319- if (0 == strcmp(node->name, "key"))
320- wp->key = xmlNodeGetContent(node);
321- if (0 == strcmp(node->name, "button"))
322- wp->button = atoi(xmlNodeGetContent(node));
323- if (0 == strcmp(node->name, "button"))
324- printf("Button : %d ", wp->button);
325-}
326-
327-void
328-parse_node(const xmlNode * root, int depth, struct wish *wp,
329- struct apps *ap)
330-{
331- xmlNode *node;
332- int position = 2;
333- for (node = root; node; node = node->next) {
334- if (node->type != XML_ELEMENT_NODE)
335- continue;
336-
337- if ((0 == strcmp(node->name, "application"))) {
338- if (0 != strcmp(ap->appName, "")) {
339- ap = ap->next =
340- (struct apps *) malloc(sizeof(struct apps));
341- inita(ap);
342- }
343- ap->appName = xmlGetProp(node, "name");
344- wp = ap->wp = (struct wish *) malloc(sizeof(struct wish));
345- initw(wp);
346- }
347- if ((0 == strcmp(node->name, "wish"))
348- && (0 == strcmp(wp->config_attr[0].attrName, "gesture name"))) {
349- if (!(wp->next)) {
350- wp->next = (struct wish *) malloc(sizeof(struct wish));
351- initw(wp->next);
352- }
353- wp = wp->next;
354- position = 2;
355- }
356- store_1config(node, wp, &position);
357- parse_node(node->children, depth + 1, wp, ap);
358- }
359-}
360-
361-void
362-ginn_config_store(const struct ginn_config *cfg, struct wish *w,
363- struct apps *a)
364-{
365- const xmlNode *root = xmlDocGetRootElement(cfg->doc);
366- parse_node(root, 0, w, a);
367-}
368-
369-void ginn_config_print(const struct ginn_config *cfg)
370-{
371- const xmlNode *root = xmlDocGetRootElement(cfg->doc);
372- print_node(root, 0);
373-}
374
375=== added file 'src/config.cpp'
376--- src/config.cpp 1970-01-01 00:00:00 +0000
377+++ src/config.cpp 2011-08-23 04:19:23 +0000
378@@ -0,0 +1,202 @@
379+/*
380+ * Copyright 2010 Canonical Ltd.
381+ *
382+ * This library is free software; you can redistribute it and/or modify it under
383+ * the terms of the GNU General Public License as published by the Free Software
384+ * Foundation; either version 3 of the License, or (at your option) any later
385+ * version.
386+ *
387+ * This library is distributed in the hope that it will be useful, but WITHOUT
388+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
389+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
390+ * details.
391+ *
392+ * You should have received a copy of the GNU General Public License along with
393+ * this program; if not, write to the Free Software Foundation, Inc., 51
394+ * Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
395+ */
396+
397+#include "config.h"
398+
399+void debugOut(Gwish *wp)
400+{
401+ int i;
402+ cout << "\n key : " << wp->key;
403+ printf("\n button : %d ", wp->button);
404+ for (i = 0; i < 4; i++)
405+ cout << "\t mod" << i << " : " << wp->modifiers[i];
406+ for (i = 0; i < 4; i++) {
407+ cout << "\n attrName : " << wp->config_attr[i].attrName;
408+ printf("\t val : %.2f ", wp->config_attr[i].val);
409+ printf("\t valMax : %.2f", wp->config_attr[i].valMax);
410+ }
411+ printf("\n pMe : %x pNext : %x ", wp, wp->next);
412+ printf("\n===================================================");
413+}
414+
415+int ginn_config_open(struct ginn_config *cfg, const char *path)
416+{
417+ memset(cfg, 0, sizeof(*cfg));
418+ cfg->doc = xmlReadFile(path, NULL, 0);
419+ if (cfg->doc == NULL)
420+ {
421+ cerr << "Failed to parse " << path << endl;
422+ return -1;
423+ }
424+ return 0;
425+}
426+
427+void ginn_config_close(struct ginn_config *cfg)
428+{
429+ xmlFreeDoc(cfg->doc);
430+}
431+
432+static void print_node(const xmlNode * root, int depth)
433+{
434+ const xmlNode *node;
435+ for (node = root; node; node = node->next)
436+ {
437+ if (node->type != XML_ELEMENT_NODE)
438+ {
439+ continue;
440+ }
441+ for (int i = 0; i < depth; i++)
442+ printf(" ");
443+ cout << node->name << endl;
444+ print_node(node->children, depth + 1);
445+ }
446+}
447+
448+static int ginn_str2state(const char *str)
449+{
450+ if (str == NULL)
451+ return -1;
452+ if (strcmp(str, "start") == 0)
453+ return GINN_START;
454+ if (strcmp(str, "update") == 0)
455+ return GINN_UPDATE;
456+ if (strcmp(str, "finish") == 0)
457+ return GINN_FINISH;
458+ cerr << "ERROR: Undefined state: " << str << endl;
459+ return -2;
460+}
461+
462+static int ginn_str2bool(const char *str)
463+{
464+ if (str == NULL)
465+ return -1;
466+ if (strcmp(str, "true") == 0)
467+ return 1;
468+ if (strcmp(str, "false") == 0)
469+ return 0;
470+ cerr << "ERROR: Invalid value for boolean attribute: " << str << endl;
471+ return -2;
472+}
473+
474+void store_1config(xmlNode * node, Gwish *wp, int *position)
475+{
476+ string nodeName = (char *)node->name;
477+ if (nodeName == "wish")
478+ {
479+ // printf(" gesture %s fingers %s ",(xmlGetProp(node, "gesture")),(xmlGetProp(node, "fingers")));
480+ switch (xmlGetProp(node, (xmlChar*)"gesture") [0])
481+ {
482+ case 'D':
483+ wp->Type = GINN_Drag;
484+ break;
485+ case 'P':
486+ wp->Type = GINN_Pinch;
487+ break;
488+ case 'R':
489+ wp->Type = GINN_Rotate;
490+ break;
491+ case 'T':
492+ wp->Type = GINN_Tap;
493+ break;
494+ }
495+ wp->TouchNum = atoi((char *) xmlGetProp(node, (xmlChar*)"fingers"));
496+ wp->DirectTouch = ginn_str2bool((char *) xmlGetProp(node, (xmlChar*)"screen"));
497+ }
498+ if (nodeName == "action")
499+ {
500+ wp->when = ginn_str2state((char *) xmlGetProp(node, (xmlChar*)"when"));
501+ if (wp->when < 0)
502+ cerr << "ERROR: you must provide property 'when' to the action: " << xmlGetProp(node, (xmlChar*)"name") << endl;
503+ }
504+ if (nodeName == "trigger")
505+ {
506+ wp->config_attr[*position].attrName = (char *)xmlGetProp(node, (xmlChar*)"prop");
507+ wp->config_attr[*position].val = atof((char *)xmlGetProp(node, (xmlChar*)"min"));
508+ wp->config_attr[*position].valMax = atof((char *)xmlGetProp(node, (xmlChar*)"max"));
509+ int acc = ginn_str2bool((char *)xmlGetProp(node, (xmlChar*)"accumulate"));
510+ wp->config_attr[*position].accumulate =
511+ acc == -1 ? GINN_DEFAULT_ACCUMULATE : acc;
512+ wp->config_attr[*position].accumVal = 0;
513+ (*position)++;
514+ }
515+ if (nodeName == "key" || nodeName == "button")
516+ {
517+ if (xmlGetProp(node, (xmlChar*)"modifier1"))
518+ wp->modifiers[0] = (char *)xmlGetProp(node, (xmlChar*)"modifier1");
519+ if (xmlGetProp(node, (xmlChar*)"modifier2"))
520+ wp->modifiers[1] = (char *)xmlGetProp(node, (xmlChar*)"modifier2");
521+ if (xmlGetProp(node, (xmlChar*)"modifier3"))
522+ wp->modifiers[2] = (char *)xmlGetProp(node, (xmlChar*)"modifier3");
523+ if (xmlGetProp(node, (xmlChar*)"modifier4"))
524+ wp->modifiers[3] = (char *)xmlGetProp(node, (xmlChar*)"modifier4");
525+ }
526+ if (nodeName == "key")
527+ wp->key = (char *)xmlNodeGetContent(node);
528+ if (nodeName == "button")
529+ {
530+ wp->button = atoi((char *)xmlNodeGetContent(node));
531+ }
532+}
533+
534+void parse_node(const xmlNode * root, int depth, Gwish *wp, Gapps *ap)
535+{
536+ xmlNode *node;
537+
538+ int position = 2;
539+ for (node = const_cast <xmlNode *> (root); node; node = node->next)
540+ {
541+ if (node->type != XML_ELEMENT_NODE)
542+ {
543+ if (node->type == XML_TEXT_NODE)
544+
545+ continue;
546+ }
547+
548+ if ((0 == strcmp((char *)node->name, "application")))
549+ {
550+ if (!ap->appName.empty())
551+ {
552+ ap = ap->next = new Gapps;//Save The previon and create new
553+ }
554+ ap->appName = (char *) xmlGetProp(node, (xmlChar*)"name");
555+ wp = ap->wp = new Gwish; //Save The previon and create new
556+ }
557+ if ((0 == strcmp((char *)node->name, "wish"))
558+ && wp->Type != -1)
559+ {
560+ if (!(wp->next))
561+ wp->next = new Gwish;
562+ wp = wp->next;
563+ position = 2;
564+ }
565+ store_1config(node, wp, &position);
566+ parse_node(node->children, depth + 1, wp, ap);
567+ }
568+}
569+
570+void ginn_config_store(const struct ginn_config *cfg, Gwish *w, struct Gapps *a)
571+{
572+ const xmlNode *root = xmlDocGetRootElement(cfg->doc);
573+ parse_node(root, 0, w, a);
574+}
575+
576+void ginn_config_print(const struct ginn_config *cfg)
577+{
578+ const xmlNode *root = xmlDocGetRootElement(cfg->doc);
579+ print_node(root, 0);
580+}
581
582=== modified file 'src/config.h' (properties changed: -x to +x)
583--- src/config.h 2011-03-16 16:19:13 +0000
584+++ src/config.h 2011-08-23 04:19:23 +0000
585@@ -18,8 +18,7 @@
586 #ifndef GINN_CONFIG_H
587 #define GINN_CONFIG_H
588
589-#include <libxml/tree.h>
590-#include <string.h>
591+#include "header.h"
592
593 #define GINN_START 0
594 #define GINN_UPDATE 1
595@@ -27,32 +26,76 @@
596
597 #define GINN_DEFAULT_ACCUMULATE 1
598
599-typedef struct ginn_config {
600+struct ginn_config
601+{
602 xmlDocPtr doc;
603 xmlNodePtr root;
604-} cfg;
605-
606-typedef struct att {
607- char *attrName;
608- float val;
609- float valMax;
610- int accumulate;
611- float accumVal;
612-} att;
613-
614-typedef struct wish {
615- att config_attr[25];
616- char *key;
617- int button;
618- char *modifiers[4];
619- struct wish *next;
620- int when;
621-} wish;
622-
623-typedef struct apps {
624- char *appName;
625- struct wish *wp;
626- struct apps *next;
627-} apps;
628+};
629+
630+struct att
631+{
632+ string attrName;
633+ float val;
634+ float valMax;
635+ int accumulate;
636+ float accumVal;
637+};
638+
639+///
640+/// Use to classify Gesture Type (For Example pinch)
641+///
642+enum GestureType
643+{
644+ GINN_Drag = 0,GINN_Pinch=1,GINN_Rotate=2,GINN_Tap=15
645+};
646+
647+///
648+/// GWish provide gesture information and the reaction for gesture called Wish
649+///
650+class Gwish
651+{
652+public:
653+ Gwish();
654+//Variable:
655+ att config_attr[25];
656+ int button;
657+ int Type; //Indicate The gusture Type (-1 Mean it's NULL)
658+ int TouchNum; //Indicate The Number of finger for gusture
659+ int DirectTouch; //use this to Detect Touchpad from Touchscreen
660+ string key;
661+ string modifiers[4];
662+ Gwish *next;
663+ int when;
664+};
665+
666+///
667+/// Use This class for save application information
668+///
669+class Gapps
670+{
671+public:
672+ Gapps();
673+//Variable:
674+ string appName;
675+ Gwish *wp;
676+ Gapps *next;
677+};
678+
679+///
680+/// Use this struct to save device attribute (GD reffered to GINN device and att reffered to attribute)
681+///
682+struct GD_att
683+{
684+ string name; //Device Name
685+ int ID; //Device ID that is unique (use to find devive)
686+ int TouchNum; //Define how many parallel finger touch can support
687+ bool isDirectTouch; //Define it is a touch screen or not(a pad)
688+};
689+
690+
691+//Decleare in config.cpp
692+int ginn_config_open(struct ginn_config *cfg, const char *path);
693+void ginn_config_print(const struct ginn_config *cfg);
694+void ginn_config_store(const struct ginn_config *cfg, Gwish *w, Gapps *a);
695
696 #endif /* GINN_CONFIG_H */
697
698=== removed file 'src/ginn.c'
699--- src/ginn.c 2011-08-12 15:40:51 +0000
700+++ src/ginn.c 1970-01-01 00:00:00 +0000
701@@ -1,592 +0,0 @@
702-/**
703- * Copyright 2010 Canonical Ltd.
704- *
705- * This library is free software; you can redistribute it and/or modify it under
706- * the terms of the GNU General Public License as published by the Free Software
707- * Foundation; either version 3 of the License, or (at your option) any later
708- * version.
709- *
710- * This library is distributed in the hope that it will be useful, but WITHOUT
711- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
712- * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
713- * details.
714- *
715- * You should have received a copy of the GNU General Public License along with
716- * this program; if not, write to the Free Software Foundation, Inc., 51
717- * Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
718- *
719- * Authors:
720- * Mohamed-Ikbel Boulabiar <boulabiar@gmail.com>
721- * Henrik Rydberg <rydberg@bitmath.org>
722- * Stephen M. Webb <stephen.webb@canonical.com>
723- *
724- */
725-#include "config.h"
726-#include <geis/geis.h>
727-#include <errno.h>
728-#include <stdio.h>
729-#include <stdlib.h>
730-#include <string.h>
731-#include <sys/select.h>
732-#include <sys/stat.h>
733-#include <unistd.h>
734-#include <X11/Xlib.h>
735-#include <X11/keysym.h>
736-
737-att config_attr[25] = {[0 ... 24] = {.attrName = "",.val = 0,.valMax = 0}
738-};
739-
740-wish w1 = {.config_attr = {[0 ... 24] =
741- {.attrName = "",.val = 0,.valMax = 0}
742- }
743-,
744-.key = "",
745-.next = NULL
746-};
747-
748-wish *wp, *wpEnd;
749-apps *ap;
750-
751-static int inside(float x, float a, float b)
752-{
753- return ((x <= b) && (x >= a));
754-}
755-
756-void initw(struct wish *wp)
757-{
758- int i;
759- wp->button = 0;
760- wp->key = "";
761- wp->next = NULL;
762- for (i = 0; i < 4; i++)
763- wp->modifiers[i] = "";
764- for (i = 0; i < 25; i++) {
765- wp->config_attr[i].attrName = "";
766- wp->config_attr[i].val = 0;
767- wp->config_attr[i].valMax = 0;
768- }
769-}
770-
771-void inita(struct apps *ap)
772-{
773- ap->next = NULL;
774- ap->wp = NULL;
775- ap->appName = "";
776-}
777-
778-static void clear_accum_attrs(att * attrs)
779-{
780- int i = 0;
781- while (strcmp(attrs[i].attrName, "") != 0) {
782- if (attrs[i].accumulate)
783- attrs[i].accumVal = 0;
784- i++;
785- }
786-}
787-
788-static void update_wishes()
789-{
790- char *activeApp;
791- apps *tmpAp = ap;
792- int diff = 0;
793-
794- activeApp = (char *) getCurrentApp();
795- printf(" --ActiveApp %s\n", activeApp);
796- if (activeApp)
797- diff = strcmp(activeApp, ap->appName);
798-
799- while (diff && ap->next) {
800- ap = ap->next;
801- diff = strcmp(activeApp, ap->appName);
802- }
803-
804- if (!diff)
805- wpEnd->next = ap->wp;
806- else
807- wpEnd->next = NULL;
808-
809- ap = tmpAp;
810-}
811-
812-static void
813-gesture_match(GeisGestureType gesture_type,
814- GeisGestureId gesture_id,
815- GeisSize attr_count, GeisGestureAttr * attrs, int state)
816-{
817- struct wish *topw;
818- topw = wp;
819- update_wishes();
820- while (wp && (0 != strcmp(wp->key, "") || wp->button)) {
821- int valid = 1;
822- if (gesture_type == wp->config_attr[0].val
823- && attrs[8].integer_val == wp->config_attr[1].val) {
824- int attrsI = 9, cAttrI = 2;
825- do {
826- if (0 ==
827- strcmp(attrs[attrsI].name,
828- wp->config_attr[cAttrI].attrName)) {
829- printf("DEBUG -- comparing %s %s : ",
830- attrs[attrsI].name,
831- wp->config_attr[cAttrI].attrName);
832- printf("%.2f %.2f %.2f \n",
833- attrs[attrsI].float_val,
834- wp->config_attr[cAttrI].val,
835- wp->config_attr[cAttrI].valMax);
836- printf("%i \n",
837- inside(attrs[attrsI].float_val,
838- wp->config_attr[cAttrI].val,
839- wp->config_attr[cAttrI].valMax));
840- if (wp->config_attr[cAttrI].accumulate) {
841- wp->config_attr[cAttrI].accumVal +=
842- attrs[attrsI].float_val;
843- valid = valid
844- && inside(wp->config_attr
845- [cAttrI].accumVal,
846- wp->config_attr
847- [cAttrI].val,
848- wp->config_attr[cAttrI].valMax);
849- } else
850- valid = valid
851- && inside(attrs[attrsI].float_val,
852- wp->config_attr
853- [cAttrI].val,
854- wp->config_attr[cAttrI].valMax);
855- attrsI++;
856- cAttrI++;
857- } else
858- attrsI++;
859- } while ((0 != strcmp(wp->config_attr[cAttrI].attrName, ""))
860- && attrsI < 18);
861- if (valid && wp->when == state) {
862- if ((0 != wp->button)
863- && (0 != strcmp(wp->key, ""))) {
864- injMixBtnKey(XStringToKeysym(wp->key),
865- wp->button, wp->modifiers);
866- printf("MIX -- MIX");
867- } else {
868- if (0 != wp->button)
869- injButton(wp->button, wp->modifiers);
870- if (0 != strcmp(wp->key, ""))
871- injKey(XStringToKeysym(wp->key), wp->modifiers);
872- }
873- clear_accum_attrs(wp->config_attr);
874- }
875- }
876- if (state == GINN_FINISH)
877- clear_accum_attrs(wp->config_attr);
878- wp = wp->next;
879- }
880- wp = topw;
881-}
882-
883-static Window getRootWindow()
884-{
885- Display *display = NULL;
886- Window window = 0;
887-
888- display = XOpenDisplay(NULL);
889- if (!display) {
890- fprintf(stderr, "error opening X11 display.\n");
891- exit(1);
892- }
893-
894- window = DefaultRootWindow(display);
895-
896- XCloseDisplay(display);
897-
898- return window;
899-}
900-
901-static void print_attr(GeisGestureAttr * attr)
902-{
903- fprintf(stdout, "\tattr %s=", attr->name);
904- switch (attr->type) {
905- case GEIS_ATTR_TYPE_BOOLEAN:
906- fprintf(stdout, "%s\n", attr->boolean_val ? "true" : "false");
907- break;
908- case GEIS_ATTR_TYPE_FLOAT:
909- fprintf(stdout, "%f\n", attr->float_val);
910- break;
911- case GEIS_ATTR_TYPE_INTEGER:
912- fprintf(stdout, "%d\n", attr->integer_val);
913- break;
914- case GEIS_ATTR_TYPE_STRING:
915- fprintf(stdout, "\"%s\"\n", attr->string_val);
916- break;
917- default:
918- fprintf(stdout, "<unknown>\n");
919- break;
920- }
921-}
922-
923-static void
924-gesture_added(void *cookie,
925- GeisGestureType gesture_type,
926- GeisGestureId gesture_id,
927- GeisSize attr_count, GeisGestureAttr * attrs)
928-{
929- int i = 0;
930- fprintf(stdout, "Gesture type %d added\n", gesture_type);
931- for (i = 0; i < attr_count; ++i)
932- print_attr(&attrs[i]);
933-}
934-
935-static void
936-gesture_removed(void *cookie,
937- GeisGestureType gesture_type,
938- GeisGestureId gesture_id,
939- GeisSize attr_count, GeisGestureAttr * attrs)
940-{
941- int i = 0;
942- fprintf(stdout, "Gesture type %d removed\n", gesture_type);
943- for (i = 0; i < attr_count; ++i)
944- print_attr(&attrs[i]);
945-}
946-
947-static void
948-gesture_start(void *cookie,
949- GeisGestureType gesture_type,
950- GeisGestureId gesture_id,
951- GeisSize attr_count, GeisGestureAttr * attrs)
952-{
953- int i = 0;
954- fprintf(stdout, "Gesture type %d started\n", gesture_type);
955- for (i = 0; i < attr_count; ++i)
956- print_attr(&attrs[i]);
957-
958- // In GEIS v1, we know that the focus coords are in attrs 5 and 6
959- movePointer((int)attrs[5].float_val, (int)attrs[6].float_val);
960-}
961-
962-static void
963-gesture_update(void *cookie,
964- GeisGestureType gesture_type,
965- GeisGestureId gesture_id,
966- GeisSize attr_count, GeisGestureAttr * attrs)
967-{
968- int i = 0;
969- fprintf(stdout, "Gesture type %d updated\n", gesture_type);
970- for (i = 0; i < attr_count; ++i)
971- print_attr(&attrs[i]);
972- gesture_match(gesture_type, gesture_id, attr_count, attrs,
973- GINN_UPDATE);
974-}
975-
976-static void
977-gesture_finish(void *cookie,
978- GeisGestureType gesture_type,
979- GeisGestureId gesture_id,
980- GeisSize attr_count, GeisGestureAttr * attrs)
981-{
982- int i = 0;
983- fprintf(stdout, "Gesture type %d finished\n", gesture_type);
984- for (i = 0; i < attr_count; ++i); //print_attr(&attrs[i]);
985- gesture_match(gesture_type, gesture_id, attr_count, attrs,
986- GINN_FINISH);
987-}
988-
989-GeisGestureFuncs gesture_funcs = {
990- gesture_added,
991- gesture_removed,
992- gesture_start,
993- gesture_update,
994- gesture_finish
995-};
996-
997-/*
998- * Searches for a default config file.
999- *
1000- * Returns a pointer to a config file name (which must be freed) or NULL
1001- * if no default config file was found.
1002- */
1003-static char *ginn_default_config()
1004-{
1005- static const char default_file_name[] = "/wishes.xml";
1006- static const char *search_paths[] = {
1007- "etc",
1008- "../etc",
1009- ".",
1010- "$HOME/.ginn",
1011- GINN_CONFIG_DIR
1012- };
1013- static const int num_paths =
1014- sizeof(search_paths) / sizeof(const char *);
1015- int i;
1016-
1017- for (i = 0; i < num_paths; ++i) {
1018- struct stat sbuf;
1019- char *file_name = NULL;
1020-
1021- if (strstr(search_paths[i], "$HOME")) {
1022- char *home_dir = getenv("HOME");
1023- if (!home_dir) {
1024- continue;
1025- } else {
1026- char *cdr = index(search_paths[i], '/');
1027- size_t file_name_length = strlen(home_dir)
1028- + strlen(cdr)
1029- + strlen(default_file_name)
1030- + 1;
1031- file_name = calloc(file_name_length, sizeof(char));
1032- strcpy(file_name, home_dir);
1033- strcat(file_name, cdr);
1034- }
1035- } else {
1036- size_t file_name_length = strlen(search_paths[i])
1037- + strlen(default_file_name)
1038- + 1;
1039- file_name = calloc(file_name_length, sizeof(char));
1040- strcpy(file_name, search_paths[i]);
1041- }
1042- strcat(file_name, default_file_name);
1043- int sres = stat(file_name, &sbuf);
1044- if (sres == 0) {
1045- fprintf(stdout, "Using wishes file %s\n", file_name);
1046- return file_name;
1047- }
1048- free(file_name);
1049- }
1050-
1051- return NULL;
1052-}
1053-
1054-int main(int argc, char *argv[])
1055-{
1056- GeisStatus status = GEIS_UNKNOWN_ERROR;
1057- GeisXcbWinInfo xcb_win_info = {
1058- .display_name = NULL,
1059- .screenp = NULL,
1060- .window_id = getRootWindow()
1061- };
1062- GeisWinInfo win_info = {
1063- GEIS_XCB_FULL_WINDOW,
1064- &xcb_win_info
1065- };
1066- GeisInstance instance;
1067- struct ginn_config cfg;
1068-
1069- {
1070- char *config_file_name = NULL;
1071- if (argc < 2) {
1072- fprintf(stderr, "usage: %s <configxml>\n", argv[0]);
1073- config_file_name = ginn_default_config();
1074- if (config_file_name) {
1075- fprintf(stderr,
1076- "using default configuration file %s ... \n",
1077- config_file_name);
1078- }
1079- } else {
1080- config_file_name = strdup(argv[1]);
1081- }
1082- if (NULL == config_file_name) {
1083- fprintf(stderr, "Could not find Ginn wishes\n");
1084- return -1;
1085- }
1086-
1087- if (ginn_config_open(&cfg, config_file_name)) {
1088- fprintf(stderr, "Could not load Ginn wishes\n");
1089- return -1;
1090- }
1091- free(config_file_name);
1092- }
1093-
1094- ginn_config_print(&cfg);
1095- ap = (struct apps *) malloc(sizeof(struct apps));
1096- inita(ap);
1097- wp = (struct wish *) malloc(sizeof(struct wish));
1098- initw(wp);
1099- ginn_config_store(&cfg, wp, ap);
1100- wpEnd = wp;
1101- while (wpEnd->next)
1102- wpEnd = wpEnd->next;
1103-
1104- int pos = 0;
1105- printf("\n");
1106- while (strcmp(config_attr[pos].attrName, "")) {
1107- printf("DEBUG %d %s %.2f %.2f \n", pos,
1108- config_attr[pos].attrName, config_attr[pos].val,
1109- config_attr[pos].valMax);
1110- pos++;
1111- }
1112-
1113- /**
1114- * Check the loaded wishes to see which gestures are used
1115- * and add these gestures to a NULL terminated list "sub_gestures_list"
1116- *
1117- * This list is used to subscribe only the necessary gestures
1118- * to GEIS. This will avoid issues with 2 finger scrolls and other gestues
1119- * being dropped when not accounted for in the wishes file.
1120- **/
1121-
1122- apps * appPtr = ap;
1123- wish * wishPtr;
1124- char * sub_gestures_list[17] = {NULL};
1125- int finished = 0;
1126-
1127- /**
1128- * Loop through each wish inside ap
1129- * After all of the wishes in ap are accounted for
1130- * add global wishes
1131- **/
1132-
1133- while(finished != 1)
1134- {
1135- // Check if we are finished with the application wishes
1136- if(appPtr == NULL)
1137- {
1138- wishPtr = wp;
1139- finished = 1;
1140- }else{
1141- wishPtr = appPtr->wp;
1142- }
1143-
1144- // Loop through each wish
1145- while(wishPtr)
1146- {
1147- int i;
1148- for(i = 0; i < 25; i ++)
1149- {
1150-
1151- char *sub_gesture = malloc(sizeof(char[16]));
1152- int pos = 0;
1153-
1154- // Check for Drag gesture
1155- if(strcmp(wishPtr->config_attr[i].attrName, "delta x") == 0 ||
1156- strcmp(wishPtr->config_attr[i].attrName, "delta y") == 0 ||
1157- strcmp(wishPtr->config_attr[i].attrName, "velocity x") == 0 ||
1158- strcmp(wishPtr->config_attr[i].attrName, "velocity y") == 0
1159- )
1160- {
1161- sprintf(sub_gesture, "Drag,touch=%i", (int)wishPtr->config_attr[1].val);
1162- }
1163-
1164- // Check for Rotate gesture
1165- else if(strcmp(wishPtr->config_attr[i].attrName, "angle delta") == 0 ||
1166- strcmp(wishPtr->config_attr[i].attrName, "angular velocity") == 0 ||
1167- strcmp(wishPtr->config_attr[i].attrName, "angle") == 0
1168- )
1169- {
1170- sprintf(sub_gesture, "Rotate,touch=%i", (int)wishPtr->config_attr[1].val);
1171- }
1172-
1173- // Check for Pinch gesture
1174- else if(strcmp(wishPtr->config_attr[i].attrName, "radius delta") == 0 ||
1175- strcmp(wishPtr->config_attr[i].attrName, "radial velocity") == 0 ||
1176- strcmp(wishPtr->config_attr[i].attrName, "radius") == 0
1177- )
1178- {
1179- sprintf(sub_gesture, "Pinch,touch=%i", (int)wishPtr->config_attr[1].val);
1180- }
1181-
1182- // Check for Tap gesture
1183- else if(strcmp(wishPtr->config_attr[i].attrName, "tap time") == 0)
1184- {
1185- sprintf(sub_gesture, "Tap,touch=%i", (int)wishPtr->config_attr[1].val);
1186- }
1187-
1188- // Deallocate sub_gesture if no gesture was found
1189- else
1190- {
1191- free(sub_gesture);
1192- sub_gesture = NULL;
1193- continue;
1194- }
1195-
1196- /** Check the current gesture list
1197- * Only add if the gesture is not already in the list
1198- * Store in index of the first NULL found
1199- **/
1200-
1201- while(pos < 17)
1202- {
1203- if(sub_gestures_list[pos] == NULL)
1204- {
1205- sub_gestures_list[pos] = sub_gesture;
1206- break;
1207- }else if(strcmp(sub_gestures_list[pos], sub_gesture) == 0)
1208- {
1209- break;
1210- }
1211- pos ++;
1212- }
1213-
1214-
1215- }
1216- // Iterate to the next wish
1217- wishPtr = wishPtr->next;
1218- }
1219-
1220- // If there are more applications, iterate to the next
1221-
1222- if(finished != 1)
1223- {
1224- appPtr = appPtr->next;
1225- }
1226- }
1227-
1228- // Show which gestures were subscribed
1229- printf("Gestures subscribed:\n");
1230-
1231- pos = 0;
1232- while(pos < 17)
1233- {
1234- if(sub_gestures_list[pos] != NULL)
1235- {
1236- printf("%s\n", sub_gestures_list[pos]);
1237- }
1238-
1239- pos ++;
1240- }
1241-
1242- // End sub gesture list creation
1243-
1244- status = geis_init(&win_info, &instance);
1245- if (status != GEIS_STATUS_SUCCESS) {
1246- fprintf(stderr, "error in geis_init\n");
1247- return 1;
1248- }
1249-
1250- status = geis_configuration_supported(instance, GEIS_CONFIG_UNIX_FD);
1251- if (status != GEIS_STATUS_SUCCESS) {
1252- fprintf(stderr, "GEIS does not support Unix fd\n");
1253- return 1;
1254- }
1255-
1256- int fd = -1;
1257- status =
1258- geis_configuration_get_value(instance, GEIS_CONFIG_UNIX_FD, &fd);
1259- if (status != GEIS_STATUS_SUCCESS) {
1260- fprintf(stderr, "error retrieving GEIS fd\n");
1261- return 1;
1262- }
1263-
1264- status = geis_subscribe(instance, GEIS_ALL_INPUT_DEVICES, sub_gestures_list, // GEIS_ALL_GESTURES,
1265- &gesture_funcs, NULL);
1266- if (status != GEIS_STATUS_SUCCESS) {
1267- fprintf(stderr, "error subscribing to gestures\n");
1268- return 1;
1269- }
1270-
1271- openDisplay();
1272-
1273- while (1) {
1274- fd_set read_fds;
1275- FD_ZERO(&read_fds);
1276- FD_SET(fd, &read_fds);
1277- int sstat = select(fd + 1, &read_fds, NULL, NULL, NULL);
1278- if (sstat < 0) {
1279- fprintf(stderr, "error %d in select(): %s\n", errno,
1280- strerror(errno));
1281- break;
1282- }
1283-
1284- if (FD_ISSET(fd, &read_fds)) {
1285- geis_event_dispatch(instance);
1286- }
1287- }
1288-
1289- geis_finish(instance);
1290- closeDisplay();
1291- free(wp);
1292- return 0;
1293-}
1294
1295=== added file 'src/ginn.cpp'
1296--- src/ginn.cpp 1970-01-01 00:00:00 +0000
1297+++ src/ginn.cpp 2011-08-23 04:19:23 +0000
1298@@ -0,0 +1,555 @@
1299+#include "ginn.h"
1300+
1301+GINN::GINN()
1302+{
1303+ //Set Default value
1304+ config_load = false;
1305+ ap = new Gapps;
1306+ wp = new Gwish;
1307+ //
1308+ att att_default;
1309+ att_default.attrName = "";
1310+ att_default.val = 0 ;
1311+ att_default.valMax = 0 ;
1312+
1313+ for (int i = 0; i < 25;i++)
1314+ config_attr[i] = att_default;
1315+
1316+ for (int i = 0; i < 25;i++)
1317+ w1.config_attr[i] = config_attr[i];
1318+ w1.key = "";
1319+ w1.next = NULL;
1320+}
1321+
1322+int GINN::inside(float x, float a, float b)
1323+{
1324+ return ((x <= b) && (x >= a));
1325+}
1326+
1327+void GINN::clear_accum_attrs(att * attrs)
1328+{
1329+ int i = 2;
1330+ while (!attrs[i].attrName.empty())
1331+ {
1332+ if (attrs[i].accumulate)
1333+ attrs[i].accumVal = 0;
1334+ i++;
1335+ }
1336+}
1337+
1338+void GINN::update_wishes()
1339+{
1340+ string activeApp;
1341+ Gapps *tmpAp = ap;
1342+ int diff = 0;
1343+
1344+ activeApp = (char *) getCurrentApp();
1345+ //cout << " --ActiveApp " << activeApp << endl; ;
1346+ if (!activeApp.empty())
1347+ diff = !(activeApp == ap->appName);
1348+
1349+ while (diff && ap->next)
1350+ {
1351+ ap = ap->next;
1352+ diff = !(activeApp == ap->appName);
1353+ }
1354+
1355+ if (!diff)
1356+ wpEnd->next = ap->wp;
1357+ else
1358+ wpEnd->next = NULL;
1359+
1360+ ap = tmpAp;
1361+}
1362+
1363+void GINN::Gmatch(GeisGestureType gesture_type,GeisGestureId gesture_id,
1364+ GeisSize attr_count, GeisGestureAttr * attrs, int state)
1365+{
1366+ Gwish *topw;
1367+ int DeviceID = attrs[0].integer_val;
1368+ int Dindex = DId2Index(DeviceID); //Device index on device_list
1369+ topw = wp;
1370+ update_wishes();
1371+ while (wp && (!wp->key.empty() || wp->button))
1372+ {
1373+ int valid = 1;
1374+ if (gesture_type == wp->Type && attrs[8].integer_val == wp->TouchNum &&
1375+ (device_list[Dindex].isDirectTouch == wp->DirectTouch || wp->DirectTouch == -1)) //wp->DirectTouch is -1 if no screen option define in wish tag
1376+ {
1377+ int attrsI = 9, cAttrI = 2;
1378+ do
1379+ {
1380+ if (attrs[attrsI].name == wp->config_attr[cAttrI].attrName)
1381+ {
1382+// cout << "DEBUG -- comparing " << attrs[attrsI].name << wp->config_attr[cAttrI].attrName << ": ";
1383+// cout << attrs[attrsI].float_val << wp->config_attr[cAttrI].val << wp->config_attr[cAttrI].valMax << endl;
1384+// cout << inside(attrs[attrsI].float_val,wp->config_attr[cAttrI].val, wp->config_attr[cAttrI].valMax) << endl;
1385+ if (wp->config_attr[cAttrI].accumulate)
1386+ {
1387+ wp->config_attr[cAttrI].accumVal += attrs[attrsI].float_val;
1388+ valid = valid
1389+ && inside(wp->config_attr
1390+ [cAttrI].accumVal,
1391+ wp->config_attr
1392+ [cAttrI].val,
1393+ wp->config_attr[cAttrI].valMax);
1394+ }
1395+ else
1396+ valid = valid && inside(attrs[attrsI].float_val, wp->config_attr
1397+ [cAttrI].val, wp->config_attr[cAttrI].valMax);
1398+ attrsI++;
1399+ cAttrI++;
1400+ }
1401+ else
1402+ attrsI++;
1403+ } while (!wp->config_attr[cAttrI].attrName.empty() && attrsI < 18);
1404+
1405+ if (valid && wp->when == state)
1406+ {
1407+ if ((0 != wp->button) && (!wp->key.empty()))
1408+ {
1409+ injMixBtnKey(XStringToKeysym(wp->key.c_str()), wp->button, wp->modifiers);
1410+ cout << "MIX -- MIX";
1411+ }
1412+ else
1413+ {
1414+ if (0 != wp->button)
1415+ injButton(wp->button, wp->modifiers);
1416+ if (!wp->key.empty())
1417+ injKey(XStringToKeysym(wp->key.c_str()), wp->modifiers);
1418+ }
1419+ clear_accum_attrs(wp->config_attr);
1420+ break;
1421+ }
1422+ }
1423+ if (state == GINN_FINISH)
1424+ clear_accum_attrs(wp->config_attr);
1425+ wp = wp->next;
1426+ }
1427+ wp = topw;
1428+}
1429+
1430+Window GINN::getRootWindow()
1431+{
1432+ Display *display = NULL;
1433+ Window window = 0;
1434+
1435+ display = XOpenDisplay(NULL);
1436+ if (!display)
1437+ {
1438+ cerr << "error opening X11 display.\n";
1439+ exit(1);
1440+ }
1441+
1442+ window = DefaultRootWindow(display);
1443+
1444+ XCloseDisplay(display);
1445+
1446+ return window;
1447+}
1448+
1449+void GINN::print_attr(GeisGestureAttr * attr)
1450+{
1451+ fprintf(stdout, "\tattr %s=", attr->name);
1452+ switch (attr->type) {
1453+ case GEIS_ATTR_TYPE_BOOLEAN:
1454+ fprintf(stdout, "%s\n", attr->boolean_val ? "true" : "false");
1455+ break;
1456+ case GEIS_ATTR_TYPE_FLOAT:
1457+ fprintf(stdout, "%f\n", attr->float_val);
1458+ break;
1459+ case GEIS_ATTR_TYPE_INTEGER:
1460+ fprintf(stdout, "%d\n", attr->integer_val);
1461+ break;
1462+ case GEIS_ATTR_TYPE_STRING:
1463+ fprintf(stdout, "\"%s\"\n", attr->string_val);
1464+ break;
1465+ default:
1466+ fprintf(stdout, "<unknown>\n");
1467+ break;
1468+ }
1469+}
1470+
1471+void GINN::Gadded(GeisGestureType gesture_type,GeisGestureId gesture_id, GeisSize attr_count, GeisGestureAttr * attrs)
1472+{
1473+ int i = 0;
1474+ fprintf(stdout, "Gesture type %d added\n", gesture_type);
1475+ for (i = 0; i < attr_count; ++i)
1476+ print_attr(&attrs[i]);
1477+}
1478+
1479+void GINN::Gremoved(GeisGestureType gesture_type, GeisGestureId gesture_id,GeisSize attr_count, GeisGestureAttr * attrs)
1480+{
1481+ int i = 0;
1482+ fprintf(stdout, "Gesture type %d removed\n", gesture_type);
1483+ for (i = 0; i < attr_count; ++i)
1484+ print_attr(&attrs[i]);
1485+}
1486+
1487+void GINN::Gstart(GeisGestureType gesture_type, GeisGestureId gesture_id, GeisSize attr_count, GeisGestureAttr * attrs)
1488+{
1489+ int i = 0;
1490+ fprintf(stdout, "Gesture type %d started\n", gesture_type);
1491+ for (i = 0; i < attr_count; ++i)
1492+ print_attr(&attrs[i]);
1493+
1494+ // In GEIS v1, we know that the focus coords are in attrs 5 and 6
1495+ movePointer((int)attrs[5].float_val, (int)attrs[6].float_val);
1496+}
1497+
1498+void GINN::Gupdate(GeisGestureType gesture_type, GeisGestureId gesture_id, GeisSize attr_count, GeisGestureAttr * attrs)
1499+{
1500+ int i = 0;
1501+ cout << "Gesture type " << gesture_type << " updated\n";
1502+ for (i = 0; i < attr_count; ++i)
1503+ print_attr(&attrs[i]);
1504+ Gmatch(gesture_type, gesture_id, attr_count, attrs,GINN_UPDATE);
1505+}
1506+
1507+void GINN::Gfinish(GeisGestureType gesture_type, GeisGestureId gesture_id, GeisSize attr_count, GeisGestureAttr * attrs)
1508+{
1509+ int i = 0;
1510+ fprintf(stdout, "Gesture type %d finished\n", gesture_type);
1511+ for (i = 0; i < attr_count; ++i); //print_attr(&attrs[i]);
1512+ Gmatch(gesture_type, gesture_id, attr_count, attrs, GINN_FINISH);
1513+}
1514+
1515+/*
1516+ * Searches for a default config file.
1517+ *
1518+ * Returns a pointer to a config file name (which must be freed) or NULL
1519+ * if no default config file was found.
1520+ */
1521+string GINN::ginn_default_config()
1522+{
1523+ string default_file_name = "/wishes.xml";
1524+ static char *search_paths[] = {"etc","../etc",".","$HOME/.ginn" , "/etc/ginn" , "/etc" };
1525+ static const int num_paths = sizeof(search_paths) / sizeof(const char *);
1526+ int i;
1527+
1528+ for (i = 0; i < num_paths; ++i)
1529+ {
1530+ struct stat sbuf;
1531+ string file_name;
1532+
1533+ if (strstr(search_paths[i], "$HOME"))
1534+ {
1535+ char *home_dir = getenv("HOME");
1536+ if (!home_dir)
1537+ {
1538+ continue;
1539+ }
1540+ else
1541+ {
1542+ char *cdr = index(search_paths[i], '/');
1543+ file_name = home_dir;
1544+ file_name += cdr;
1545+ }
1546+ }
1547+ else
1548+ {
1549+ file_name = search_paths[i];
1550+ }
1551+ file_name += default_file_name;
1552+ int sres = stat(file_name.c_str(), &sbuf);
1553+ if (sres == 0)
1554+ {
1555+ cout << "Using wishes file " << file_name << endl;
1556+ return file_name;
1557+ }
1558+ }
1559+
1560+ return "";
1561+}
1562+//! find out is the device is Direct Touch for example touchscreen is but touchpad not!
1563+bool GINN::isDirectTouch(int deviceID)
1564+{
1565+ GeisDevice device;
1566+ int count = geis_device_attr_count (device);
1567+ for (int i =0;i<count;i++)
1568+ {
1569+ GeisGestureAttr *buffer = (GeisGestureAttr *) geis_device_attr(device,i);
1570+ if (!strcmp(buffer->name , GEIS_DEVICE_ATTRIBUTE_DIRECT_TOUCH))
1571+ {
1572+ return buffer->boolean_val;
1573+ }
1574+ }
1575+}
1576+//! set Gesture functon callback for GEIS API.
1577+void GINN::setGFuncton(GCallback GaddedP, GCallback GremovedP, GCallback GstartP, GCallback GupdateP, GCallback GfinishP)
1578+{
1579+ gesture_funcs.added = GaddedP;
1580+ gesture_funcs.removed = GremovedP;
1581+ gesture_funcs.start = GstartP;
1582+ gesture_funcs.update = GupdateP;
1583+ gesture_funcs.finish = GfinishP;
1584+}
1585+//! get Gesture functon callback (More info on setGFuncton).
1586+GeisGestureFuncs GINN::getGFuncton()
1587+{
1588+ return gesture_funcs;
1589+}
1590+//! Open (even from argv) and Check Wish file automatically and if any problem emit error and print it.
1591+void GINN::loadConfig(int argc, char *argv[])
1592+{
1593+ if (argc < 2)
1594+ {
1595+ cerr << "usage: " << argv[0] << " <configxml>\n";
1596+ cfg_path = ginn_default_config();
1597+ if (cfg_path.empty())
1598+ {
1599+ cerr << "using default configuration file " << cfg_path << "... \n";
1600+ }
1601+ }
1602+ else
1603+ {
1604+ cfg_path = strdup(argv[1]);
1605+ }
1606+ if (cfg_path.empty())
1607+ {
1608+ cerr << "Could not find Ginn wishes\n";
1609+ exit (-1);
1610+ }
1611+
1612+ if (ginn_config_open(&cfg, cfg_path.c_str()))
1613+ {
1614+ cerr << "Could not load Ginn wishes\n";
1615+ exit (-1);
1616+ }
1617+ config_load = true;
1618+}
1619+//! Print the config file.
1620+void GINN::printConfig()
1621+{
1622+ if (config_load)
1623+ ginn_config_print(&cfg);
1624+}
1625+//! Store the config file and process it
1626+void GINN::StoreConfig()
1627+{
1628+ if (config_load)
1629+ ginn_config_store(&cfg, wp, ap);
1630+}
1631+
1632+//! subscribe all gesture callback and other value on GEIS
1633+GeisStatus GINN::Gsubscribe(GeisInstance geis_instance, GeisInputDeviceId *input_list, const char **gesture_list)
1634+{
1635+ return geis_subscribe(geis_instance, input_list, gesture_list, &gesture_funcs, this);
1636+}
1637+//! set Device functon callback for GEIS API.
1638+void GINN::setDFuncton(DCallback DaddedP, DCallback DchangedP, DCallback DremovedP)
1639+{
1640+ device_funcs.added = DaddedP;
1641+ device_funcs.removed = DremovedP;
1642+ device_funcs.changed = DchangedP;
1643+}
1644+//! get Device functon callback (More info on setDFuncton).
1645+GeisInputFuncs GINN::getDFuncton()
1646+{
1647+ return device_funcs;
1648+}
1649+//! subscribe all Device callback and other value on GEIS
1650+GeisStatus GINN::Dsubscribe(GeisInstance geis_instance)
1651+{
1652+ return geis_input_devices(geis_instance, &device_funcs, this);
1653+}
1654+//! when a touch device add this function called
1655+void GINN::Dadded(GeisInputDeviceId device_id, void *attrs)
1656+{
1657+ GeisGestureAttr *a = (GeisGestureAttr *)attrs;
1658+ GD_att buffer;
1659+ try
1660+ {
1661+ buffer.ID = device_id;
1662+ buffer.name = a[0].string_val;
1663+ buffer.isDirectTouch = a[2].boolean_val;
1664+ buffer.TouchNum = a[3].integer_val;
1665+ device_list.push_back(buffer);
1666+ }
1667+ catch(error_t error)
1668+ {
1669+ cerr << "Erorr on read Device atrribute for device with ID: " << device_id << endl;
1670+ }
1671+}
1672+//! when a touch device attributes changed this function called
1673+void GINN::Dchanged(GeisInputDeviceId device_id, void *attrs)
1674+{
1675+ ;
1676+}
1677+//! when a touch device removed this function called
1678+void GINN::Dremoved(GeisInputDeviceId device_id, void *attrs)
1679+{
1680+ int index = DId2Index(device_id);
1681+ device_list.erase(device_list.begin() + index);
1682+}
1683+//! return Device index in device_list from deviceID ; return -1 if the device not found
1684+int GINN::DId2Index(int DeviceID)
1685+{
1686+ for (int i=0;i<device_list.size();i++)
1687+ {
1688+ if(device_list[i].ID == DeviceID)
1689+ return i;
1690+ }
1691+ return -1;
1692+}
1693+
1694+/**
1695+ * Check the loaded wishes to see which gestures are used
1696+ * and add these gestures to a NULL terminated list "sub_gestures_list"
1697+ *
1698+ * This list is used to subscribe only the necessary gestures
1699+ * to GEIS. This will avoid issues with 2 finger scrolls and other gestues
1700+ * being dropped when not accounted for in the wishes file.
1701+**/
1702+vector<string> GINN::extract_gesture()
1703+{
1704+ Gapps * appPtr = ap;
1705+ Gwish * wishPtr;
1706+ int finished = 0;
1707+ vector<string> sub_gestures_list(17);
1708+ /**
1709+ * Loop through each wish inside ap
1710+ * After all of the wishes in ap are accounted for
1711+ * add global wishes
1712+ **/
1713+
1714+ while(finished != 1)
1715+ {
1716+ // Check if we are finished with the application wishes
1717+ if(appPtr == NULL)
1718+ {
1719+ wishPtr = wp;
1720+ finished = 1;
1721+ }
1722+ else
1723+ {
1724+ wishPtr = appPtr->wp;
1725+ }
1726+
1727+ // Loop through each wish
1728+ while(wishPtr)
1729+ {
1730+ int i;
1731+ for(i = 0; i < 25; i ++)
1732+ {
1733+
1734+ string sub_gesture;
1735+ char buffer[100];
1736+ int pos = 0;
1737+
1738+ // Check for Drag gesture
1739+ if(wishPtr->config_attr[i].attrName == "delta x" || wishPtr->config_attr[i].attrName == "delta y" ||
1740+ wishPtr->config_attr[i].attrName == "velocity x" || wishPtr->config_attr[i].attrName == "velocity y")
1741+ {
1742+ sprintf(buffer, "Drag,touch=%i", (int)wishPtr->config_attr[1].val);
1743+ }
1744+
1745+ // Check for Rotate gesture
1746+ else if(wishPtr->config_attr[i].attrName == "angle delta"||
1747+ wishPtr->config_attr[i].attrName == "angular velocity"||
1748+ wishPtr->config_attr[i].attrName == "angle")
1749+ {
1750+ sprintf(buffer, "Rotate,touch=%i", (int)wishPtr->config_attr[1].val);
1751+ }
1752+
1753+ // Check for Pinch gesture
1754+ else if(wishPtr->config_attr[i].attrName == "radius delta" ||wishPtr->config_attr[i].attrName == "radial velocity" ||
1755+ wishPtr->config_attr[i].attrName == "radius")
1756+ {
1757+ sprintf(buffer, "Pinch,touch=%i", (int)wishPtr->config_attr[1].val);
1758+ }
1759+
1760+ // Check for Tap gesture
1761+ else if(wishPtr->config_attr[i].attrName == "tap time")
1762+ {
1763+ sprintf(buffer, "Tap,touch=%i", (int)wishPtr->config_attr[1].val);
1764+ }
1765+
1766+ // Deallocate sub_gesture if no gesture was found
1767+ else
1768+ {
1769+ buffer[0] = NULL;
1770+ continue;
1771+ }
1772+ sub_gesture = buffer;
1773+
1774+ /** Check the current gesture list
1775+ * Only add if the gesture is not already in the list
1776+ * Store in index of the first NULL found
1777+ **/
1778+
1779+ while(pos < 17)
1780+ {
1781+ if(sub_gestures_list[pos].empty())
1782+ {
1783+ sub_gestures_list[pos] = sub_gesture;
1784+ break;
1785+ }
1786+ else if(sub_gesture == sub_gestures_list[pos])
1787+ {
1788+ break;
1789+ }
1790+ pos ++;
1791+ }
1792+
1793+
1794+ }
1795+ // Iterate to the next wish
1796+ wishPtr = wishPtr->next;
1797+ }
1798+
1799+ // If there are more applications, iterate to the next
1800+
1801+ if(finished != 1)
1802+ {
1803+ appPtr = appPtr->next;
1804+ }
1805+ }
1806+ return sub_gestures_list;
1807+}
1808+
1809+//! print the Subscribe gesture list
1810+void GINN::print_SGL(const char **sub_gestures_list)
1811+{
1812+ // Show which gestures were subscribed
1813+ cout << "Gestures subscribed:" << endl;
1814+
1815+ int pos = 0;
1816+ while(pos < 17)
1817+ {
1818+ if(sub_gestures_list[pos] != NULL)
1819+ {
1820+ cout << sub_gestures_list[pos] << endl;
1821+ }
1822+
1823+ pos ++;
1824+ }
1825+}
1826+
1827+
1828+
1829+
1830+
1831+
1832+
1833+
1834+
1835+
1836+
1837+
1838+
1839+
1840+
1841+
1842+
1843+
1844+
1845+
1846+
1847+
1848+
1849+
1850+
1851+
1852+
1853+
1854
1855=== added file 'src/ginn.h'
1856--- src/ginn.h 1970-01-01 00:00:00 +0000
1857+++ src/ginn.h 2011-08-23 04:19:23 +0000
1858@@ -0,0 +1,60 @@
1859+#ifndef GINN_H
1860+#define GINN_H
1861+
1862+#include "config.h"
1863+
1864+typedef GeisGestureCallback GCallback;
1865+typedef GeisInputCallback DCallback;
1866+
1867+class GINN
1868+{
1869+public:
1870+ GINN();
1871+ void Gmatch(GeisGestureType gesture_type, GeisGestureId gesture_id,GeisSize attr_count,GeisGestureAttr * attrs, int state);
1872+ int inside(float x, float a, float b);
1873+ bool isDirectTouch(int deviceID);
1874+ void clear_accum_attrs(att * attrs);
1875+ void update_wishes();
1876+ void print_SGL(const char **sub_gestures_list);
1877+ void print_attr(GeisGestureAttr * attr);
1878+ Window getRootWindow();
1879+ string ginn_default_config();
1880+ vector<string> extract_gesture();
1881+//New Interfaces:
1882+ int DId2Index(int DeviceID);
1883+ void printConfig();
1884+ void StoreConfig();
1885+ void loadConfig(int argc, char *argv[]);
1886+ void setGFuncton(GCallback GaddedP, GCallback GremovedP, GCallback GstartP, GCallback GupdateP, GCallback GfinishP);
1887+ GeisGestureFuncs getGFuncton();
1888+ void setDFuncton(DCallback DaddedP, DCallback DchangedP, DCallback DremovedP);
1889+ GeisInputFuncs getDFuncton();
1890+ GeisStatus Gsubscribe(GeisInstance geis_instance, GeisInputDeviceId *input_list, const char **gesture_list);
1891+ GeisStatus Dsubscribe(GeisInstance geis_instance);
1892+//CallBacks:
1893+ //Gesture CallBacks
1894+ void Gadded (GeisGestureType gesture_type, GeisGestureId gesture_id, GeisSize attr_count, GeisGestureAttr * attrs);
1895+ void Gremoved(GeisGestureType gesture_type, GeisGestureId gesture_id, GeisSize attr_count, GeisGestureAttr * attrs);
1896+ void Gstart (GeisGestureType gesture_type, GeisGestureId gesture_id, GeisSize attr_count, GeisGestureAttr * attrs);
1897+ void Gupdate (GeisGestureType gesture_type, GeisGestureId gesture_id, GeisSize attr_count, GeisGestureAttr * attrs);
1898+ void Gfinish (GeisGestureType gesture_type, GeisGestureId gesture_id, GeisSize attr_count, GeisGestureAttr * attrs);
1899+ //Device CallBacks (D in Dadded referred to Device)
1900+ void Dadded (GeisInputDeviceId device_id, void *attrs);
1901+ void Dchanged(GeisInputDeviceId device_id, void *attrs);
1902+ void Dremoved(GeisInputDeviceId device_id, void *attrs);
1903+//Variable:
1904+ Gwish *wp, *wpEnd;
1905+ Gapps *ap;
1906+ att config_attr[25];
1907+ Gwish w1;
1908+private:
1909+ GeisGestureFuncs gesture_funcs;
1910+ GeisInputFuncs device_funcs;
1911+ ginn_config cfg;
1912+ string cfg_path;
1913+ vector<GD_att> device_list; //save Device list and device attribute
1914+ bool config_load;
1915+};
1916+
1917+
1918+#endif // GINN_H
1919
1920=== modified file 'src/ginn.pod' (properties changed: -x to +x)
1921=== added file 'src/gir.cpp'
1922--- src/gir.cpp 1970-01-01 00:00:00 +0000
1923+++ src/gir.cpp 2011-08-23 04:19:23 +0000
1924@@ -0,0 +1,47 @@
1925+#include "gir.h"
1926+
1927+Gapps::Gapps()
1928+{
1929+ next = NULL;
1930+ wp = NULL;
1931+ appName = "";
1932+}
1933+
1934+Gwish::Gwish()
1935+{
1936+ //Default Value
1937+ Type = -1;
1938+ TouchNum = 0;
1939+ DirectTouch = -1;
1940+ //
1941+ int i;
1942+ button = 0;
1943+ key = "";
1944+ next = NULL;
1945+ for (i = 0; i < 4; i++)
1946+ modifiers[i] = "";
1947+ for (i = 0; i < 25; i++)
1948+ {
1949+ config_attr[i].attrName = "";
1950+ config_attr[i].val = 0;
1951+ config_attr[i].valMax = 0;
1952+ }
1953+}
1954+
1955+
1956+
1957+
1958+
1959+
1960+
1961+
1962+
1963+
1964+
1965+
1966+
1967+
1968+
1969+
1970+
1971+
1972
1973=== added file 'src/gir.h'
1974--- src/gir.h 1970-01-01 00:00:00 +0000
1975+++ src/gir.h 2011-08-23 04:19:23 +0000
1976@@ -0,0 +1,70 @@
1977+/**
1978+ * New Implemetion for GINN Include C++ Callback
1979+ */
1980+
1981+#ifndef GIR_H
1982+#define GIR_H
1983+
1984+#include "ginn.h"
1985+
1986+/** Gesure CallBack Interface Start Decration HERE! These function recieve events from GEIS and send it to
1987+related object as well as a postman!
1988+***/
1989+static void gesture_added(void *cookie,GeisGestureType gesture_type, GeisGestureId gesture_id,
1990+ GeisSize attr_count, GeisGestureAttr * attrs)
1991+{
1992+ GINN *buffer = (GINN *) cookie;
1993+ buffer->Gadded(gesture_type,gesture_id,attr_count,attrs);
1994+}
1995+
1996+static void gesture_removed(void *cookie, GeisGestureType gesture_type, GeisGestureId gesture_id,
1997+ GeisSize attr_count, GeisGestureAttr * attrs)
1998+{
1999+ GINN *buffer = (GINN *) cookie;
2000+ buffer->Gadded(gesture_type,gesture_id,attr_count,attrs);
2001+}
2002+
2003+static void gesture_start(void *cookie, GeisGestureType gesture_type, GeisGestureId gesture_id,
2004+ GeisSize attr_count, GeisGestureAttr * attrs)
2005+{
2006+ GINN *buffer = (GINN *) cookie;
2007+ buffer->Gstart(gesture_type,gesture_id,attr_count,attrs);
2008+}
2009+
2010+static void gesture_update(void *cookie, GeisGestureType gesture_type,
2011+ GeisGestureId gesture_id, GeisSize attr_count, GeisGestureAttr * attrs)
2012+{
2013+ GINN *buffer = (GINN *) cookie;
2014+ buffer->Gupdate(gesture_type,gesture_id,attr_count,attrs);
2015+}
2016+
2017+static void gesture_finish(void *cookie, GeisGestureType gesture_type,
2018+ GeisGestureId gesture_id, GeisSize attr_count, GeisGestureAttr * attrs)
2019+{
2020+ GINN *buffer = (GINN *) cookie;
2021+ buffer->Gfinish(gesture_type,gesture_id,attr_count,attrs);
2022+}
2023+
2024+/** Device CallBack Interface Start Decration HERE! These function recieve events from GEIS and send it to
2025+related object as well as a postman!
2026+***/
2027+static void device_added(void *cookie, GeisInputDeviceId device_id, void *attrs)
2028+{
2029+ GINN *buffer = (GINN *) cookie;
2030+ buffer->Dadded(device_id,attrs);
2031+}
2032+
2033+
2034+static void device_changed(void *cookie, GeisInputDeviceId device_id, void *attrs)
2035+{
2036+ GINN *buffer = (GINN *) cookie;
2037+ buffer->Dchanged(device_id,attrs);
2038+}
2039+
2040+
2041+static void device_removed(void *cookie, GeisInputDeviceId device_id, void *attrs)
2042+{
2043+ GINN *buffer = (GINN *) cookie;
2044+ buffer->Dremoved(device_id,attrs);
2045+}
2046+#endif // GIR_H
2047
2048=== added file 'src/header.h'
2049--- src/header.h 1970-01-01 00:00:00 +0000
2050+++ src/header.h 2011-08-23 04:19:23 +0000
2051@@ -0,0 +1,38 @@
2052+#ifndef HEADER_H
2053+#define HEADER_H
2054+
2055+//Standart C and C++ Header
2056+#include <string>
2057+#include <vector>
2058+#include <cstring>
2059+#include <errno.h>
2060+#include <stdio.h>
2061+#include <stdlib.h>
2062+#include <string.h>
2063+#include <unistd.h>
2064+#include <iostream>
2065+//X window Header
2066+#include <X11/X.h>
2067+#include <X11/Xlib.h>
2068+#include <X11/keysym.h>
2069+#include <X11/extensions/XTest.h>
2070+//Other
2071+#include <sys/select.h>
2072+#include <sys/stat.h>
2073+#include <libxml/tree.h>
2074+#include <geis/geis.h>
2075+#include <libxml/parser.h>
2076+
2077+using namespace std;
2078+
2079+//Function Prototypes
2080+char *getCurrentApp();
2081+//Decleare in xt.cpp
2082+void injMixBtnKey (KeySym ks, int btn, string *modifiers);
2083+void injButton (int btn, string *modifiers);
2084+void injKey (KeySym ks, string *modifiers);
2085+void movePointer (int x, int y);
2086+void openDisplay ( );
2087+void closeDisplay ( );
2088+
2089+#endif // HEADER_H
2090
2091=== added file 'src/main.cpp'
2092--- src/main.cpp 1970-01-01 00:00:00 +0000
2093+++ src/main.cpp 2011-08-23 04:19:23 +0000
2094@@ -0,0 +1,137 @@
2095+/**
2096+ * Copyright 2010 Canonical Ltd.
2097+ *
2098+ * This library is free software; you can redistribute it and/or modify it under
2099+ * the terms of the GNU General Public License as published by the Free Software
2100+ * Foundation; either version 3 of the License, or (at your option) any later
2101+ * version.
2102+ *
2103+ * This library is distributed in the hope that it will be useful, but WITHOUT
2104+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
2105+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
2106+ * details.
2107+ *
2108+ * You should have received a copy of the GNU General Public License along with
2109+ * this program; if not, write to the Free Software Foundation, Inc., 51
2110+ * Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
2111+ *
2112+ * Authors:
2113+ * Mohamed-Ikbel Boulabiar <boulabiar@gmail.com>
2114+ * Henrik Rydberg <rydberg@bitmath.org>
2115+ * Stephen M. Webb <stephen.webb@canonical.com>
2116+ * Bijan Binaee <bijanbina@gmail.com>
2117+ *
2118+ */
2119+
2120+#include "gir.h"
2121+
2122+int main(int argc, char *argv[])
2123+{
2124+ GeisStatus status = GEIS_UNKNOWN_ERROR;
2125+ GeisXcbWinInfo xcb_win_info;
2126+ GINN local;
2127+ //Initizalize xcb_win_info
2128+ xcb_win_info.display_name = NULL;
2129+ xcb_win_info.screenp = NULL;
2130+ xcb_win_info.window_id = local.getRootWindow();
2131+ //Initialize win_info
2132+ GeisWinInfo win_info = {GEIS_XCB_FULL_WINDOW,&xcb_win_info};
2133+ GeisInstance instance;
2134+ //Initializ GINN Class
2135+ local.setGFuncton(gesture_added, gesture_removed, gesture_start, gesture_update, gesture_finish);
2136+ local.setDFuncton(device_added,device_changed,device_removed);
2137+
2138+ local.loadConfig(argc,argv);
2139+ //local.printConfig();
2140+ local.StoreConfig();
2141+
2142+
2143+ local.wpEnd = local.wp;
2144+ while (local.wpEnd->next)
2145+ local.wpEnd = local.wpEnd->next;
2146+
2147+ int pos = 2;
2148+ cout << endl;
2149+ while (!local.config_attr[pos].attrName.empty())
2150+ {
2151+ cout << "DEBUG " << pos << local.config_attr[pos].attrName << local.config_attr[pos].val << local.config_attr[pos].valMax << endl;
2152+ pos++;
2153+ }
2154+
2155+ //Use Dynamic sub gestures list
2156+ vector<string> SGL = local.extract_gesture();//sub gestures list buffer
2157+ const char *sub_gestures_list[SGL.size()];
2158+ //convert to const char
2159+ for (int i =0;i<SGL.size();i++)
2160+ {
2161+ sub_gestures_list[i] = (char *)(SGL[i].c_str());
2162+ if (SGL[i].empty())
2163+ sub_gestures_list[i]= NULL;
2164+ }
2165+ local.print_SGL(sub_gestures_list);
2166+ //End Use Dynamic sub gestures list
2167+
2168+ status = geis_init(&win_info, &instance);
2169+ if (status != GEIS_STATUS_SUCCESS) {
2170+ cerr << "error in geis_init\n";
2171+ return 1;
2172+ }
2173+
2174+ status = geis_configuration_supported(instance, GEIS_CONFIG_UNIX_FD);
2175+ if (status != GEIS_STATUS_SUCCESS) {
2176+ cerr << "GEIS does not support Unix fd\n";
2177+ return 1;
2178+ }
2179+
2180+ int fd = -1;
2181+ status = geis_configuration_get_value(instance, GEIS_CONFIG_UNIX_FD, &fd);
2182+ if (status != GEIS_STATUS_SUCCESS)
2183+ {
2184+ cerr << "error retrieving GEIS fd\n";
2185+ return 1;
2186+ }
2187+ //Subscribe Device input callback
2188+ status = local.Dsubscribe(instance);// GEIS_ALL_GESTURES,
2189+ if (status != GEIS_STATUS_SUCCESS)
2190+ {
2191+ cerr << "error on subscribing to Device\n";
2192+ return 1;
2193+ }
2194+ //Subscribe gesture callback
2195+ status = local.Gsubscribe(instance, GEIS_ALL_INPUT_DEVICES, const_cast <const char**>(sub_gestures_list));// GEIS_ALL_GESTURES,
2196+ if (status != GEIS_STATUS_SUCCESS)
2197+ {
2198+ cerr << "error on subscribing to gestures\n";
2199+ return 1;
2200+ }
2201+
2202+ openDisplay();
2203+
2204+ while (1)
2205+ {
2206+ fd_set read_fds;
2207+ FD_ZERO(&read_fds);
2208+ FD_SET(fd, &read_fds);
2209+ int sstat = select(fd + 1, &read_fds, NULL, NULL, NULL);
2210+ if (sstat < 0)
2211+ {
2212+ cerr << "error " << errno << "in select(): " << strerror(errno) << endl;
2213+ break;
2214+ }
2215+
2216+ if (FD_ISSET(fd, &read_fds))
2217+ geis_event_dispatch(instance);
2218+ }
2219+
2220+ delete local.wp;
2221+ geis_finish(instance);
2222+ closeDisplay();
2223+
2224+ return 0;
2225+}
2226+
2227+
2228+
2229+
2230+
2231+
2232
2233=== modified file 'src/todo' (properties changed: -x to +x)
2234=== removed file 'src/xt.c'
2235--- src/xt.c 2011-03-16 16:23:21 +0000
2236+++ src/xt.c 1970-01-01 00:00:00 +0000
2237@@ -1,108 +0,0 @@
2238-/*
2239- * Copyright (C) 2010 Canonical, Ltd.
2240- *
2241- * This program is free software: you can redistribute it and/or modify
2242- * it under the terms of the GNU General Public License as published by
2243- * the Free Software Foundation, either version 3 of the License, or
2244- * (at your option) any later version.
2245-
2246- * This program is distributed in the hope that it will be useful,
2247- * but WITHOUT ANY WARRANTY; without even the implied warranty of
2248- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
2249- * GNU General Public License for more details.
2250-
2251- * You should have received a copy of the GNU General Public License
2252- * along with this program. If not, see <http://www.gnu.org/licenses/>.
2253- *
2254- * Author: Mohamed-Ikbel Boulabiar <boulabiar@gmail.com>
2255- */
2256-
2257-#include <X11/X.h>
2258-#include <X11/extensions/XTest.h>
2259-#include <X11/keysym.h>
2260-
2261-static Display *disp = NULL;
2262-
2263-void openDisplay()
2264-{
2265- disp = XOpenDisplay(NULL);
2266-}
2267-
2268-void closeDisplay()
2269-{
2270- XCloseDisplay(disp);
2271-}
2272-
2273-void movePointer(int x, int y)
2274-{
2275- XTestFakeMotionEvent(disp, 0, x, y, CurrentTime);
2276-}
2277-
2278-void injKey(KeySym ks, char *modifiers[])
2279-{
2280- int i;
2281-
2282- for (i = 0; i < 4 && 0 != strcmp(modifiers[i], ""); i++)
2283- XTestFakeKeyEvent(disp,
2284- XKeysymToKeycode(disp,
2285- XStringToKeysym(modifiers
2286- [i])), True,
2287- CurrentTime);
2288- XTestFakeKeyEvent(disp, XKeysymToKeycode(disp, ks), True, CurrentTime);
2289- XTestFakeKeyEvent(disp, XKeysymToKeycode(disp, ks), False,
2290- CurrentTime);
2291- for (i = 0; i < 4 && 0 != strcmp(modifiers[i], ""); i++)
2292- XTestFakeKeyEvent(disp,
2293- XKeysymToKeycode(disp,
2294- XStringToKeysym(modifiers
2295- [i])), False,
2296- CurrentTime);
2297-
2298- XFlush(disp);
2299-}
2300-
2301-void injButton(int btn, char *modifiers[])
2302-{
2303- int i;
2304-
2305- for (i = 0; i < 4 && 0 != strcmp(modifiers[i], ""); i++)
2306- XTestFakeKeyEvent(disp,
2307- XKeysymToKeycode(disp,
2308- XStringToKeysym(modifiers
2309- [i])), True,
2310- CurrentTime);
2311- XTestFakeButtonEvent(disp, btn, True, CurrentTime);
2312- XTestFakeButtonEvent(disp, btn, False, CurrentTime);
2313- for (i = 0; i < 4 && 0 != strcmp(modifiers[i], ""); i++)
2314- XTestFakeKeyEvent(disp,
2315- XKeysymToKeycode(disp,
2316- XStringToKeysym(modifiers
2317- [i])), False,
2318- CurrentTime);
2319-
2320- XFlush(disp);
2321-}
2322-
2323-void injMixBtnKey(KeySym ks, int btn, char *modifiers[])
2324-{
2325- int i;
2326-
2327- XTestFakeButtonEvent(disp, btn, True, CurrentTime);
2328- for (i = 0; i < 4 && 0 != strcmp(modifiers[i], ""); i++)
2329- XTestFakeKeyEvent(disp,
2330- XKeysymToKeycode(disp,
2331- XStringToKeysym(modifiers
2332- [i])), True,
2333- CurrentTime);
2334- XTestFakeKeyEvent(disp, XKeysymToKeycode(disp, ks), True, CurrentTime);
2335- XTestFakeKeyEvent(disp, XKeysymToKeycode(disp, ks), False,
2336- CurrentTime);
2337- for (i = 0; i < 4 && 0 != strcmp(modifiers[i], ""); i++)
2338- XTestFakeKeyEvent(disp,
2339- XKeysymToKeycode(disp,
2340- XStringToKeysym(modifiers
2341- [i])), False,
2342- CurrentTime);
2343- XTestFakeButtonEvent(disp, btn, False, CurrentTime);
2344- XFlush(disp);
2345-}
2346
2347=== added file 'src/xt.cpp'
2348--- src/xt.cpp 1970-01-01 00:00:00 +0000
2349+++ src/xt.cpp 2011-08-23 04:19:23 +0000
2350@@ -0,0 +1,97 @@
2351+/*
2352+ * Copyright (C) 2010 Canonical, Ltd.
2353+ *
2354+ * This program is free software: you can redistribute it and/or modify
2355+ * it under the terms of the GNU General Public License as published by
2356+ * the Free Software Foundation, either version 3 of the License, or
2357+ * (at your option) any later version.
2358+
2359+ * This program is distributed in the hope that it will be useful,
2360+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
2361+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
2362+ * GNU General Public License for more details.
2363+
2364+ * You should have received a copy of the GNU General Public License
2365+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
2366+ *
2367+ * Author: Mohamed-Ikbel Boulabiar <boulabiar@gmail.com>
2368+ */
2369+#include "header.h"
2370+
2371+static Display *disp = NULL;
2372+
2373+void openDisplay()
2374+{
2375+ disp = XOpenDisplay(NULL);
2376+}
2377+
2378+void closeDisplay()
2379+{
2380+ XCloseDisplay(disp);
2381+}
2382+
2383+void movePointer(int x, int y)
2384+{
2385+ XTestFakeMotionEvent(disp, 0, x, y, CurrentTime);
2386+}
2387+
2388+void injKey(KeySym ks, string *modifiers)
2389+{
2390+ int i;
2391+
2392+ for (i = 0; i < 4 && !modifiers[i].empty(); i++)
2393+ XTestFakeKeyEvent(disp,
2394+ XKeysymToKeycode(disp,
2395+ XStringToKeysym(modifiers[i].c_str())), True,
2396+ CurrentTime);
2397+ XTestFakeKeyEvent(disp, XKeysymToKeycode(disp, ks), True, CurrentTime);
2398+ XTestFakeKeyEvent(disp, XKeysymToKeycode(disp, ks), False,
2399+ CurrentTime);
2400+ for (i = 0; i < 4 && !modifiers[i].empty(); i++)
2401+ XTestFakeKeyEvent(disp,
2402+ XKeysymToKeycode(disp,
2403+ XStringToKeysym(modifiers[i].c_str())), False,
2404+ CurrentTime);
2405+
2406+ XFlush(disp);
2407+}
2408+
2409+void injButton(int btn, string *modifiers)
2410+{
2411+ int i;
2412+
2413+ for (i = 0; i < 4 && !modifiers[i].empty(); i++)
2414+ XTestFakeKeyEvent(disp,
2415+ XKeysymToKeycode(disp,
2416+ XStringToKeysym(modifiers[i].c_str())), True,
2417+ CurrentTime);
2418+ XTestFakeButtonEvent(disp, btn, True, CurrentTime);
2419+ XTestFakeButtonEvent(disp, btn, False, CurrentTime);
2420+ for (i = 0; i < 4 && !modifiers[i].empty(); i++)
2421+ XTestFakeKeyEvent(disp,
2422+ XKeysymToKeycode(disp,
2423+ XStringToKeysym(modifiers[i].c_str())), False,
2424+ CurrentTime);
2425+
2426+ XFlush(disp);
2427+}
2428+
2429+void injMixBtnKey(KeySym ks, int btn, string *modifiers)
2430+{
2431+ int i;
2432+
2433+ XTestFakeButtonEvent(disp, btn, True, CurrentTime);
2434+ for (i = 0; i < 4 && !modifiers[i].empty(); i++)
2435+ XTestFakeKeyEvent(disp,
2436+ XKeysymToKeycode(disp, XStringToKeysym(modifiers [i].c_str())), True,
2437+ CurrentTime);
2438+ XTestFakeKeyEvent(disp, XKeysymToKeycode(disp, ks), True, CurrentTime);
2439+ XTestFakeKeyEvent(disp, XKeysymToKeycode(disp, ks), False,
2440+ CurrentTime);
2441+ for (i = 0; i < 4 && !modifiers[i].empty(); i++)
2442+ XTestFakeKeyEvent(disp, XKeysymToKeycode(disp,
2443+ XStringToKeysym(modifiers [i].c_str())), False,
2444+ CurrentTime);
2445+ XTestFakeButtonEvent(disp, btn, False, CurrentTime);
2446+ XFlush(disp);
2447+}