~ubuntu-branches/ubuntu/vivid/freerdp/vivid

« back to all changes in this revision

Viewing changes to client/X11/xf_input.c

  • Committer: Package Import Robot
  • Author(s): Iain Lane
  • Date: 2014-11-11 12:20:50 UTC
  • mfrom: (1.2.5)
  • mto: This revision was merged to the branch mainline in revision 24.
  • Revision ID: package-import@ubuntu.com-20141111122050-7z628f4ab38qxad5
Tags: upstream-1.1.0~git20140921.1.440916e+dfsg1
ImportĀ upstreamĀ versionĀ 1.1.0~git20140921.1.440916e+dfsg1

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/**
 
2
 * FreeRDP: A Remote Desktop Protocol Implementation
 
3
 * X11 Input
 
4
 *
 
5
 * Copyright 2013 Corey Clayton <can.of.tuna@gmail.com>
 
6
 *
 
7
 * Licensed under the Apache License, Version 2.0 (the "License");
 
8
 * you may not use this file except in compliance with the License.
 
9
 * You may obtain a copy of the License at
 
10
 *
 
11
 *     http://www.apache.org/licenses/LICENSE-2.0
 
12
 *
 
13
 * Unless required by applicable law or agreed to in writing, software
 
14
 * distributed under the License is distributed on an "AS IS" BASIS,
 
15
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 
16
 * See the License for the specific language governing permissions and
 
17
 * limitations under the License.
 
18
 */
 
19
 
 
20
#ifdef HAVE_CONFIG_H
 
21
#include "config.h"
 
22
#endif
 
23
 
 
24
#ifdef WITH_XI
 
25
#include <X11/extensions/XInput2.h>
 
26
#endif
 
27
 
 
28
#include <math.h>
 
29
 
 
30
#include "xf_event.h"
 
31
 
 
32
#include "xf_input.h"
 
33
 
 
34
#ifdef WITH_XI
 
35
 
 
36
#define MAX_CONTACTS 2
 
37
 
 
38
typedef struct touch_contact
 
39
{
 
40
        int id;
 
41
        int count;
 
42
        double pos_x;
 
43
        double pos_y;
 
44
        double last_x;
 
45
        double last_y;
 
46
 
 
47
} touchContact;
 
48
 
 
49
touchContact contacts[MAX_CONTACTS];
 
50
 
 
51
int active_contacts;
 
52
XIDeviceEvent lastEvent;
 
53
double firstDist = -1.0;
 
54
double lastDist;
 
55
double z_vector;
 
56
int xinput_opcode;
 
57
int scale_cnt;
 
58
 
 
59
const char* xf_input_get_class_string(int class)
 
60
{
 
61
        if (class == XIKeyClass)
 
62
                return "XIKeyClass";
 
63
        else if (class == XIButtonClass)
 
64
                return "XIButtonClass";
 
65
        else if (class == XIValuatorClass)
 
66
                return "XIValuatorClass";
 
67
        else if (class == XIScrollClass)
 
68
                return "XIScrollClass";
 
69
        else if (class == XITouchClass)
 
70
                return "XITouchClass";
 
71
 
 
72
        return "XIUnknownClass";
 
73
}
 
74
 
 
75
int xf_input_init(xfContext* xfc, Window window)
 
