~ubuntu-branches/ubuntu/trusty/libgii/trusty

« back to all changes in this revision

Viewing changes to filter/mouse/filter.c

  • Committer: Bazaar Package Importer
  • Author(s): Martin Albert
  • Date: 2001-08-27 23:17:32 UTC
  • Revision ID: james.westby@ubuntu.com-20010827231732-5kiieyxb3mvj25ur
Tags: upstream-0.8.1
ImportĀ upstreamĀ versionĀ 0.8.1

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* $Id: filter.c,v 1.2 2001/06/17 08:34:30 cegger Exp $
 
2
******************************************************************************
 
3
 
 
4
   Filter-mouse - generic mouse event translaator.
 
5
 
 
6
   Copyright (C) 1999 Andreas Beck      [becka@ggi-project.org]
 
7
 
 
8
   Permission is hereby granted, free of charge, to any person obtaining a
 
9
   copy of this software and associated documentation files (the "Software"),
 
10
   to deal in the Software without restriction, including without limitation
 
11
   the rights to use, copy, modify, merge, publish, distribute, sublicense,
 
12
   and/or sell copies of the Software, and to permit persons to whom the
 
13
   Software is furnished to do so, subject to the following conditions:
 
14
 
 
15
   The above copyright notice and this permission notice shall be included in
 
16
   all copies or substantial portions of the Software.
 
17
 
 
18
   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 
19
   IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 
20
   FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
 
21
   THE AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
 
22
   IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
 
23
   CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 
24
 
 
25
******************************************************************************
 
26
*/
 
27
 
 
28
#include <math.h>
 
29
#include <stdlib.h>
 
30
#include <string.h>
 
31
#include <ctype.h>
 
32
 
 
33
#include <ggi/internal/gii-dl.h>
 
34
#include <ggi/internal/gii_debug.h>
 
35
 
 
36
static void send_devinfo(gii_input *inp);
 
37
 
 
38
enum maptype { 
 
39
        MAP_KEY,
 
40
        MAP_REL,
 
41
        MAP_ABS,
 
42
        MAP_BUTTON,
 
43
        MAP_TO,         /* Dummy entry for parsing */
 
44
        MAP_END
 
45
};
 
46
 
 
47
const char *maptypelist[MAP_END]={
 
48
        "KEY",
 
49
        "REL",
 
50
        "ABS",
 
51
        "BUT",
 
52
        "TO"
 
53
};
 
54
 
 
55
enum axis {
 
56
        AX_X,
 
57
        AX_Y,
 
58
        AX_Z,
 
59
        AX_WHEEL,
 
60
        AX_END
 
61
};
 
62
 
 
63
const char *axislist[AX_END]={
 
64
        "X",
 
65
        "Y",
 
66
        "Z",
 
67
        "W"
 
68
};
 
69
 
 
70
struct transform {
 
71
        enum axis axis;
 
72
        double factor,treshold,higher;
 
73
};
 
74
 
 
75
typedef struct mapping_entry {
 
76
 
 
77
        struct mapping_entry *next;
 
78
 
 
79
        enum maptype from;
 
80
        uint32  modifier_mask;  /* all modifiers in mask */
 
81
        uint32  modifier_value; /* must match value */
 
82
        union   {
 
83
                struct key {
 
84
                        uint32 button, label, symbol;
 
85
                } key;
 
86
                enum axis axis;
 
87
                int button;
 
88
        } fromdata;
 
89
        enum maptype to;
 
90
        union {
 
91
                struct transform trans;
 
92
                int button;
 
93
        } todata;
 
94
} mapping_entry;
 
95
 
 
96
typedef struct {
 
97
        mapping_entry *entry;
 
98
        uint32 modifiers;
 
99
} fmouse_priv;
 
100
 
 
101
static void
 
102
fmouse_send_pbutton(gii_input *inp, uint8 type, uint32 nr)
 
103
{
 
104
        gii_event ev;
 
105
 
 
106
        _giiEventBlank(&ev, sizeof(gii_pbutton_event));
 
107
        ev.pbutton.type = type;
 
108
        ev.pbutton.size = sizeof(gii_pbutton_event);
 
109
        ev.pbutton.origin = inp->origin;
 
110
        ev.pbutton.target = GII_EV_TARGET_ALL;
 
111
        ev.pbutton.button = nr;
 
112
        _giiEvQueueAdd(inp, &ev);
 
113
}
 
