[client,common] move pen detection to client common
This commit is contained in:
parent
ff2b57c634
commit
93423eaf11
@ -79,7 +79,6 @@ static BOOL register_input_events(xfContext* xfc, Window window)
|
||||
WINPR_ASSERT(settings);
|
||||
|
||||
XIDeviceInfo* info = XIQueryDevice(xfc->display, XIAllDevices, &ndevices);
|
||||
xfc->num_pens = 0;
|
||||
|
||||
for (int i = 0; i < MIN(ndevices, 64); i++)
|
||||
{
|
||||
@ -140,25 +139,24 @@ static BOOL register_input_events(xfContext* xfc, Window window)
|
||||
if (t->number == 2)
|
||||
{
|
||||
double max_pressure = t->max;
|
||||
|
||||
if (strstr(dev->name, "Stylus Pen") || strstr(dev->name, "Pen Pen"))
|
||||
{
|
||||
xfc->pens[xfc->num_pens].deviceid = dev->deviceid;
|
||||
xfc->pens[xfc->num_pens].is_eraser = FALSE;
|
||||
xfc->pens[xfc->num_pens].max_pressure = max_pressure;
|
||||
xfc->pens[xfc->num_pens].hovering = FALSE;
|
||||
xfc->pens[xfc->num_pens].pressed = FALSE;
|
||||
xfc->num_pens++;
|
||||
if (!freerdp_client_handle_pen(
|
||||
&xfc->common, FREERDP_PEN_REGISTER | FREERDP_PEN_HAS_PRESSURE,
|
||||
dev->deviceid, max_pressure))
|
||||
return FALSE;
|
||||
WLog_DBG(TAG, "registered pen");
|
||||
}
|
||||
else if (strstr(dev->name, "Stylus Eraser") ||
|
||||
strstr(dev->name, "Pen Eraser"))
|
||||
{
|
||||
xfc->pens[xfc->num_pens].deviceid = dev->deviceid;
|
||||
xfc->pens[xfc->num_pens].is_eraser = TRUE;
|
||||
xfc->pens[xfc->num_pens].max_pressure = max_pressure;
|
||||
xfc->pens[xfc->num_pens].hovering = FALSE;
|
||||
xfc->pens[xfc->num_pens].pressed = FALSE;
|
||||
xfc->num_pens++;
|
||||
if (!freerdp_client_handle_pen(&xfc->common,
|
||||
FREERDP_PEN_REGISTER |
|
||||
FREERDP_PEN_IS_INVERTED |
|
||||
FREERDP_PEN_HAS_PRESSURE,
|
||||
dev->deviceid, max_pressure))
|
||||
return FALSE;
|
||||
WLog_DBG(TAG, "registered eraser");
|
||||
}
|
||||
}
|
||||
@ -682,7 +680,7 @@ static int xf_input_touch_remote(xfContext* xfc, XIDeviceEvent* event, int evtyp
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int xf_input_pen_remote(xfContext* xfc, XIDeviceEvent* event, int evtype, int pen_index)
|
||||
static int xf_input_pen_remote(xfContext* xfc, XIDeviceEvent* event, int evtype, int deviceid)
|
||||
{
|
||||
int x, y;
|
||||
RdpeiClientContext* rdpei = xfc->common.rdpei;
|
||||
@ -706,73 +704,38 @@ static int xf_input_pen_remote(xfContext* xfc, XIDeviceEvent* event, int evtype,
|
||||
pressure = value;
|
||||
}
|
||||
}
|
||||
WLog_DBG(TAG, "pen pressure %f", pressure);
|
||||
// [MS-RDPEI] 2.2.3.7.1.1: This value MUST be normalized in the range 0x00000000 to 0x00000400
|
||||
// (1024), inclusive
|
||||
pressure = pressure / xfc->pens[pen_index].max_pressure * 1024;
|
||||
|
||||
const UINT32 fieldFlags =
|
||||
RDPINPUT_PEN_CONTACT_PENFLAGS_PRESENT | RDPINPUT_PEN_CONTACT_PRESSURE_PRESENT;
|
||||
const UINT32 penFlags = xfc->pens[pen_index].is_eraser ? RDPINPUT_PEN_FLAG_INVERTED : 0;
|
||||
const UINT32 penPressure = (UINT32)pressure;
|
||||
switch (evtype)
|
||||
{
|
||||
case XI_ButtonPress:
|
||||
WLog_DBG(TAG, "Pen press %d", pen_index);
|
||||
xfc->pens[pen_index].hovering = FALSE;
|
||||
xfc->pens[pen_index].pressed = TRUE;
|
||||
rdpei->PenBegin(rdpei, pen_index, fieldFlags, x, y, penFlags, penPressure);
|
||||
if (!freerdp_client_handle_pen(&xfc->common,
|
||||
FREERDP_PEN_PRESS | FREERDP_PEN_HAS_PRESSURE, deviceid,
|
||||
x, y, pressure))
|
||||
return FALSE;
|
||||
break;
|
||||
case XI_Motion:
|
||||
if (xfc->pens[pen_index].pressed)
|
||||
{
|
||||
WLog_DBG(TAG, "Pen update %d", pen_index);
|
||||
rdpei->PenUpdate(rdpei, pen_index, fieldFlags, x, y, penFlags, penPressure);
|
||||
}
|
||||
else if (xfc->pens[pen_index].hovering)
|
||||
{
|
||||
WLog_DBG(TAG, "Pen hover update %d", pen_index);
|
||||
rdpei->PenHoverUpdate(rdpei, pen_index, RDPINPUT_PEN_CONTACT_PENFLAGS_PRESENT, x, y,
|
||||
penFlags);
|
||||
}
|
||||
else
|
||||
{
|
||||
WLog_DBG(TAG, "Pen hover begin %d", pen_index);
|
||||
xfc->pens[pen_index].hovering = TRUE;
|
||||
rdpei->PenHoverBegin(rdpei, pen_index, RDPINPUT_PEN_CONTACT_PENFLAGS_PRESENT, x, y,
|
||||
penFlags);
|
||||
}
|
||||
if (!freerdp_client_handle_pen(&xfc->common,
|
||||
FREERDP_PEN_MOTION | FREERDP_PEN_HAS_PRESSURE, deviceid,
|
||||
x, y, pressure))
|
||||
return FALSE;
|
||||
break;
|
||||
case XI_ButtonRelease:
|
||||
WLog_DBG(TAG, "Pen release %d", pen_index);
|
||||
xfc->pens[pen_index].pressed = FALSE;
|
||||
xfc->pens[pen_index].hovering = TRUE;
|
||||
rdpei->PenUpdate(rdpei, pen_index, fieldFlags, x, y, penFlags, penPressure);
|
||||
rdpei->PenEnd(rdpei, pen_index, RDPINPUT_PEN_CONTACT_PENFLAGS_PRESENT, x, y, penFlags);
|
||||
if (!freerdp_client_handle_pen(&xfc->common,
|
||||
FREERDP_PEN_RELEASE | FREERDP_PEN_HAS_PRESSURE, deviceid,
|
||||
x, y, pressure))
|
||||
return FALSE;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
xfc->pens[pen_index].last_x = x;
|
||||
xfc->pens[pen_index].last_y = y;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int xf_input_pens_unhover(xfContext* xfc)
|
||||
{
|
||||
RdpeiClientContext* rdpei = xfc->common.rdpei;
|
||||
if (!rdpei)
|
||||
return 0;
|
||||
WINPR_ASSERT(xfc);
|
||||
|
||||
for (int i = 0; i < xfc->num_pens; i++)
|
||||
{
|
||||
if (xfc->pens[i].hovering)
|
||||
{
|
||||
WLog_DBG(TAG, "unhover pen %d", i);
|
||||
xfc->pens[i].hovering = FALSE;
|
||||
rdpei->PenHoverCancel(rdpei, i, 0, xfc->pens[i].last_x, xfc->pens[i].last_y);
|
||||
}
|
||||
}
|
||||
freerdp_client_pen_cancel_all(&xfc->common);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -902,19 +865,12 @@ static int xf_input_handle_event_remote(xfContext* xfc, const XEvent* event)
|
||||
WLog_DBG(TAG, "checking for pen");
|
||||
XIDeviceEvent* deviceEvent = (XIDeviceEvent*)cookie.cc->data;
|
||||
int deviceid = deviceEvent->deviceid;
|
||||
bool used = FALSE;
|
||||
for (int i = 0; i < xfc->num_pens; i++)
|
||||
|
||||
if (freerdp_client_is_pen(&xfc->common, deviceid))
|
||||
{
|
||||
if (xfc->pens[i].deviceid == deviceid)
|
||||
{
|
||||
WLog_DBG(TAG, "pen found, is_eraser=%d", xfc->pens[i].is_eraser);
|
||||
xf_input_pen_remote(xfc, cookie.cc->data, cookie.cc->evtype, i);
|
||||
used = TRUE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (used)
|
||||
xf_input_pen_remote(xfc, cookie.cc->data, cookie.cc->evtype, deviceid);
|
||||
break;
|
||||
}
|
||||
}
|
||||
default:
|
||||
xf_input_pens_unhover(xfc);
|
||||
|
@ -124,7 +124,6 @@ typedef struct
|
||||
|
||||
#if defined(WITH_XI)
|
||||
#define MAX_CONTACTS 20
|
||||
#define MAX_PENS 4
|
||||
|
||||
typedef struct touch_contact
|
||||
{
|
||||
@ -137,17 +136,6 @@ typedef struct touch_contact
|
||||
|
||||
} touchContact;
|
||||
|
||||
typedef struct pen_device
|
||||
{
|
||||
int deviceid;
|
||||
BOOL is_eraser;
|
||||
double max_pressure;
|
||||
int hovering;
|
||||
int pressed;
|
||||
int last_x;
|
||||
int last_y;
|
||||
} penDevice;
|
||||
|
||||
#endif
|
||||
|
||||
struct xf_context
|
||||
@ -303,8 +291,6 @@ struct xf_context
|
||||
double z_vector;
|
||||
double px_vector;
|
||||
double py_vector;
|
||||
penDevice pens[MAX_PENS];
|
||||
int num_pens;
|
||||
#endif
|
||||
BOOL xi_rawevent;
|
||||
BOOL xi_event;
|
||||
|
@ -1664,3 +1664,218 @@ int client_cli_logon_error_info(freerdp* instance, UINT32 data, UINT32 type)
|
||||
WLog_INFO(TAG, "Logon Error Info %s [%s]", str_data, str_type);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static FreeRDP_PenDevice* freerdp_client_get_pen(rdpClientContext* cctx, INT32 deviceid,
|
||||
size_t* pos)
|
||||
{
|
||||
WINPR_ASSERT(cctx);
|
||||
|
||||
for (size_t i = 0; i < ARRAYSIZE(cctx->contacts); i++)
|
||||
{
|
||||
FreeRDP_PenDevice* pen = &cctx->pens[i];
|
||||
if (deviceid == pen->deviceid)
|
||||
{
|
||||
if (pos)
|
||||
*pos = i;
|
||||
return pen;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static BOOL freerdp_client_register_pen(rdpClientContext* cctx, UINT32 flags, INT32 deviceid,
|
||||
double pressure)
|
||||
{
|
||||
WINPR_ASSERT(cctx);
|
||||
WINPR_ASSERT((flags & FREERDP_PEN_REGISTER) != 0);
|
||||
if (freerdp_client_is_pen(cctx, deviceid))
|
||||
{
|
||||
WLog_WARN(TAG, "trying to double register pen device %" PRId32, deviceid);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
size_t pos = 0;
|
||||
FreeRDP_PenDevice* pen = freerdp_client_get_pen(cctx, deviceid, &pos);
|
||||
if (pen)
|
||||
{
|
||||
const FreeRDP_PenDevice empty = { 0 };
|
||||
*pen = empty;
|
||||
|
||||
pen->deviceid = deviceid;
|
||||
pen->max_pressure = pressure;
|
||||
pen->flags = flags;
|
||||
|
||||
WLog_DBG(TAG, "registered pen at index %" PRIuz, pos);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
WLog_WARN(TAG, "No free slots for an additiona pen device, skipping");
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
BOOL freerdp_client_handle_pen(rdpClientContext* cctx, UINT32 flags, INT32 deviceid, ...)
|
||||
{
|
||||
if ((flags & FREERDP_PEN_REGISTER) != 0)
|
||||
{
|
||||
va_list args;
|
||||
|
||||
va_start(args, deviceid);
|
||||
double pressure = va_arg(args, double);
|
||||
va_end(args);
|
||||
return freerdp_client_register_pen(cctx, flags, deviceid, pressure);
|
||||
}
|
||||
size_t pos = 0;
|
||||
FreeRDP_PenDevice* pen = freerdp_client_get_pen(cctx, deviceid, &pos);
|
||||
if (!pen)
|
||||
{
|
||||
WLog_WARN(TAG, "unregistered pen device %" PRId32 " event 0x%08" PRIx32, deviceid, flags);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
UINT32 fieldFlags = RDPINPUT_PEN_CONTACT_PENFLAGS_PRESENT;
|
||||
UINT32 penFlags =
|
||||
((pen->flags & FREERDP_PEN_IS_INVERTED) != 0) ? RDPINPUT_PEN_FLAG_INVERTED : 0;
|
||||
|
||||
RdpeiClientContext* rdpei = cctx->rdpei;
|
||||
WINPR_ASSERT(rdpei);
|
||||
|
||||
UINT32 normalizedpressure = 1024;
|
||||
INT32 x, y;
|
||||
UINT16 rotation;
|
||||
INT16 tiltX, tiltY;
|
||||
va_list args;
|
||||
va_start(args, deviceid);
|
||||
|
||||
x = va_arg(args, INT32);
|
||||
y = va_arg(args, INT32);
|
||||
if ((flags & FREERDP_PEN_HAS_PRESSURE) != 0)
|
||||
{
|
||||
const double pressure = va_arg(args, double);
|
||||
normalizedpressure = (pressure * 1024) / pen->max_pressure;
|
||||
WLog_DBG(TAG, "pen pressure %lf -> %" PRIu32, pressure, normalizedpressure);
|
||||
fieldFlags |= RDPINPUT_PEN_CONTACT_PRESSURE_PRESENT;
|
||||
}
|
||||
if ((flags & FREERDP_PEN_HAS_ROTATION) != 0)
|
||||
{
|
||||
rotation = va_arg(args, unsigned);
|
||||
fieldFlags |= RDPINPUT_PEN_CONTACT_ROTATION_PRESENT;
|
||||
}
|
||||
if ((flags & FREERDP_PEN_HAS_TILTX) != 0)
|
||||
{
|
||||
tiltX = va_arg(args, int);
|
||||
fieldFlags |= RDPINPUT_PEN_CONTACT_TILTX_PRESENT;
|
||||
}
|
||||
if ((flags & FREERDP_PEN_HAS_TILTY) != 0)
|
||||
{
|
||||
tiltX = va_arg(args, int);
|
||||
fieldFlags |= RDPINPUT_PEN_CONTACT_TILTY_PRESENT;
|
||||
}
|
||||
va_end(args);
|
||||
|
||||
if ((flags & FREERDP_PEN_ERASER_PRESSED) != 0)
|
||||
penFlags |= RDPINPUT_PEN_FLAG_ERASER_PRESSED;
|
||||
if ((flags & FREERDP_PEN_BARREL_PRESSED) != 0)
|
||||
penFlags |= RDPINPUT_PEN_FLAG_BARREL_PRESSED;
|
||||
|
||||
pen->last_x = x;
|
||||
pen->last_y = y;
|
||||
if ((flags & FREERDP_PEN_PRESS) != 0)
|
||||
{
|
||||
WLog_DBG(TAG, "Pen press %d", deviceid);
|
||||
pen->hovering = FALSE;
|
||||
pen->pressed = TRUE;
|
||||
|
||||
WINPR_ASSERT(rdpei->PenBegin);
|
||||
const UINT rc = rdpei->PenBegin(rdpei, deviceid, fieldFlags, x, y, penFlags,
|
||||
normalizedpressure, rotation, tiltX, tiltY);
|
||||
return rc == CHANNEL_RC_OK;
|
||||
}
|
||||
else if ((flags & FREERDP_PEN_MOTION) != 0)
|
||||
{
|
||||
UINT rc = ERROR_INTERNAL_ERROR;
|
||||
if (pen->pressed)
|
||||
{
|
||||
WLog_DBG(TAG, "Pen update %" PRId32, deviceid);
|
||||
|
||||
// TODO: what if no rotation is supported but tilt is?
|
||||
WINPR_ASSERT(rdpei->PenUpdate);
|
||||
rc = rdpei->PenUpdate(rdpei, deviceid, fieldFlags, x, y, penFlags, normalizedpressure,
|
||||
rotation, tiltX, tiltY);
|
||||
}
|
||||
else if (pen->hovering)
|
||||
{
|
||||
WLog_DBG(TAG, "Pen hover update %" PRId32, deviceid);
|
||||
|
||||
WINPR_ASSERT(rdpei->PenHoverUpdate);
|
||||
rc = rdpei->PenHoverUpdate(rdpei, deviceid, RDPINPUT_PEN_CONTACT_PENFLAGS_PRESENT, x, y,
|
||||
penFlags, normalizedpressure, rotation, tiltX, tiltY);
|
||||
}
|
||||
else
|
||||
{
|
||||
WLog_DBG(TAG, "Pen hover begin %" PRId32, deviceid);
|
||||
pen->hovering = TRUE;
|
||||
|
||||
WINPR_ASSERT(rdpei->PenHoverBegin);
|
||||
rc = rdpei->PenHoverBegin(rdpei, deviceid, RDPINPUT_PEN_CONTACT_PENFLAGS_PRESENT, x, y,
|
||||
penFlags, normalizedpressure, rotation, tiltX, tiltY);
|
||||
}
|
||||
return rc == CHANNEL_RC_OK;
|
||||
}
|
||||
else if ((flags & FREERDP_PEN_RELEASE) != 0)
|
||||
{
|
||||
WLog_DBG(TAG, "Pen release %" PRId32, deviceid);
|
||||
pen->pressed = FALSE;
|
||||
pen->hovering = TRUE;
|
||||
|
||||
WINPR_ASSERT(rdpei->PenUpdate);
|
||||
const UINT rc = rdpei->PenUpdate(rdpei, deviceid, fieldFlags, x, y, penFlags,
|
||||
normalizedpressure, rotation, tiltX, tiltY);
|
||||
if (rc != CHANNEL_RC_OK)
|
||||
return FALSE;
|
||||
WINPR_ASSERT(rdpei->PenEnd);
|
||||
const UINT re = rdpei->PenEnd(rdpei, deviceid, RDPINPUT_PEN_CONTACT_PENFLAGS_PRESENT, x, y,
|
||||
penFlags, normalizedpressure, rotation, tiltX, tiltY);
|
||||
return re == CHANNEL_RC_OK;
|
||||
}
|
||||
|
||||
WLog_WARN(TAG, "Invalid pen %" PRId32 " flags 0x%08" PRIx32, deviceid, flags);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
BOOL freerdp_client_pen_cancel_all(rdpClientContext* cctx)
|
||||
{
|
||||
WINPR_ASSERT(cctx);
|
||||
|
||||
RdpeiClientContext* rdpei = cctx->rdpei;
|
||||
|
||||
if (!rdpei)
|
||||
return FALSE;
|
||||
|
||||
for (size_t i = 0; i < ARRAYSIZE(cctx->contacts); i++)
|
||||
{
|
||||
FreeRDP_PenDevice* pen = &cctx->pens[i];
|
||||
if (pen->hovering)
|
||||
{
|
||||
WLog_DBG(TAG, "unhover pen %d", i);
|
||||
pen->hovering = FALSE;
|
||||
rdpei->PenHoverCancel(rdpei, i, 0, pen->last_x, pen->last_y);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
BOOL freerdp_client_is_pen(rdpClientContext* cctx, INT32 deviceid)
|
||||
{
|
||||
WINPR_ASSERT(cctx);
|
||||
|
||||
if (deviceid == 0)
|
||||
return FALSE;
|
||||
|
||||
for (size_t x = 0; x < ARRAYSIZE(cctx->pens); x++)
|
||||
{
|
||||
const FreeRDP_PenDevice* pen = &cctx->pens[x];
|
||||
if (pen->deviceid == deviceid)
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
@ -92,6 +92,19 @@ extern "C"
|
||||
ALIGN64 UINT32 pressure;
|
||||
} FreeRDP_TouchContact;
|
||||
|
||||
#define FREERDP_MAX_PEN_DEVICES 10
|
||||
|
||||
typedef struct pen_device
|
||||
{
|
||||
ALIGN64 INT32 deviceid;
|
||||
ALIGN64 UINT32 flags;
|
||||
ALIGN64 double max_pressure;
|
||||
ALIGN64 BOOL hovering;
|
||||
ALIGN64 BOOL pressed;
|
||||
ALIGN64 INT32 last_x;
|
||||
ALIGN64 INT32 last_y;
|
||||
} FreeRDP_PenDevice;
|
||||
|
||||
struct rdp_client_context
|
||||
{
|
||||
rdpContext context;
|
||||
@ -119,7 +132,8 @@ extern "C"
|
||||
UINT64 reserved3[2];
|
||||
#endif
|
||||
ALIGN64 FreeRDP_TouchContact contacts[FREERDP_MAX_TOUCH_CONTACTS]; /**< (offset 8) */
|
||||
UINT64 reserved[128 - 68]; /**< (offset 68) */
|
||||
ALIGN64 FreeRDP_PenDevice pens[FREERDP_MAX_PEN_DEVICES]; /**< (offset 9) */
|
||||
UINT64 reserved[128 - 9]; /**< (offset 9) */
|
||||
};
|
||||
|
||||
/* Common client functions */
|
||||
@ -223,6 +237,27 @@ extern "C"
|
||||
FREERDP_API BOOL freerdp_client_handle_touch(rdpClientContext* cctx, UINT32 flags, INT32 finger,
|
||||
UINT32 pressure, INT32 x, INT32 y);
|
||||
|
||||
typedef enum
|
||||
{
|
||||
FREERDP_PEN_REGISTER = 0x01,
|
||||
FREERDP_PEN_ERASER_PRESSED = 0x02,
|
||||
FREERDP_PEN_PRESS = 0x04,
|
||||
FREERDP_PEN_MOTION = 0x08,
|
||||
FREERDP_PEN_RELEASE = 0x10,
|
||||
FREERDP_PEN_BARREL_PRESSED = 0x20,
|
||||
FREERDP_PEN_HAS_PRESSURE = 0x40,
|
||||
FREERDP_PEN_HAS_ROTATION = 0x40,
|
||||
FREERDP_PEN_HAS_TILTX = 0x80,
|
||||
FREERDP_PEN_HAS_TILTY = 0x100,
|
||||
FREERDP_PEN_IS_INVERTED = 0x200
|
||||
} FreeRDPPenEventType;
|
||||
|
||||
FREERDP_API BOOL freerdp_client_handle_pen(rdpClientContext* cctx, UINT32 flags, INT32 deviceid,
|
||||
...);
|
||||
FREERDP_API BOOL freerdp_client_is_pen(rdpClientContext* cctx, INT32 deviceid);
|
||||
|
||||
FREERDP_API BOOL freerdp_client_pen_cancel_all(rdpClientContext* cctx);
|
||||
|
||||
FREERDP_API BOOL freerdp_client_send_wheel_event(rdpClientContext* cctx, UINT16 mflags);
|
||||
|
||||
FREERDP_API BOOL freerdp_client_send_mouse_event(rdpClientContext* cctx, UINT64 mflags, INT32 x,
|
||||
|
Loading…
x
Reference in New Issue
Block a user