76
{
 
77
        int i, j;
 
78
        int nmasks;
 
79
        int ndevices;
 
80
        int major = 2;
 
81
        int minor = 2;
 
82
        Status xstatus;
 
83
        XIDeviceInfo* info;
 
84
        XIEventMask evmasks[64];
 
85
        int opcode, event, error;
 
86
        BYTE masks[8][XIMaskLen(XI_LASTEVENT)];
 
87
 
 
88
        nmasks = 0;
 
89
        ndevices = 0;
 
90
        active_contacts = 0;
 
91
        ZeroMemory(contacts, sizeof(touchContact) * MAX_CONTACTS);
 
92
 
 
93
        if (!XQueryExtension(xfc->display, "XInputExtension", &opcode, &event, &error))
 
94
        {
 
95
                printf("XInput extension not available.\n");
 
96
                return -1;
 
97
        }
 
98
 
 
99
        xfc->XInputOpcode = opcode;
 
100
 
 
101
        XIQueryVersion(xfc->display, &major, &minor);
 
102
 
 
103
        if (major * 1000 + minor < 2002)
 
104
        {
 
105
                printf("Server does not support XI 2.2\n");
 
106
                return -1;
 
107
        }
 
108
 
 
109
        if (xfc->settings->MultiTouchInput)
 
110
                xfc->use_xinput = TRUE;
 
111
 
 
112
        info = XIQueryDevice(xfc->display, XIAllDevices, &ndevices);
 
113
 
 
114
        for (i = 0; i < ndevices; i++)
 
115
        {
 
116
                BOOL touch = FALSE;
 
117
                XIDeviceInfo* dev = &info[i];
 
118
 
 
119
                for (j = 0; j < dev->num_classes; j++)
 
120
                {
 
121
                        XIAnyClassInfo* class = dev->classes[j];
 
122
                        XITouchClassInfo* t = (XITouchClassInfo*) class;
 
123
 
 
124
                        if ((class->type == XITouchClass) && (t->mode == XIDirectTouch) &&
 
125
                                (strcmp(dev->name, "Virtual core pointer") != 0))
 
126
                        {
 
127
                                touch = TRUE;
 
128
                        }
 
129
                }
 
130
 
 
131
                for (j = 0; j < dev->num_classes; j++)
 
132
                {
 
133
                        XIAnyClassInfo* class = dev->classes[j];
 
134
                        XITouchClassInfo* t = (XITouchClassInfo*) class;
 
135
 
 
136
                        if (xfc->settings->MultiTouchInput)
 
137
                        {
 
138
                                printf("%s (%d) \"%s\" id: %d\n",
 
139
                                                xf_input_get_class_string(class->type),
 
140
                                                class->type, dev->name, dev->deviceid);
 
141
                        }
 
142
 
 
143
                        evmasks[nmasks].mask = masks[nmasks];
 
144
                        evmasks[nmasks].mask_len = sizeof(masks[0]);
 
145
                        ZeroMemory(masks[nmasks], sizeof(masks[0]));
 
146
                        evmasks[nmasks].deviceid = dev->deviceid;
 
147
 
 
148
                        if ((class->type == XITouchClass) && (t->mode == XIDirectTouch) &&
 
149
                                        (strcmp(dev->name, "Virtual core pointer") != 0))
 
150
                        {
 
151
                                if (xfc->settings->MultiTouchInput)
 
152
                                {
 
153
                                        printf("%s %s touch device (id: %d, mode: %d), supporting %d touches.\n",
 
154
                                                dev->name, (t->mode == XIDirectTouch) ? "direct" : "dependent",
 
155
                                                dev->deviceid, t->mode, t->num_touches);
 
156
                                }
 
157
 
 
158
                                XISetMask(masks[nmasks], XI_TouchBegin);
 
159
                                XISetMask(masks[nmasks], XI_TouchUpdate);
 
160
                                XISetMask(masks[nmasks], XI_TouchEnd);
 
161
                                nmasks++;
 
162
                        }
 
163
 
 
164
                        if (xfc->use_xinput)
 
165
                        {
 
166
                                if (!touch && (class->type == XIButtonClass) && strcmp(dev->name, "Virtual core pointer"))
 
167
                                {
 
168
                                        printf("%s button device (id: %d, mode: %d)\n",
 
169
                                                dev->name,
 
170
                                                dev->deviceid, t->mode);
 
171
                                        XISetMask(masks[nmasks], XI_ButtonPress);
 
172
                                        XISetMask(masks[nmasks], XI_ButtonRelease);
 
173
                                        XISetMask(masks[nmasks], XI_Motion);
 
174
                                        nmasks++;
 
175
                                }
 
176
                        }
 
177
                }
 
178
        }
 
179
 
 
180
        if (nmasks > 0)
 
181
                xstatus = XISelectEvents(xfc->display, window, evmasks, nmasks);
 
182
 
 
183
        return 0;
 
184
}
 
185
 
 
186
BOOL xf_input_is_duplicate(XIDeviceEvent* event)
 
187
{
 
188
        if ( (lastEvent.time == event->time) &&
 
189
                        (lastEvent.detail == event->detail) &&
 
190
                        (lastEvent.event_x == event->event_x) &&
 
191
                        (lastEvent.event_y == event->event_y) )
 
192
        {
 
193
                return TRUE;
 
194
        }
 
195
 
 
196
        return FALSE;
 
197
}
 