114
 
 
115
 
 
116
static sint32 getaxis(gii_pmove_event *move,enum axis axis) {
 
117
        switch(axis) {
 
118
                case AX_X:      return move->x;
 
119
                case AX_Y:      return move->y;
 
120
                case AX_Z:      return move->z;
 
121
                case AX_WHEEL:  return move->wheel;
 
122
                default:        return 0;
 
123
        }
 
124
        return 0;       /* shouldn't happen. */
 
125
}
 
126
 
 
127
static void setaxis(gii_pmove_event *move,enum axis axis,sint32 value) {
 
128
        switch(axis) {
 
129
                case AX_X:      move->x=value;break;
 
130
                case AX_Y:      move->y=value;break;
 
131
                case AX_Z:      move->z=value;break;
 
132
                case AX_WHEEL:  move->wheel=value;break;
 
133
                default:        return;
 
134
        }
 
135
}
 
136
 
 
137
static sint32 gettrans(struct transform *tf,double invalue) {
 
138
        return invalue*tf->factor+
 
139
                ((fabs(invalue)>tf->treshold) ? (invalue > 0.0 ? invalue-tf->treshold : invalue+tf->treshold)*tf->higher : 0) ;
 
140
}
 
141
 
 
142
#define HASREL 1
 
143
#define HASABS 2
 
144
 
 
145
static int
 
146
GII_fmouse_handler(gii_input *inp, gii_event *event)
 
147
{
 
148
        fmouse_priv   *priv = inp->priv;
 
149
        mapping_entry *entry;
 
150
        int ret = 0;
 
151
        int has = 0;
 
152
        int invalue=0;
 
153
        static int di_sent=0;
 
154
        gii_pmove_event pmrel,pmabs;
 
155
        
 
156
        /* Did we already send the device info record ? Do so, if we didn't. */
 
157
        if (di_sent==0) { 
 
158
                di_sent=1;
 
159
                send_devinfo(inp); 
 
160
        }
 
161
        
 
162
        GIIDPRINT_MISC("filter-mouse: Filt check.\n");
 
163
        if (event->any.origin==inp->origin) 
 
164
                return 0;       /* avoid recursion ! */
 
165
        GIIDPRINT_MISC("filter-mouse: Real check.\n");
 
166
 
 
167
        /* Track modifiers. This allows to use stuff like shift-clicking */
 
168
        if (event->any.type==evKeyPress  ||
 
169
            event->any.type==evKeyRepeat ||
 
170
            event->any.type==evKeyRelease) {
 
171
                priv->modifiers=event->key.modifiers;
 
172
        }
 
173
 
 
174
        /* Clear the eventual relative and absolute events that will 
 
175
         * get sent after evaluating all rules. We should probably keep the
 
176
         * absolute events between calls.
 
177
         */
 
178
        _giiEventBlank((gii_event *)&pmrel, sizeof(gii_pmove_event));
 
179
        pmrel.type = evPtrRelative;
 
180
        pmrel.size = sizeof(gii_pmove_event);
 
181
        pmrel.origin = inp->origin;
 
182
        pmrel.target = GII_EV_TARGET_ALL;
 
183
        pmrel.x = pmrel.y = pmrel.z = pmrel.wheel = 0;
 
184
 
 
185
        _giiEventBlank((gii_event *)&pmabs, sizeof(gii_pmove_event));
 
186
        pmabs.type = evPtrAbsolute;
 
187
        pmabs.size = sizeof(gii_pmove_event);
 
188
        pmabs.origin = inp->origin;
 
189
        pmabs.target = GII_EV_TARGET_ALL;
 
190
        pmabs.x = pmabs.y = pmabs.z = pmabs.wheel = 0;
 
191
 
 
192
        /* Now go through the entries and convert as appropriate.
 
193
         */
 
194
        for(entry = priv->entry;entry;entry = entry->next) {
 
195
 
 
196
 
 
197
                GIIDPRINT_MISC("filter-mouse: Checking entry %p.\n",entry);
 
198
                if ((priv->modifiers&entry->modifier_mask)!=
 
199
                    entry->modifier_value) continue;    /* Modifiers are wrong. Forget it. */
 
200
 
 
201
                switch(entry->from) {
 
202
                        case MAP_KEY: 
 
203
                                if (event->any.type==evKeyPress||
 
204
                                    event->any.type==evKeyRepeat) invalue=1;    /* Key press */
 
205
                                else if (event->any.type==evKeyRelease) invalue=0;      /* Key release*/
 
206
                                else continue;                                  /* Something else - forget it. */
 
207
 
 
208
                                /* Continue, if the button/label/symbol doesn't match */
 
209
                                if (entry->fromdata.key.button!=GIIK_NIL&&
 
210
                                    entry->fromdata.key.button!=event->key.button) continue;
 
211
                                if (entry->fromdata.key.label!=GIIK_NIL&&
 
212
                                    entry->fromdata.key.label!=event->key.label) continue;
 
213
                                if (entry->fromdata.key.symbol!=GIIK_NIL&&
 
214
                                    entry->fromdata.key.symbol!=event->key.sym) continue;
 
215
                                break;
 
216
                        case MAP_REL:
 
217
                                if (event->any.type==evPtrRelative) 
 
218
                                        invalue=getaxis(&event->pmove,entry->fromdata.axis);
 
219
                                else continue;
 
220
                                break;
 
221
                        case MAP_ABS:
 
222
                                if (event->any.type==evPtrAbsolute) 
 
223
                                        invalue=getaxis(&event->pmove,entry->fromdata.axis);
 
224
                                else continue;
 
225
                                break;
 
226
                        case MAP_BUTTON:
 
227
                                if (event->any.type==evPtrButtonPress &&
 
228
                                    event->pbutton.button==entry->fromdata.button) invalue=1;
 
229
                                else if (event->any.type==evPtrButtonRelease &&
 
230
                                    event->pbutton.button==entry->fromdata.button) invalue=0;
 
231
                                else continue;
 
232
                                break;
 
233
                        default:continue;       /* Something is wrong */
 
234
                }
 
235
                switch(entry->to) {
 
236
                        case MAP_REL:
 
237
                                setaxis(&pmrel,entry->todata.trans.axis,gettrans(&entry->todata.trans,invalue));
 
238
                                ret=1;has|=HASREL;
 
239
                                break;
 
240
                        case MAP_ABS:
 
241
                                setaxis(&pmabs,entry->todata.trans.axis,gettrans(&entry->todata.trans,invalue));
 
242
                                ret=1;has|=HASABS;
 
243
                                break;
 
244
                        case MAP_BUTTON:
 
245
                                fmouse_send_pbutton(inp, 
 
246
                                        invalue ? evPtrButtonPress :
 
247
                                                evPtrButtonRelease, 
 
248
                                        entry->todata.button);
 
249
                                ret=1;
 
250
                                break;
 
251
                        default:continue; /* Something is WRONG here. */
 
252
                }
 
253
        }
 
254
        GIIDPRINT_MISC("filter-mouse: Checking entry %p.\n",entry);
 
255
 
 
256
        if (has&HASABS) {
 
257
                _giiEvQueueAdd(inp, (gii_event *) &pmabs);
 
258
        }
 
259
        if (has&HASREL) {
 
260
                _giiEvQueueAdd(inp, (gii_event *) &pmrel);
 
261
        }
 
262
        
 
263
        if (ret) GIIDPRINT_MISC("filter-mouse: Eating event.\n");
 
264
 
 
265
        return ret;
 
266
}
 
