shadow: add improved pointer updates

This commit is contained in:
Marc-André Moreau 2014-11-06 17:25:41 -05:00
parent 92d08cf58f
commit a538e791b3
4 changed files with 253 additions and 10 deletions

View File

@ -1506,9 +1506,25 @@ static void update_send_pointer_system(rdpContext* context, POINTER_SYSTEM_UPDAT
Stream_Release(s);
}
static void update_send_pointer_position(rdpContext* context, POINTER_POSITION_UPDATE* pointerPosition)
{
wStream* s;
rdpRdp* rdp = context->rdp;
s = fastpath_update_pdu_init(rdp->fastpath);
Stream_EnsureRemainingCapacity(s, 16);
Stream_Write_UINT16(s, pointerPosition->xPos); /* xPos (2 bytes) */
Stream_Write_UINT16(s, pointerPosition->yPos); /* yPos (2 bytes) */
fastpath_send_update_pdu(rdp->fastpath, FASTPATH_UPDATETYPE_PTR_POSITION, s);
Stream_Release(s);
}
static void update_write_pointer_color(wStream* s, POINTER_COLOR_UPDATE* pointer_color)
{
Stream_EnsureRemainingCapacity(s, 15 + (int) pointer_color->lengthAndMask + (int) pointer_color->lengthXorMask);
Stream_EnsureRemainingCapacity(s, 32 + (int) pointer_color->lengthAndMask + (int) pointer_color->lengthXorMask);
Stream_Write_UINT16(s, pointer_color->cacheIndex);
Stream_Write_UINT16(s, pointer_color->xPos);
@ -1544,8 +1560,12 @@ static void update_send_pointer_new(rdpContext* context, POINTER_NEW_UPDATE* poi
rdpRdp* rdp = context->rdp;
s = fastpath_update_pdu_init(rdp->fastpath);
Stream_EnsureRemainingCapacity(s, 16);
Stream_Write_UINT16(s, pointer_new->xorBpp); /* xorBpp (2 bytes) */
update_write_pointer_color(s, &pointer_new->colorPtrAttr);
fastpath_send_update_pdu(rdp->fastpath, FASTPATH_UPDATETYPE_POINTER, s);
Stream_Release(s);
}
@ -1614,14 +1634,14 @@ BOOL update_read_suppress_output(rdpUpdate* update, wStream* s)
static void update_send_set_keyboard_indicators(rdpContext* context, UINT16 led_flags)
{
wStream* s;
rdpRdp* rdp = context->rdp;
wStream* s;
rdpRdp* rdp = context->rdp;
s = rdp_data_pdu_init(rdp);
Stream_Write_UINT16(s, 0); /* unitId should be 0 according to MS-RDPBCGR 2.2.8.2.1.1 */
Stream_Write_UINT16(s, led_flags); /* ledFlags (2 bytes) */
rdp_send_data_pdu(rdp, s, DATA_PDU_TYPE_SET_KEYBOARD_INDICATORS, rdp->mcs->userId);
Stream_Release(s);
s = rdp_data_pdu_init(rdp);
Stream_Write_UINT16(s, 0); /* unitId should be 0 according to MS-RDPBCGR 2.2.8.2.1.1 */
Stream_Write_UINT16(s, led_flags); /* ledFlags (2 bytes) */
rdp_send_data_pdu(rdp, s, DATA_PDU_TYPE_SET_KEYBOARD_INDICATORS, rdp->mcs->userId);
Stream_Release(s);
}
void update_register_server_callbacks(rdpUpdate* update)
@ -1655,6 +1675,7 @@ void update_register_server_callbacks(rdpUpdate* update)
update->altsec->CreateOffscreenBitmap = update_send_create_offscreen_bitmap_order;
update->altsec->SwitchSurface = update_send_switch_surface_order;
update->pointer->PointerSystem = update_send_pointer_system;
update->pointer->PointerPosition = update_send_pointer_position;
update->pointer->PointerColor = update_send_pointer_color;
update->pointer->PointerNew = update_send_pointer_new;
update->pointer->PointerCached = update_send_pointer_cached;

View File

@ -341,6 +341,55 @@ void x11_shadow_input_extended_mouse_event(x11ShadowSubsystem* subsystem, UINT16
#endif
}
int x11_shadow_pointer_position_update(x11ShadowSubsystem* subsystem)
{
SHADOW_MSG_OUT_POINTER_POSITION_UPDATE* msg;
UINT32 msgId = SHADOW_MSG_OUT_POINTER_POSITION_UPDATE_ID;
wMessagePipe* MsgPipe = subsystem->MsgPipe;
msg = (SHADOW_MSG_OUT_POINTER_POSITION_UPDATE*) calloc(1, sizeof(SHADOW_MSG_OUT_POINTER_POSITION_UPDATE));
if (!msg)
return -1;
msg->xPos = subsystem->cursorX;
msg->yPos = subsystem->cursorY;
MessageQueue_Post(MsgPipe->Out, NULL, msgId, (void*) msg, NULL);
return 1;
}
int x11_shadow_pointer_alpha_update(x11ShadowSubsystem* subsystem)
{
SHADOW_MSG_OUT_POINTER_ALPHA_UPDATE* msg;
UINT32 msgId = SHADOW_MSG_OUT_POINTER_ALPHA_UPDATE_ID;
wMessagePipe* MsgPipe = subsystem->MsgPipe;
msg = (SHADOW_MSG_OUT_POINTER_ALPHA_UPDATE*) calloc(1, sizeof(SHADOW_MSG_OUT_POINTER_ALPHA_UPDATE));
if (!msg)
return -1;
msg->xHot = subsystem->cursorHotX;
msg->yHot = subsystem->cursorHotY;
msg->width = subsystem->cursorWidth;
msg->height = subsystem->cursorHeight;
msg->scanline = msg->width * 4;
msg->pixels = (BYTE*) malloc(msg->scanline * msg->height);
if (!msg->pixels)
return -1;
CopyMemory(msg->pixels, subsystem->cursorPixels, msg->scanline * msg->height);
msg->premultiplied = TRUE;
MessageQueue_Post(MsgPipe->Out, NULL, msgId, (void*) msg, NULL);
return 1;
}
int x11_shadow_query_cursor(x11ShadowSubsystem* subsystem, BOOL getImage)
{
int x, y, n, k;
@ -385,6 +434,8 @@ int x11_shadow_query_cursor(x11ShadowSubsystem* subsystem, BOOL getImage)
}
XFree(ci);
x11_shadow_pointer_alpha_update(subsystem);
#endif
}
else
@ -407,6 +458,8 @@ int x11_shadow_query_cursor(x11ShadowSubsystem* subsystem, BOOL getImage)
subsystem->cursorX = x;
subsystem->cursorY = y;
x11_shadow_pointer_position_update(subsystem);
return 1;
}
@ -633,7 +686,7 @@ int x11_shadow_screen_grab(x11ShadowSubsystem* subsystem)
(BYTE*) image->data, PIXEL_FORMAT_XRGB32,
image->bytes_per_line, x, y, NULL);
x11_shadow_blend_cursor(subsystem);
//x11_shadow_blend_cursor(subsystem);
count = ArrayList_Count(server->clients);

