Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for RFB Extension Qemu Key Event #447

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
93 changes: 89 additions & 4 deletions libvncserver/rfbserver.c
Original file line number Diff line number Diff line change
Expand Up @@ -980,6 +980,8 @@ rfbSendSupportedMessages(rfbClientPtr cl)
rfbSetBit(msgs.server2client, rfbPalmVNCReSizeFrameBuffer);
rfbSetBit(msgs.client2server, rfbSetDesktopSize);

rfbSetBit(msgs.server2client, rfbQemuClientMessage);

if (cl->screen->xvpHook) {
rfbSetBit(msgs.client2server, rfbXvp);
rfbSetBit(msgs.server2client, rfbXvp);
Expand Down Expand Up @@ -1036,9 +1038,11 @@ rfbSendSupportedEncodings(rfbClientPtr cl)
rfbEncodingSupportedMessages,
rfbEncodingSupportedEncodings,
rfbEncodingServerIdentity,
rfbEncodingQEMUKeyEvent,
};
uint32_t nEncodings = sizeof(supported) / sizeof(supported[0]), i;


Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

please don't add unrelated whitespace.

/* think rfbSetEncodingsMsg */

if (cl->ublen + sz_rfbFramebufferUpdateRectHeader
Expand Down Expand Up @@ -1133,6 +1137,38 @@ rfbSendServerIdentity(rfbClientPtr cl)
return TRUE;
}

/*
* Send rfbEncodingQEMUKeyEvent.
*/

rfbBool
rfbSendQemuKeyEvent(rfbClientPtr cl)
{
rfbFramebufferUpdateRectHeader rect;

if (cl->ublen + sz_rfbFramebufferUpdateRectHeader > UPDATE_BUF_SIZE) {
if (!rfbSendUpdateBuf(cl))
return FALSE;
}

rect.encoding = Swap32IfLE(rfbEncodingQEMUKeyEvent);
rect.r.x = 0;
rect.r.y = 0;
rect.r.w = 0;
rect.r.h = 0;

memcpy(&cl->updateBuf[cl->ublen], (char *)&rect,
sz_rfbFramebufferUpdateRectHeader);
cl->ublen += sz_rfbFramebufferUpdateRectHeader;

rfbStatRecordEncodingSent(cl, rfbEncodingQEMUKeyEvent, sz_rfbFramebufferUpdateRectHeader, sz_rfbFramebufferUpdateRectHeader);

if (!rfbSendUpdateBuf(cl))
return FALSE;

return TRUE;
}