198
 
 
199
void xf_input_save_last_event(XIDeviceEvent* event)
 
200
{
 
201
        lastEvent.time = event->time;
 
202
        lastEvent.detail = event->detail;
 
203
        lastEvent.event_x = event->event_x;
 
204
        lastEvent.event_y = event->event_y;
 
205
}
 
206
 
 
207
void xf_input_detect_pinch(xfContext* xfc)
 
208
{
 
209
        double dist;
 
210
        double zoom;
 
211
        double delta;
 
212
        ResizeWindowEventArgs e;
 
213
 
 
214
        if (active_contacts != 2)
 
215
        {
 
216
                firstDist = -1.0;
 
217
                return;
 
218
        }
 
219
 
 
220
        /* first calculate the distance */
 
221
        dist = sqrt(pow(contacts[1].pos_x - contacts[0].last_x, 2.0) +
 
222
                        pow(contacts[1].pos_y - contacts[0].last_y, 2.0));
 
223
 
 
224
        /* if this is the first 2pt touch */
 
225
        if (firstDist <= 0)
 
226
        {
 
227
                firstDist = dist;
 
228
                lastDist = firstDist;
 
229
                scale_cnt = 0;
 
230
                z_vector = 0;
 
231
        }
 
232
        else
 
233
        {
 
234
                delta = lastDist - dist;
 
235
 
 
236
                /* compare the current distance to the first one */
 
237
                zoom = (dist / firstDist);
 
238
 
 
239
                z_vector += delta;
 
240
                //printf("d: %.2f\n", delta);
 
241
 
 
242
                lastDist = dist;
 
243
 
 
244
                if (z_vector > 10)
 
245
                {
 
246
                        xfc->scale -= 0.05;
 
247
 
 
248
                        if (xfc->scale < 0.5)
 
249
                                xfc->scale = 0.5;
 
250
 
 
251
                        XResizeWindow(xfc->display, xfc->window->handle, xfc->originalWidth * xfc->scale, xfc->originalHeight * xfc->scale);
 
252
 
 
253
                        EventArgsInit(&e, "xfreerdp");
 
254
                        e.width = (int) xfc->originalWidth * xfc->scale;
 
255
                        e.height = (int) xfc->originalHeight * xfc->scale;
 
256
                        PubSub_OnResizeWindow(((rdpContext*) xfc)->pubSub, xfc, &e);
 
257
 
 
258
                        z_vector = 0;
 
259
                }
 
260
 
 
261
                if (z_vector < -10)
 
262
                {
 
263
                        xfc->scale += 0.05;
 
264
 
 
265
                        if (xfc->scale > 1.5)
 
266
                                xfc->scale = 1.5;
 
267
 
 
268
                        XResizeWindow(xfc->display, xfc->window->handle, xfc->originalWidth * xfc->scale, xfc->originalHeight * xfc->scale);
 
269
 
 
270
                        EventArgsInit(&e, "xfreerdp");
 
271
                        e.width = (int) xfc->originalWidth * xfc->scale;
 
272
                        e.height = (int) xfc->originalHeight * xfc->scale;
 
273
                        PubSub_OnResizeWindow(((rdpContext*) xfc)->pubSub, xfc, &e);
 
274
 
 
275
                        z_vector = 0;
 
276
                }
 
277
        }
 
278
}
 
279
 
 
280
void xf_input_touch_begin(xfContext* xfc, XIDeviceEvent* event)
 
281
{
 
282
        int i;
 
283
 
 
284
        for (i = 0; i < MAX_CONTACTS; i++)
 
285
        {
 
286
                if (contacts[i].id == 0)
 
287
                {
 
288
                        contacts[i].id = event->detail;
 
289
                        contacts[i].count = 1;
 
290
                        contacts[i].pos_x = event->event_x;
 
291
                        contacts[i].pos_y = event->event_y;
 
292
 
 
293
                        active_contacts++;
 
294
                        break;
 
295
                }
 
296
        }
 
297
}
 
298
 
 
299
void xf_input_touch_update(xfContext* xfc, XIDeviceEvent* event)
 