267
 
 
268
static int GII_fmouse_close(gii_input *inp)
 
269
{
 
270
        fmouse_priv   *priv = inp->priv;
 
271
        mapping_entry *entry,*next;
 
272
 
 
273
        GIIDPRINT_MISC("GII_fmouse_close(%p) called\n", inp);
 
274
 
 
275
        entry=priv->entry;
 
276
        while(entry) {
 
277
                next=entry->next;
 
278
                free(entry);
 
279
                entry=next;
 
280
        }
 
281
 
 
282
        free(priv);
 
283
 
 
284
        return 0;
 
285
}
 
286
 
 
287
static gii_cmddata_getdevinfo devinfo =
 
288
{
 
289
        "Mouse filter", /* long device name */
 
290
        "mouf",         /* shorthand */
 
291
        emPointer,      /* can_generate */
 
292
        4,              /* num_buttons  (no supported device have more) */
 
293
        0               /* num_axes     (only for valuators) */
 
294
};
 
295
 
 
296
static gii_deviceinfo xdevinfo =
 
297
{
 
298
        NULL,
 
299
        0,
 
300
        &devinfo,
 
301
        NULL
 
302
};
 
303
 
 
304
static void send_devinfo(gii_input *inp)
 
305
{
 
306
        gii_event ev;
 
307
        gii_cmddata_getdevinfo *dinfo;
 
308
        int size = sizeof(gii_cmd_nodata_event)+sizeof(gii_cmddata_getdevinfo);
 
309
 
 
310
        _giiEventBlank(&ev, size);
 
311
        
 
312
        ev.any.size   = size;
 
313
        ev.any.type   = evCommand;
 
314
        ev.any.origin = inp->origin;
 
315
        ev.cmd.code   = GII_CMDCODE_GETDEVINFO;
 
316
 
 
317
        dinfo = (gii_cmddata_getdevinfo *) ev.cmd.data;
 
318
        *dinfo = devinfo;
 
319
 
 
320
        _giiEvQueueAdd(inp, &ev);
 
321
}
 