/*
* Send an xvp server message
*/
Expand Down Expand Up @@ -2130,6 +2166,7 @@ rfbProcessClientNormalMessage(rfbClientPtr cl)
cl->enableSupportedMessages = FALSE;
cl->enableSupportedEncodings = FALSE;
cl->enableServerIdentity = FALSE;
cl->enableQemuKeyEvent = FALSE;
#if defined(LIBVNCSERVER_HAVE_LIBZ) || defined(LIBVNCSERVER_HAVE_LIBPNG)
cl->tightQualityLevel = -1;
#ifdef LIBVNCSERVER_HAVE_LIBJPEG
Expand Down Expand Up @@ -2267,6 +2304,13 @@ rfbProcessClientNormalMessage(rfbClientPtr cl)
}
}
break;
case rfbEncodingQEMUKeyEvent:
if (!cl->enableQemuKeyEvent) {
rfbLog("Enabling Qemu Key Event extension for client "
"%s\n", cl->host);
cl->enableQemuKeyEvent = TRUE;
}
break;
default:
#if defined(LIBVNCSERVER_HAVE_LIBZ) || defined(LIBVNCSERVER_HAVE_LIBPNG)
if ( enc >= (uint32_t)rfbEncodingCompressLevel0 &&
Expand Down Expand Up @@ -2457,11 +2501,28 @@ rfbProcessClientNormalMessage(rfbClientPtr cl)
rfbStatRecordMessageRcvd(cl, msg.type, sz_rfbKeyEventMsg, sz_rfbKeyEventMsg);

if(!cl->viewOnly) {
cl->screen->kbdAddEvent(msg.ke.down, (rfbKeySym)Swap32IfLE(msg.ke.key), cl);
cl->screen->kbdAddEvent(msg.ke.down, (rfbKeySym)Swap32IfLE(msg.ke.key), 0, cl);
}

return;

case rfbQemuClientMessage:
if ((n = rfbReadExact(cl, ((char *)&msg) + 1,
sz_rfbQemuClientMsg - 1)) <= 0) {
if (n != 0)
rfbLogPerror("rfbProcessClientNormalMessage: read");
rfbCloseClient(cl);
return;
}
rfbStatRecordMessageRcvd(cl, msg.type, sz_rfbQemuClientMsg, sz_rfbQemuClientMsg);

if(!cl->viewOnly) {
if (msg.qcm.subtype == 0 ) {
cl->screen->kbdAddEvent(msg.qcm.down_flag ? 1 : 0, (rfbKeySym)Swap32IfLE(msg.qcm.keysym), (rfbKeyCode)Swap32IfLE(msg.qcm.keycode), cl);
}
}
return;


case rfbPointerEvent:

Expand Down Expand Up @@ -2842,6 +2903,7 @@ rfbSendFramebufferUpdate(rfbClientPtr cl,
rfbBool sendSupportedMessages = FALSE;
rfbBool sendSupportedEncodings = FALSE;
rfbBool sendServerIdentity = FALSE;
rfbBool sendQemuKeyEvent = FALSE;
rfbBool result = TRUE;


Expand Down Expand Up @@ -2945,6 +3007,15 @@ rfbSendFramebufferUpdate(rfbClientPtr cl,
cl->enableServerIdentity = FALSE;
}

if (cl->enableQemuKeyEvent)
{
sendQemuKeyEvent = TRUE;
/* We only send this message ONCE <per setEncodings message received>
* (We disable it here)
*/
cl->enableQemuKeyEvent = FALSE;
}

LOCK(cl->updateMutex);

/*
Expand Down Expand Up @@ -2989,7 +3060,7 @@ rfbSendFramebufferUpdate(rfbClientPtr cl,
(cl->enableCursorShapeUpdates ||
(cl->cursorX == cl->screen->cursorX && cl->cursorY == cl->screen->cursorY)) &&
!sendCursorShape && !sendCursorPos && !sendKeyboardLedState &&
!sendSupportedMessages && !sendSupportedEncodings && !sendServerIdentity) {
!sendSupportedMessages && !sendSupportedEncodings && !sendServerIdentity && !sendQemuKeyEvent) {
sraRgnDestroy(updateRegion);
UNLOCK(cl->updateMutex);
if(cl->screen->displayFinishedHook)
Expand Down Expand Up @@ -3181,7 +3252,7 @@ rfbSendFramebufferUpdate(rfbClientPtr cl,
fu->nRects = Swap16IfLE((uint16_t)(sraRgnCountRects(updateCopyRegion) +
nUpdateRegionRects +
!!sendCursorShape + !!sendCursorPos + !!sendKeyboardLedState +
!!sendSupportedMessages + !!sendSupportedEncodings + !!sendServerIdentity));
!!sendSupportedMessages + !!sendSupportedEncodings + !!sendServerIdentity + !!sendQemuKeyEvent));
} else {
fu->nRects = 0xFFFF;
}
Expand Down Expand Up @@ -3216,6 +3287,10 @@ rfbSendFramebufferUpdate(rfbClientPtr cl,
if (!rfbSendServerIdentity(cl))
goto updateFailed;
}
if (sendQemuKeyEvent) {
if (!rfbSendQemuKeyEvent(cl))
goto updateFailed;
}

if (!sraRgnEmpty(updateCopyRegion)) {
if (!rfbSendCopyRegion(cl,updateCopyRegion,dx,dy))
Expand Down Expand Up @@ -3805,9 +3880,19 @@ rfbProcessUDPInput(rfbScreenInfoPtr rfbScreen)
rfbDisconnectUDPSock(rfbScreen);
return;
}
cl->screen->kbdAddEvent(msg.ke.down, (rfbKeySym)Swap32IfLE(msg.ke.key), cl);
cl->screen->kbdAddEvent(msg.ke.down, (rfbKeySym)Swap32IfLE(msg.ke.key), 0, cl);
break;

case rfbQemuClientMessage:
if (n != sz_rfbQemuClientMsg) {
rfbErr("rfbProcessUDPInput: key event incorrect length\n");
rfbDisconnectUDPSock(rfbScreen);
return;
}
if (msg.qcm.subtype == 0 )
cl->screen->kbdAddEvent(msg.qcm.down_flag, (rfbKeySym)Swap32IfLE(msg.qcm.keysym), (rfbKeyCode)Swap32IfLE(msg.qcm.keycode), cl);
return;

case rfbPointerEvent:
if (n != sz_rfbPointerEventMsg) {
rfbErr("rfbProcessUDPInput: ptr event incorrect length\n");
Expand Down
2 changes: 2 additions & 0 deletions libvncserver/stats.c
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,7 @@ char *messageNameClient2Server(uint32_t type, char *buf, int len) {
case rfbPalmVNCSetScaleFactor: snprintf(buf, len, "PalmVNCSetScale"); break;
case rfbXvp: snprintf(buf, len, "XvpClientMessage"); break;
case rfbSetDesktopSize: snprintf(buf, len, "SetDesktopSize"); break;
case rfbQemuClientMessage: snprintf(buf, len, "QemuClientMessage"); break;
default:
snprintf(buf, len, "cli2svr-0x%08X", type);

Expand Down Expand Up @@ -128,6 +129,7 @@ char *encodingName(uint32_t type, char *buf, int len) {
case rfbEncodingSupportedMessages: snprintf(buf, len, "SupportedMessage"); break;
case rfbEncodingSupportedEncodings: snprintf(buf, len, "SupportedEncoding"); break;
case rfbEncodingServerIdentity: snprintf(buf, len, "ServerIdentify"); break;
case rfbEncodingQEMUKeyEvent: snprintf(buf, len, "QEMUKeyEvent"); break;

/* The following lookups do not report in stats */
case rfbEncodingCompressLevel0: snprintf(buf, len, "CompressLevel0"); break;
Expand Down
3 changes: 2 additions & 1 deletion rfb/rfb.h
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@ enum rfbSocketState {
RFB_SOCKET_SHUTDOWN
};

typedef void (*rfbKbdAddEventProcPtr) (rfbBool down, rfbKeySym keySym, struct _rfbClientRec* cl);
typedef void (*rfbKbdAddEventProcPtr) (rfbBool down, rfbKeySym keySym, rfbKeyCode keyCode, struct _rfbClientRec* cl);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Never ever change existing API - this breaks code for existing users.

typedef void (*rfbKbdReleaseAllKeysProcPtr) (struct _rfbClientRec* cl);
typedef void (*rfbPtrAddEventProcPtr) (int buttonMask, int x, int y, struct _rfbClientRec* cl);
typedef void (*rfbSetXCutTextProcPtr) (char* str,int len, struct _rfbClientRec* cl);
Expand Down Expand Up @@ -608,6 +608,7 @@ typedef struct _rfbClientRec {
rfbBool useRichCursorEncoding; /**< rfbEncodingRichCursor is preferred */
rfbBool cursorWasChanged; /**< cursor shape update should be sent */
rfbBool cursorWasMoved; /**< cursor position update should be sent */
rfbBool enableQemuKeyEvent; /**< client supports QemuKeyEvent */
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please add members at the end of the struct to not break ABI.

int cursorX,cursorY; /**< the coordinates of the cursor,
if enableCursorShapeUpdates = FALSE */

Expand Down
16 changes: 16 additions & 0 deletions rfb/rfbproto.h
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,7 @@ typedef int8_t rfbBool;
#endif

typedef uint32_t rfbKeySym;
typedef uint32_t rfbKeyCode;
typedef uint32_t rfbPixel;

#ifdef LIBVNCSERVER_NEED_INADDR_T
Expand Down Expand Up @@ -427,6 +428,7 @@ typedef struct {
/* SetDesktopSize client -> server message */
#define rfbSetDesktopSize 251

#define rfbQemuClientMessage 255



Expand Down Expand Up @@ -467,6 +469,9 @@ typedef struct {
/* Xvp pseudo-encoding */
#define rfbEncodingXvp 0xFFFFFECB

/* QemuKeyEvent pseudo-encoding */
#define rfbEncodingQEMUKeyEvent 0xFFFFFEFE

/*
* Special encoding numbers:
* 0xFFFFFD00 .. 0xFFFFFD05 -- subsampling level
Expand Down Expand Up @@ -1490,6 +1495,16 @@ typedef struct _rfbSetSWMsg {
#define sz_rfbSetSWMsg 6


typedef struct _rfbQemuClientMsg {
uint8_t type; /* always rfbQemuClientMessage */
uint8_t subtype;
uint16_t down_flag;
uint32_t keysym;
uint32_t keycode;
} rfbQemuClientMsg;

#define sz_rfbQemuClientMsg 12


/*-----------------------------------------------------------------------------
* Union of all client->server messages.
Expand All @@ -1512,6 +1527,7 @@ typedef union {
rfbTextChatMsg tc;
rfbXvpMsg xvp;
rfbSetDesktopSizeMsg sdm;
rfbQemuClientMsg qcm;
} rfbClientToServerMsg;

/*
Expand Down