300
{
 
301
        int i;
 
302
 
 
303
        for (i = 0; i < MAX_CONTACTS; i++)
 
304
        {
 
305
                if (contacts[i].id == event->detail)
 
306
                {
 
307
                        contacts[i].count++;
 
308
                        contacts[i].last_x = contacts[i].pos_x;
 
309
                        contacts[i].last_y = contacts[i].pos_y;
 
310
                        contacts[i].pos_x = event->event_x;
 
311
                        contacts[i].pos_y = event->event_y;
 
312
 
 
313
                        xf_input_detect_pinch(xfc);
 
314
 
 
315
                        break;
 
316
                }
 
317
        }
 
318
}
 
319
 
 
320
void xf_input_touch_end(xfContext* xfc, XIDeviceEvent* event)
 
321
{
 
322
        int i;
 
323
 
 
324
        for (i = 0; i < MAX_CONTACTS; i++)
 
325
        {
 
326
                if (contacts[i].id == event->detail)
 
327
                {
 
328
                        contacts[i].id = 0;
 
329
                        contacts[i].count = 0;
 
330
                        //contacts[i].pos_x = (int)event->event_x;
 
331
                        //contacts[i].pos_y = (int)event->event_y;
 
332
 
 
333
                        active_contacts--;
 
334
                        break;printf("TouchBegin\n");
 
335
                }
 
336
        }
 
337
}
 
338
 
 
339
int xf_input_handle_event_local(xfContext* xfc, XEvent* event)
 
340
{
 
341
        XGenericEventCookie* cookie = &event->xcookie;
 
342
 
 
343
        XGetEventData(xfc->display, cookie);
 
344
 
 
345
        if ((cookie->type == GenericEvent) && (cookie->extension == xfc->XInputOpcode))
 
346
        {
 
347
                switch (cookie->evtype)
 
348
                {
 
349
                        case XI_TouchBegin:
 
350
                                if (xf_input_is_duplicate(cookie->data) == FALSE)
 
351
                                        xf_input_touch_begin(xfc, cookie->data);
 
352
                                xf_input_save_last_event(cookie->data);
 
353
                                break;
 
354
 
 
355
                        case XI_TouchUpdate:
 
356
                                if (xf_input_is_duplicate(cookie->data) == FALSE)
 
357
                                        xf_input_touch_update(xfc, cookie->data);
 
358
                                xf_input_save_last_event(cookie->data);
 
359
                                break;
 
360
 
 
361
                        case XI_TouchEnd:
 
362
                                if (xf_input_is_duplicate(cookie->data) == FALSE)
 
363
                                        xf_input_touch_end(xfc, cookie->data);
 
364
                                xf_input_save_last_event(cookie->data);
 
365
                                break;
 
366
 
 
367
                        default:
 
368
                                printf("unhandled xi type= %d\n", cookie->evtype);
 
369
                                break;
 
370
                }
 
371
        }
 
372
 
 
373
        XFreeEventData(xfc->display,cookie);
 
374
 
 
375
        return 0;
 
376
}
 
377
 
 
378
char* xf_input_touch_state_string(DWORD flags)
 
379
{
 
380
        if (flags & CONTACT_FLAG_DOWN)
 
381
                return "TouchBegin";
 
382
        else if (flags & CONTACT_FLAG_UPDATE)
 
383
                return "TouchUpdate";
 
384
        else if (flags & CONTACT_FLAG_UP)
 
385
                return "TouchEnd";
 
386
        else
 
387
                return "TouchUnknown";
 
388
}
 
389
 
 
390
int xf_input_touch_remote(xfContext* xfc, XIDeviceEvent* event, int evtype)
 
