mirror of
https://github.com/morgan9e/FreeRDP
synced 2026-04-15 00:44:19 +09:00
xfreerdp: initial multitouch functionality
This commit is contained in:
@@ -36,6 +36,26 @@
|
||||
|
||||
#include "rdpei_main.h"
|
||||
|
||||
/**
|
||||
* Touch Input
|
||||
* http://msdn.microsoft.com/en-us/library/windows/desktop/dd562197/
|
||||
*
|
||||
* Windows Touch Input
|
||||
* http://msdn.microsoft.com/en-us/library/windows/desktop/dd317321/
|
||||
*
|
||||
* Input: Touch injection sample
|
||||
* http://code.msdn.microsoft.com/windowsdesktop/Touch-Injection-Sample-444d9bf7
|
||||
*
|
||||
* Pointer Input Message Reference
|
||||
* http://msdn.microsoft.com/en-us/library/hh454916/
|
||||
*
|
||||
* POINTER_INFO Structure
|
||||
* http://msdn.microsoft.com/en-us/library/hh454907/
|
||||
*
|
||||
* POINTER_TOUCH_INFO Structure
|
||||
* http://msdn.microsoft.com/en-us/library/hh454910/
|
||||
*/
|
||||
|
||||
#define MAX_CONTACTS 512
|
||||
|
||||
struct _RDPEI_CHANNEL_CALLBACK
|
||||
@@ -66,11 +86,12 @@ struct _RDPEI_PLUGIN
|
||||
RDPEI_LISTENER_CALLBACK* listener_callback;
|
||||
|
||||
int version;
|
||||
int touchIdOffset;
|
||||
UINT16 maxTouchContacts;
|
||||
UINT64 currentFrameTime;
|
||||
UINT64 previousFrameTime;
|
||||
RDPINPUT_TOUCH_FRAME frame;
|
||||
RDPINPUT_CONTACT_DATA contacts[MAX_CONTACTS];
|
||||
RDPINPUT_CONTACT_POINT* contactPoints;
|
||||
};
|
||||
typedef struct _RDPEI_PLUGIN RDPEI_PLUGIN;
|
||||
|
||||
@@ -108,21 +129,19 @@ int rdpei_send_cs_ready_pdu(RDPEI_CHANNEL_CALLBACK* callback)
|
||||
wStream* s;
|
||||
UINT32 flags;
|
||||
UINT32 pduLength;
|
||||
UINT16 maxTouchContacts;
|
||||
RDPEI_PLUGIN* rdpei = (RDPEI_PLUGIN*) callback->plugin;
|
||||
|
||||
flags = 0;
|
||||
flags |= READY_FLAGS_SHOW_TOUCH_VISUALS;
|
||||
//flags |= READY_FLAGS_DISABLE_TIMESTAMP_INJECTION;
|
||||
|
||||
maxTouchContacts = 10;
|
||||
|
||||
pduLength = RDPINPUT_HEADER_LENGTH + 10;
|
||||
s = Stream_New(NULL, pduLength);
|
||||
Stream_Seek(s, RDPINPUT_HEADER_LENGTH);
|
||||
|
||||
Stream_Write_UINT32(s, flags); /* flags (4 bytes) */
|
||||
Stream_Write_UINT32(s, RDPINPUT_PROTOCOL_V1); /* protocolVersion (4 bytes) */
|
||||
Stream_Write_UINT16(s, maxTouchContacts); /* maxTouchContacts (2 bytes) */
|
||||
Stream_Write_UINT16(s, rdpei->maxTouchContacts); /* maxTouchContacts (2 bytes) */
|
||||
|
||||
Stream_SealLength(s);
|
||||
|
||||
@@ -132,6 +151,22 @@ int rdpei_send_cs_ready_pdu(RDPEI_CHANNEL_CALLBACK* callback)
|
||||
return status;
|
||||
}
|
||||
|
||||
void rdpei_print_contact_flags(UINT32 contactFlags)
|
||||
{
|
||||
if (contactFlags & CONTACT_FLAG_DOWN)
|
||||
printf(" CONTACT_FLAG_DOWN");
|
||||
if (contactFlags & CONTACT_FLAG_UPDATE)
|
||||
printf(" CONTACT_FLAG_UPDATE");
|
||||
if (contactFlags & CONTACT_FLAG_UP)
|
||||
printf(" CONTACT_FLAG_UP");
|
||||
if (contactFlags & CONTACT_FLAG_INRANGE)
|
||||
printf(" CONTACT_FLAG_INRANGE");
|
||||
if (contactFlags & CONTACT_FLAG_INCONTACT)
|
||||
printf(" CONTACT_FLAG_INCONTACT");
|
||||
if (contactFlags & CONTACT_FLAG_CANCELED)
|
||||
printf(" CONTACT_FLAG_CANCELED");
|
||||
}
|
||||
|
||||
int rdpei_write_touch_frame(wStream* s, RDPINPUT_TOUCH_FRAME* frame)
|
||||
{
|
||||
int index;
|
||||
@@ -153,7 +188,9 @@ int rdpei_write_touch_frame(wStream* s, RDPINPUT_TOUCH_FRAME* frame)
|
||||
printf("contact[%d].fieldsPresent: %d\n", index, contact->fieldsPresent);
|
||||
printf("contact[%d].x: %d\n", index, contact->x);
|
||||
printf("contact[%d].y: %d\n", index, contact->y);
|
||||
printf("contact[%d].contactFlags: 0x%04X\n", index, contact->contactFlags);
|
||||
printf("contact[%d].contactFlags: 0x%04X", index, contact->contactFlags);
|
||||
rdpei_print_contact_flags(contact->contactFlags);
|
||||
printf("\n");
|
||||
|
||||
Stream_Write_UINT8(s, contact->contactId); /* contactId (1 byte) */
|
||||
|
||||
@@ -408,27 +445,10 @@ int rdpei_end_frame(RdpeiClientContext* context)
|
||||
|
||||
int rdpei_add_contact(RdpeiClientContext* context, RDPINPUT_CONTACT_DATA* contact)
|
||||
{
|
||||
RDPINPUT_CONTACT_DATA* previousContact;
|
||||
RDPEI_PLUGIN* rdpei = (RDPEI_PLUGIN*) context->handle;
|
||||
|
||||
if (rdpei->frame.contactCount < MAX_CONTACTS)
|
||||
{
|
||||
if (rdpei->frame.contactCount > 0)
|
||||
{
|
||||
previousContact = &(rdpei->contacts[rdpei->frame.contactCount - 1]);
|
||||
|
||||
if ((previousContact->x == contact->x) || (previousContact->y == contact->y) ||
|
||||
(previousContact->contactId == contact->contactId))
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (rdpei->touchIdOffset < 0)
|
||||
rdpei->touchIdOffset = contact->contactId;
|
||||
|
||||
contact->contactId -= rdpei->touchIdOffset;
|
||||
|
||||
CopyMemory(&(rdpei->contacts[rdpei->frame.contactCount]), contact, sizeof(RDPINPUT_CONTACT_DATA));
|
||||
rdpei->frame.contactCount++;
|
||||
}
|
||||
@@ -436,6 +456,104 @@ int rdpei_add_contact(RdpeiClientContext* context, RDPINPUT_CONTACT_DATA* contac
|
||||
return 1;
|
||||
}
|
||||
|
||||
int rdpei_contact_begin(RdpeiClientContext* context, int externalId, int x, int y)
|
||||
{
|
||||
int i, j;
|
||||
int contactId = -1;
|
||||
RDPEI_PLUGIN* rdpei = (RDPEI_PLUGIN*) context->handle;
|
||||
|
||||
/* Create a new contact point in an empty slot */
|
||||
|
||||
for (i = 0; i < rdpei->maxTouchContacts; i++)
|
||||
{
|
||||
if (!rdpei->contactPoints[i].flags)
|
||||
{
|
||||
rdpei->contactPoints[i].flags = 1;
|
||||
rdpei->contactPoints[i].contactId = i;
|
||||
rdpei->contactPoints[i].touchDownX = x;
|
||||
rdpei->contactPoints[i].touchDownX = y;
|
||||
|
||||
for (j = 0; j < MAX_EXTERNAL_IDS; j++)
|
||||
{
|
||||
if (!rdpei->contactPoints[i].externalIds[j])
|
||||
{
|
||||
rdpei->contactPoints[i].externalIds[j] = externalId;
|
||||
rdpei->contactPoints[i].externalIdCount++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
contactId = rdpei->contactPoints[i].contactId;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return contactId;
|
||||
}
|
||||
|
||||
int rdpei_contact_update(RdpeiClientContext* context, int externalId)
|
||||
{
|
||||
int i, j;
|
||||
int contactId = -1;
|
||||
RDPEI_PLUGIN* rdpei = (RDPEI_PLUGIN*) context->handle;
|
||||
|
||||
for (i = 0; i < rdpei->maxTouchContacts; i++)
|
||||
{
|
||||
if (!rdpei->contactPoints[i].flags)
|
||||
continue;
|
||||
|
||||
for (j = 0; j < MAX_EXTERNAL_IDS; j++)
|
||||
{
|
||||
if (rdpei->contactPoints[i].externalIds[j] == externalId)
|
||||
{
|
||||
contactId = rdpei->contactPoints[i].contactId;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (contactId != -1)
|
||||
break;
|
||||
}
|
||||
|
||||
return contactId;
|
||||
}
|
||||
|
||||
int rdpei_contact_end(RdpeiClientContext* context, int externalId)
|
||||
{
|
||||
int i, j;
|
||||
int contactId = -1;
|
||||
RDPEI_PLUGIN* rdpei = (RDPEI_PLUGIN*) context->handle;
|
||||
|
||||
for (i = 0; i < rdpei->maxTouchContacts; i++)
|
||||
{
|
||||
if (!rdpei->contactPoints[i].flags)
|
||||
continue;
|
||||
|
||||
for (j = 0; j < MAX_EXTERNAL_IDS; j++)
|
||||
{
|
||||
if (rdpei->contactPoints[i].externalIds[j] == externalId)
|
||||
{
|
||||
contactId = rdpei->contactPoints[i].contactId;
|
||||
rdpei->contactPoints[i].externalIds[j] = 0;
|
||||
rdpei->contactPoints[i].externalIdCount--;
|
||||
|
||||
if (rdpei->contactPoints[i].externalIdCount < 1)
|
||||
{
|
||||
rdpei->contactPoints[i].flags = 0;
|
||||
rdpei->contactPoints[i].contactId = 0;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (contactId != -1)
|
||||
break;
|
||||
}
|
||||
|
||||
return contactId;
|
||||
}
|
||||
|
||||
#ifdef STATIC_CHANNELS
|
||||
#define DVCPluginEntry rdpei_DVCPluginEntry
|
||||
#endif
|
||||
@@ -450,6 +568,8 @@ int DVCPluginEntry(IDRDYNVC_ENTRY_POINTS* pEntryPoints)
|
||||
|
||||
if (rdpei == NULL)
|
||||
{
|
||||
size_t size;
|
||||
|
||||
rdpei = (RDPEI_PLUGIN*) malloc(sizeof(RDPEI_PLUGIN));
|
||||
ZeroMemory(rdpei, sizeof(RDPEI_PLUGIN));
|
||||
|
||||
@@ -459,11 +579,15 @@ int DVCPluginEntry(IDRDYNVC_ENTRY_POINTS* pEntryPoints)
|
||||
rdpei->iface.Terminated = rdpei_plugin_terminated;
|
||||
|
||||
rdpei->version = 1;
|
||||
rdpei->touchIdOffset = -1;
|
||||
rdpei->currentFrameTime = 0;
|
||||
rdpei->previousFrameTime = 0;
|
||||
rdpei->frame.contacts = (RDPINPUT_CONTACT_DATA*) rdpei->contacts;
|
||||
|
||||
rdpei->maxTouchContacts = 10;
|
||||
size = rdpei->maxTouchContacts * sizeof(RDPINPUT_CONTACT_POINT);
|
||||
rdpei->contactPoints = (RDPINPUT_CONTACT_POINT*) malloc(size);
|
||||
ZeroMemory(rdpei->contactPoints, size);
|
||||
|
||||
context = (RdpeiClientContext*) malloc(sizeof(RdpeiClientContext));
|
||||
|
||||
context->handle = (void*) rdpei;
|
||||
@@ -472,6 +596,10 @@ int DVCPluginEntry(IDRDYNVC_ENTRY_POINTS* pEntryPoints)
|
||||
context->EndFrame = rdpei_end_frame;
|
||||
context->AddContact = rdpei_add_contact;
|
||||
|
||||
context->ContactBegin = rdpei_contact_begin;
|
||||
context->ContactUpdate = rdpei_contact_update;
|
||||
context->ContactEnd = rdpei_contact_end;
|
||||
|
||||
rdpei->iface.pInterface = (void*) context;
|
||||
|
||||
error = pEntryPoints->RegisterPlugin(pEntryPoints, "rdpei", (IWTSPlugin*) rdpei);
|
||||
|
||||
@@ -51,6 +51,19 @@
|
||||
#define EVENTID_RESUME_TOUCH 0x0005
|
||||
#define EVENTID_DISMISS_HOVERING_CONTACT 0x0006
|
||||
|
||||
#define MAX_EXTERNAL_IDS 32
|
||||
|
||||
struct _RDPINPUT_CONTACT_POINT
|
||||
{
|
||||
UINT32 flags;
|
||||
UINT32 contactId;
|
||||
int touchDownX;
|
||||
int touchDownY;
|
||||
int externalIdCount;
|
||||
int externalIds[MAX_EXTERNAL_IDS];
|
||||
};
|
||||
typedef struct _RDPINPUT_CONTACT_POINT RDPINPUT_CONTACT_POINT;
|
||||
|
||||
#ifdef WITH_DEBUG_DVC
|
||||
#define DEBUG_DVC(fmt, ...) DEBUG_CLASS(DVC, fmt, ## __VA_ARGS__)
|
||||
#else
|
||||
|
||||
@@ -136,6 +136,9 @@ static BOOL xf_event_MotionNotify(xfInfo* xfi, XEvent* event, BOOL app)
|
||||
int x, y;
|
||||
Window childWindow;
|
||||
|
||||
if (xfi->settings->MultiTouchInput)
|
||||
return TRUE;
|
||||
|
||||
input = xfi->instance->input;
|
||||
x = event->xmotion.x;
|
||||
y = event->xmotion.y;
|
||||
@@ -186,6 +189,9 @@ static BOOL xf_event_ButtonPress(xfInfo* xfi, XEvent* event, BOOL app)
|
||||
BOOL extended;
|
||||
rdpInput* input;
|
||||
|
||||
if (xfi->settings->MultiTouchInput)
|
||||
return TRUE;
|
||||
|
||||
input = xfi->instance->input;
|
||||
|
||||
x = 0;
|
||||
@@ -295,6 +301,9 @@ static BOOL xf_event_ButtonRelease(xfInfo* xfi, XEvent* event, BOOL app)
|
||||
BOOL extended;
|
||||
rdpInput* input;
|
||||
|
||||
if (xfi->settings->MultiTouchInput)
|
||||
return TRUE;
|
||||
|
||||
input = xfi->instance->input;
|
||||
|
||||
x = 0;
|
||||
|
||||
@@ -57,15 +57,17 @@ int scale_cnt;
|
||||
int xf_input_init(xfInfo* xfi, Window window)
|
||||
{
|
||||
int i, j;
|
||||
int nmasks;
|
||||
int ndevices;
|
||||
int major = 2;
|
||||
int minor = 2;
|
||||
Status xstatus;
|
||||
XIEventMask evmask;
|
||||
XIDeviceInfo* info;
|
||||
XIEventMask evmasks[8];
|
||||
int opcode, event, error;
|
||||
unsigned char mask[XIMaskLen(XI_LASTEVENT)];
|
||||
BYTE masks[8][XIMaskLen(XI_LASTEVENT)];
|
||||
|
||||
nmasks = 0;
|
||||
active_contacts = 0;
|
||||
ZeroMemory(contacts, sizeof(touchContact) * MAX_CONTACTS);
|
||||
|
||||
@@ -99,21 +101,29 @@ int xf_input_init(xfInfo* xfi, Window window)
|
||||
if (class->type != XITouchClass)
|
||||
continue;
|
||||
|
||||
printf("%s %s touch device, supporting %d touches.\n",
|
||||
dev->name, (t->mode == XIDirectTouch) ? "direct" : "dependent", t->num_touches);
|
||||
if (t->mode != XIDirectTouch)
|
||||
continue;
|
||||
|
||||
if (strcmp(dev->name, "Virtual core pointer") == 0)
|
||||
continue;
|
||||
|
||||
printf("%s %s touch device (id: %d, mode: %d), supporting %d touches.\n",
|
||||
dev->name, (t->mode == XIDirectTouch) ? "direct" : "dependent",
|
||||
dev->deviceid, t->mode, t->num_touches);
|
||||
|
||||
evmasks[nmasks].mask = masks[nmasks];
|
||||
evmasks[nmasks].mask_len = sizeof(masks[0]);
|
||||
ZeroMemory(masks[nmasks], sizeof(masks[0]));
|
||||
evmasks[nmasks].deviceid = dev->deviceid;
|
||||
|
||||
XISetMask(masks[nmasks], XI_TouchBegin);
|
||||
XISetMask(masks[nmasks], XI_TouchUpdate);
|
||||
XISetMask(masks[nmasks], XI_TouchEnd);
|
||||
nmasks++;
|
||||
}
|
||||
}
|
||||
|
||||
evmask.mask = mask;
|
||||
evmask.mask_len = sizeof(mask);
|
||||
ZeroMemory(mask, sizeof(mask));
|
||||
evmask.deviceid = XIAllDevices;
|
||||
|
||||
XISetMask(mask, XI_TouchBegin);
|
||||
XISetMask(mask, XI_TouchUpdate);
|
||||
XISetMask(mask, XI_TouchEnd);
|
||||
|
||||
xstatus = XISelectEvents(xfi->display, window, &evmask, 1);
|
||||
xstatus = XISelectEvents(xfi->display, window, evmasks, nmasks);
|
||||
|
||||
return -1;
|
||||
}
|
||||
@@ -331,7 +341,6 @@ int xf_input_touch_remote(xfInfo* xfi, XIDeviceEvent* event, DWORD flags)
|
||||
//if ((x < 0) || (y < 0))
|
||||
// return 0;
|
||||
|
||||
contact.contactId = touchId;
|
||||
contact.fieldsPresent = 0;
|
||||
contact.x = x;
|
||||
contact.y = y;
|
||||
@@ -339,20 +348,22 @@ int xf_input_touch_remote(xfInfo* xfi, XIDeviceEvent* event, DWORD flags)
|
||||
|
||||
if (flags & CONTACT_FLAG_DOWN)
|
||||
{
|
||||
contact.contactId = rdpei->ContactBegin(rdpei, touchId, x, y);
|
||||
contact.contactFlags |= CONTACT_FLAG_INRANGE;
|
||||
contact.contactFlags |= CONTACT_FLAG_INCONTACT;
|
||||
}
|
||||
else if (flags & CONTACT_FLAG_UPDATE)
|
||||
{
|
||||
contact.contactId = rdpei->ContactUpdate(rdpei, touchId);
|
||||
contact.contactFlags |= CONTACT_FLAG_INRANGE;
|
||||
contact.contactFlags |= CONTACT_FLAG_INCONTACT;
|
||||
}
|
||||
else if (flags & CONTACT_FLAG_UP)
|
||||
{
|
||||
//contact.contactFlags |= CONTACT_FLAG_INRANGE;
|
||||
contact.contactId = rdpei->ContactEnd(rdpei, touchId);
|
||||
}
|
||||
|
||||
//rdpei->BeginFrame(rdpei);
|
||||
rdpei->BeginFrame(rdpei);
|
||||
rdpei->AddContact(rdpei, &contact);
|
||||
rdpei->EndFrame(rdpei);
|
||||
|
||||
|
||||
@@ -68,6 +68,10 @@ typedef int (*pcRdpeiBeginFrame)(RdpeiClientContext* context);
|
||||
typedef int (*pcRdpeiEndFrame)(RdpeiClientContext* context);
|
||||
typedef int (*pcRdpeiAddContact)(RdpeiClientContext* context, RDPINPUT_CONTACT_DATA* contact);
|
||||
|
||||
typedef int (*pcRdpeiContactBegin)(RdpeiClientContext* context, int externalId, int x, int y);
|
||||
typedef int (*pcRdpeiContactUpdate)(RdpeiClientContext* context, int externalId);
|
||||
typedef int (*pcRdpeiContactEnd)(RdpeiClientContext* context, int externalId);
|
||||
|
||||
struct _rdpei_client_context
|
||||
{
|
||||
void* handle;
|
||||
@@ -77,6 +81,10 @@ struct _rdpei_client_context
|
||||
pcRdpeiBeginFrame BeginFrame;
|
||||
pcRdpeiEndFrame EndFrame;
|
||||
pcRdpeiAddContact AddContact;
|
||||
|
||||
pcRdpeiContactBegin ContactBegin;
|
||||
pcRdpeiContactUpdate ContactUpdate;
|
||||
pcRdpeiContactEnd ContactEnd;
|
||||
};
|
||||
|
||||
#endif /* FREERDP_CHANNEL_CLIENT_RDPEI_H */
|
||||
|
||||
Reference in New Issue
Block a user