322
 
 
323
static int checkkeyword(char *str,char **endptr,const char *list[],int numlist) {
 
324
        int x;
 
325
 
 
326
        if (endptr) *endptr=str;
 
327
        while(isspace((int)*str)) str++;
 
328
 
 
329
        for(x=0;x<numlist;x++) {
 
330
                if (0==strncasecmp(str, list[x], strlen(list[x]))) {
 
331
                        if (endptr) *endptr=str+strlen(list[x]);
 
332
                        return x;
 
333
                }
 
334
        }
 
335
        return -1;
 
336
}
 
337
 
 
338
static int fmouse_doload(const char *filename,fmouse_priv *priv) {
 
339
 
 
340
        FILE *infile;
 
341
        char buffer[2048],*parsepoint,*pp2;
 
342
        char *expect="nothing";
 
343
        int line=0;
 
344
        mapping_entry entry;
 
345
        mapping_entry **ptr;
 
346
        
 
347
        ptr=&priv->entry;
 
348
        
 
349
        while(*ptr) ptr=&((*ptr)->next);
 
350
 
 
351
        GIIDPRINT_MISC("filter-keymap opening config \"%s\" called\n", 
 
352
                       filename ? filename : "(nil)");
 
353
        if ( NULL==(infile=fopen(filename,"r")) ) {
 
354
                return GGI_ENOFILE;
 
355
        }
 
356
        while(fgets(buffer,2048,infile)) {
 
357
                line++;
 
358
                /* GIIDPRINT_MISC("filter-mouse should parse %s\n",buffer); - Shouldn't be needed anymore. */
 
359
                entry.next=NULL;
 
360
                parsepoint=pp2=buffer;
 
361
                switch(entry.from=checkkeyword(parsepoint=pp2,&pp2,maptypelist,MAP_TO)) {
 
362
                        case MAP_KEY:
 
363
                                entry.modifier_mask=strtol(parsepoint=pp2, &pp2, 0);
 
364
                                if (pp2==parsepoint) {expect="modmask";goto error;}
 
365
                                entry.modifier_value=strtol(parsepoint=pp2, &pp2, 0);
 
366
                                if (pp2==parsepoint) {expect="modval";goto error;}
 
367
                                entry.fromdata.key.button=strtol(parsepoint=pp2, &pp2, 0);
 
368
                                if (pp2==parsepoint) {expect="key-button";goto error;}
 
369
                                entry.fromdata.key.label=strtol(parsepoint=pp2, &pp2, 0);
 
370
                                if (pp2==parsepoint) {expect="key-label";goto error;}
 
371
                                entry.fromdata.key.symbol=strtol(parsepoint=pp2, &pp2, 0);
 
372
                                if (pp2==parsepoint) {expect="key-symbol";goto error;}
 
373
                                break;
 
374
 
 
375
                        case MAP_REL:
 
376
                        case MAP_ABS:
 
377
                                entry.modifier_mask=strtol(parsepoint=pp2, &pp2, 0);
 
378
                                if (pp2==parsepoint) {expect="modmask";goto error;}
 
379
                                entry.modifier_value=strtol(parsepoint=pp2, &pp2, 0);
 
380
                                if (pp2==parsepoint) {expect="modval";goto error;}
 
381
                                entry.fromdata.axis=checkkeyword(parsepoint=pp2,&pp2,axislist,AX_END);
 
382
                                if (pp2==parsepoint) {expect="axis";goto error;}
 
383
                                break;
 
384
                        case MAP_BUTTON:
 
385
                                entry.modifier_mask=strtol(parsepoint=pp2, &pp2, 0);
 
386
                                if (pp2==parsepoint) {expect="modmask";goto error;}
 
387
                                entry.modifier_value=strtol(parsepoint=pp2, &pp2, 0);
 
388
                                if (pp2==parsepoint) {expect="modval";goto error;}
 
389
                                entry.fromdata.button=strtol(parsepoint=pp2, &pp2, 0);
 
390
                                if (pp2==parsepoint) {expect="butnum";goto error;}
 
391
                                break;
 
392
                        default: continue;      /* silently ignore all unparseables */
 
393
                }
 
394
                if (MAP_TO!=checkkeyword(parsepoint=pp2,&pp2,maptypelist,MAP_END)) {
 
395
                        expect="TO";
 
396
                        error:
 
397
                        GIIDPRINT_MISC("filter-mouse Parse error at %d:%s (expecting %s)\n",line,parsepoint,expect);
 
398
                        continue;
 
399
                }
 
400
                switch(entry.to=checkkeyword(parsepoint=pp2,&pp2,maptypelist,MAP_TO)) {
 
401
                        case MAP_KEY:
 
402
                                expect="no KEY output allowed";
 
403
                                goto error;     /* Maybe we should add that for mouse->key ? */
 
404
                        case MAP_REL:
 
405
                        case MAP_ABS:
 
406
                                entry.todata.trans.axis=checkkeyword(parsepoint=pp2,&pp2,axislist,AX_END);
 
407
                                if (pp2==parsepoint) {expect="axis";goto error;}
 
408
                                entry.todata.trans.factor=strtod(parsepoint=pp2, &pp2);
 
409
                                if (pp2==parsepoint) entry.todata.trans.factor=1.0;     /* O.k. - the rest will fail as well. So all defaults. */
 
410
                                entry.todata.trans.treshold=strtod(parsepoint=pp2, &pp2);
 
411
                                if (pp2==parsepoint) entry.todata.trans.treshold=9999.0;
 
412
                                entry.todata.trans.higher=strtod(parsepoint=pp2, &pp2);
 
413
                                if (pp2==parsepoint) entry.todata.trans.higher=entry.todata.trans.factor;
 
414
                                break;
 
415
                        case MAP_BUTTON:
 
416
                                entry.todata.button=strtol(parsepoint=pp2, &pp2, 0);
 
417
                                if (pp2==parsepoint) {expect="button";goto error;}
 
418
                                break;
 
419
                        default: goto error;
 
420
                }
 
421
                *ptr=malloc(sizeof(mapping_entry));
 
422
                if (*ptr) {
 
423
                        memcpy(*ptr,&entry,sizeof(mapping_entry));
 
424
                        ptr=&((*ptr)->next);
 
425
                } else {
 
426
                        fclose(infile);
 
427
                        return GGI_ENOMEM;
 
428
                }
 
429
        }
 
430
        fclose(infile);
 
431
        return 0;
 
432
}
 