View File

@ -736,10 +736,144 @@ int shadow_client_surface_update(rdpShadowClient* client, REGION16* region)
return 1;
}
int shadow_client_convert_alpha_pointer_data(BYTE* pixels, BOOL premultiplied,
UINT32 width, UINT32 height, POINTER_COLOR_UPDATE* pointerColor)
{
UINT32 x, y;
BYTE* pSrc8;
BYTE* pDst8;
int xorStep;
int andStep;
UINT32 andBit;
BYTE* andBits;
UINT32 andPixel;
BYTE A, R, G, B;
xorStep = (width * 3);
xorStep += (xorStep % 2);
andStep = ((width + 7) / 8);
andStep += (andStep % 2);
pointerColor->lengthXorMask = height * xorStep;
pointerColor->xorMaskData = (BYTE*) calloc(1, pointerColor->lengthXorMask);
if (!pointerColor->xorMaskData)
return -1;
pointerColor->lengthAndMask = height * andStep;
pointerColor->andMaskData = (BYTE*) calloc(1, pointerColor->lengthAndMask);
if (!pointerColor->andMaskData)
return -1;
for (y = 0; y < height; y++)
{
pSrc8 = &pixels[(width * 4) * (height - 1 - y)];
pDst8 = &(pointerColor->xorMaskData[y * xorStep]);
andBit = 0x80;
andBits = &(pointerColor->andMaskData[andStep * y]);
for (x = 0; x < width; x++)
{
B = *pSrc8++;
G = *pSrc8++;
R = *pSrc8++;
A = *pSrc8++;
andPixel = 0;
if (A < 64)
A = 0; /* pixel cannot be partially transparent */
if (!A)
{
/* transparent pixel: XOR = black, AND = 1 */
andPixel = 1;
B = G = R = 0;
}
else
{
if (premultiplied)
{
B = (B * 0xFF ) / A;
G = (G * 0xFF ) / A;
R = (R * 0xFF ) / A;
}
}
*pDst8++ = B;
*pDst8++ = G;
*pDst8++ = R;
if (andPixel) *andBits |= andBit;
if (!(andBit >>= 1)) { andBits++; andBit = 0x80; }
}
}
return 1;
}
int shadow_client_subsystem_process_message(rdpShadowClient* client, wMessage* message)
{
rdpContext* context = (rdpContext*) client;
rdpUpdate* update = context->update;
/* FIXME: the pointer updates appear to be broken when used with bulk compression and mstsc */
if (message->id == SHADOW_MSG_OUT_POINTER_POSITION_UPDATE_ID)
{
POINTER_POSITION_UPDATE pointerPosition;
SHADOW_MSG_OUT_POINTER_POSITION_UPDATE* msg = (SHADOW_MSG_OUT_POINTER_POSITION_UPDATE*) message->wParam;
pointerPosition.xPos = msg->xPos;
pointerPosition.yPos = msg->yPos;
if (0)
{
IFCALL(update->pointer->PointerPosition, context, &pointerPosition);
}
free(msg);
}
else if (message->id == SHADOW_MSG_OUT_POINTER_ALPHA_UPDATE_ID)
{
POINTER_NEW_UPDATE pointerNew;
POINTER_COLOR_UPDATE* pointerColor;
SHADOW_MSG_OUT_POINTER_ALPHA_UPDATE* msg = (SHADOW_MSG_OUT_POINTER_ALPHA_UPDATE*) message->wParam;
ZeroMemory(&pointerNew, sizeof(POINTER_NEW_UPDATE));
pointerNew.xorBpp = 24;
pointerColor = &(pointerNew.colorPtrAttr);
pointerColor->cacheIndex = 0;
pointerColor->xPos = msg->xHot;
pointerColor->yPos = msg->yHot;
pointerColor->width = msg->width;
pointerColor->height = msg->height;
shadow_client_convert_alpha_pointer_data(msg->pixels, msg->premultiplied,
msg->width, msg->height, pointerColor);
if (0)
{
IFCALL(update->pointer->PointerNew, context, &pointerNew);
}
free(msg->pixels);
free(msg);
}
return 1;
}
void* shadow_client_thread(rdpShadowClient* client)
{
DWORD status;
DWORD nCount;
wMessage message;
HANDLE events[32];
HANDLE StopEvent;
HANDLE ClientEvent;
@ -752,6 +886,7 @@ void* shadow_client_thread(rdpShadowClient* client)
rdpShadowScreen* screen;
rdpShadowEncoder* encoder;
rdpShadowSubsystem* subsystem;
wMessagePipe* MsgPipe = client->subsystem->MsgPipe;
server = client->server;
screen = server->screen;
@ -786,6 +921,7 @@ void* shadow_client_thread(rdpShadowClient* client)
events[nCount++] = UpdateEvent;
events[nCount++] = ClientEvent;
events[nCount++] = ChannelEvent;
events[nCount++] = MessageQueue_Event(MsgPipe->Out);
status = WaitForMultipleObjects(nCount, events, FALSE, INFINITE);
@ -833,12 +969,23 @@ void* shadow_client_thread(rdpShadowClient* client)
if (WaitForSingleObject(ChannelEvent, 0) == WAIT_OBJECT_0)
{
if (WTSVirtualChannelManagerCheckFileDescriptor(client->vcm) != TRUE)
if (!WTSVirtualChannelManagerCheckFileDescriptor(client->vcm))
{
WLog_ERR(TAG, "WTSVirtualChannelManagerCheckFileDescriptor failure");
break;
}
}
if (WaitForSingleObject(MessageQueue_Event(MsgPipe->Out), 0) == WAIT_OBJECT_0)
{
if (MessageQueue_Peek(MsgPipe->Out, &message, TRUE))
{
if (message.id == WMQ_QUIT)
break;
shadow_client_subsystem_process_message(client, &message);
}
}
}
peer->Disconnect(peer);

View File

@ -41,6 +41,28 @@ struct _SHADOW_MSG_IN_SUPPRESS_OUTPUT
};
typedef struct _SHADOW_MSG_IN_SUPPRESS_OUTPUT SHADOW_MSG_IN_SUPPRESS_OUTPUT;
#define SHADOW_MSG_OUT_POINTER_POSITION_UPDATE_ID 2001
#define SHADOW_MSG_OUT_POINTER_ALPHA_UPDATE_ID 2002
struct _SHADOW_MSG_OUT_POINTER_POSITION_UPDATE
{
UINT32 xPos;
UINT32 yPos;
};
typedef struct _SHADOW_MSG_OUT_POINTER_POSITION_UPDATE SHADOW_MSG_OUT_POINTER_POSITION_UPDATE;
struct _SHADOW_MSG_OUT_POINTER_ALPHA_UPDATE
{
UINT32 xHot;
UINT32 yHot;
UINT32 width;
UINT32 height;
BYTE* pixels;
int scanline;
BOOL premultiplied;
};
typedef struct _SHADOW_MSG_OUT_POINTER_ALPHA_UPDATE SHADOW_MSG_OUT_POINTER_ALPHA_UPDATE;
#ifdef __cplusplus
extern "C" {
#endif