391
{
 
392
        int x, y;
 
393
        int touchId;
 
394
        int contactId;
 
395
        RdpeiClientContext* rdpei = xfc->rdpei;
 
396
 
 
397
        if (!rdpei)
 
398
                return 0;
 
399
 
 
400
        touchId = event->detail;
 
401
        x = (int) event->event_x;
 
402
        y = (int) event->event_y;
 
403
 
 
404
        if (evtype == XI_TouchBegin)
 
405
        {
 
406
                //printf("TouchBegin: %d\n", touchId);
 
407
                contactId = rdpei->TouchBegin(rdpei, touchId, x, y);
 
408
        }
 
409
        else if (evtype == XI_TouchUpdate)
 
410
        {
 
411
                //printf("TouchUpdate: %d\n", touchId);
 
412
                contactId = rdpei->TouchUpdate(rdpei, touchId, x, y);
 
413
        }
 
414
        else if (evtype == XI_TouchEnd)
 
415
        {
 
416
                //printf("TouchEnd: %d\n", touchId);
 
417
                contactId = rdpei->TouchEnd(rdpei, touchId, x, y);
 
418
        }
 
419
 
 
420
        return 0;
 
421
}
 
422
 
 
423
int xf_input_event(xfContext* xfc, XIDeviceEvent* event, int evtype)
 
424
{
 
425
 
 
426
        switch (evtype)
 
427
        {
 
428
                case XI_ButtonPress:
 
429
                        //printf("ButtonPress\n");
 
430
                        xf_generic_ButtonPress(xfc, (int) event->event_x, (int) event->event_y,
 
431
                                        event->detail, event->event, xfc->remote_app);
 
432
                        break;
 
433
 
 
434
                case XI_ButtonRelease:
 
435
                        //printf("ButtonRelease\n");
 
436
                        xf_generic_ButtonRelease(xfc, (int) event->event_x, (int) event->event_y,
 
437
                                        event->detail, event->event, xfc->remote_app);
 
438
                        break;
 
439
 
 
440
                case XI_Motion:
 
441
                        //printf("Motion\n");
 
442
                        xf_generic_MotionNotify(xfc, (int) event->event_x, (int) event->event_y,
 
443
                                        event->detail, event->event, xfc->remote_app);
 
444
                        break;
 
445
        }
 
446
 
 
447
        return 0;
 
448
}
 
449
 
 
450
int xf_input_handle_event_remote(xfContext* xfc, XEvent* event)
 
451
{
 
452
        XGenericEventCookie* cookie = &event->xcookie;
 
453
 
 
454
        XGetEventData(xfc->display, cookie);
 
455
 
 
456
        if ((cookie->type == GenericEvent) && (cookie->extension == xfc->XInputOpcode))
 
457
        {
 
458
                switch (cookie->evtype)
 
459
                {
 
460
                        case XI_TouchBegin:
 
461
                                xf_input_touch_remote(xfc, cookie->data, XI_TouchBegin);
 
462
                                break;
 
463
 
 
464
                        case XI_TouchUpdate:
 
465
                                xf_input_touch_remote(xfc, cookie->data, XI_TouchUpdate);
 
466
                                break;
 
467
 
 
468
                        case XI_TouchEnd:
 
469
                                xf_input_touch_remote(xfc, cookie->data, XI_TouchEnd);
 
470
                                break;
 
471
 
 
472
                        default:
 
473
                                xf_input_event(xfc, cookie->data, cookie->evtype);
 
474
                                break;
 
475
                }
 
476
        }
 
477
 
 
478
        XFreeEventData(xfc->display,cookie);
 
479
 
 
480
        return 0;
 
481
}
 
482
 
 
483
#else
 
484
 
 
485
int xf_input_init(xfContext* xfc, Window window)
 
486
{
 
487
        return 0;
 
488
}
 
489
 
 
490
#endif
 
491
 
 
492
void xf_process_rdpei_event(xfContext* xfc, wMessage* event)
 
493
{
 
494
        switch (GetMessageType(event->id))
 
495
        {
 
496
                case RdpeiChannel_ServerReady:
 
497
                        break;
 
498
 
 
499
                case RdpeiChannel_SuspendTouch:
 
500
                        break;
 
501
 
 
502
                case RdpeiChannel_ResumeTouch:
 
503
                        break;
 
504
        }
 
505
}
 
506
 
 
507
int xf_input_handle_event(xfContext* xfc, XEvent* event)
 
508
{
 
509
#ifdef WITH_XI
 
510
        if (xfc->settings->MultiTouchInput)
 
511
        {
 
512
                return xf_input_handle_event_remote(xfc, event);
 
513
        }
 
514
 
 
515
        if (xfc->enableScaling)
 
516
                return xf_input_handle_event_local(xfc, event);
 
517
#endif
 
518
 
 
519
        return 0;
 
520
}