433
 
 
434
static int fmouse_loadmap(const char *args,fmouse_priv *priv) {
 
435
 
 
436
        const char *dirname;
 
437
        char fname[2048];
 
438
        char appendstr[] = "/filter/mouse";
 
439
 
 
440
        if (args&&*args) return fmouse_doload(args,priv);
 
441
 
 
442
        dirname = ggGetUserDir();
 
443
        if (strlen(dirname) + sizeof(appendstr) < 2048) {
 
444
                sprintf(fname, "%s%s", dirname, appendstr);
 
445
                if (fmouse_doload(fname,priv)
 
446
                    == 0) {
 
447
                        return 0;
 
448
                }
 
449
        }
 
450
 
 
451
        dirname = giiGetConfDir();
 
452
        if (strlen(dirname) + sizeof(appendstr) < 2048) {
 
453
                sprintf(fname, "%s%s", dirname, appendstr);
 
454
                if (fmouse_doload(fname,priv)
 
455
                    == 0) {
 
456
                        return 0;
 
457
                }
 
458
        }
 
459
        return 1;       /* Failure */
 
460
}
 
461
 
 
462
int GIIdlinit(gii_input *inp, const char *args, void *argptr)
 
463
{
 
464
        fmouse_priv   *priv;
 
465
 
 
466
        GIIDPRINT_MISC("filter-mouse init(%p, \"%s\") called\n", inp,
 
467
                       args ? args : "");
 
468
 
 
469
        priv = malloc(sizeof(fmouse_priv));
 
470
        if (priv == NULL) return GGI_ENOMEM;
 
471
 
 
472
        priv->entry = NULL;
 
473
        priv->modifiers = 0;
 
474
        fmouse_loadmap(args,priv);
 
475
        
 
476
        inp->priv       = priv;
 
477
        inp->GIIhandler = GII_fmouse_handler;
 
478
        inp->GIIclose   = GII_fmouse_close;
 
479
        inp->devinfo    = &xdevinfo;
 
480
        xdevinfo.origin = inp->origin;
 
481
 
 
482
        GIIDPRINT_MISC("filter-mouse fully up\n");
 
483
 
 
484
        return 0;
 
485
}