From 1602b345f3e7e508b043133d5c289d9984e39f18 Mon Sep 17 00:00:00 2001 From: dscho Date: Tue, 28 Mar 2006 14:49:21 +0000 Subject: [PATCH] add KeyboardLedState extension --- ChangeLog | 4 ++ client_examples/SDLvncviewer.c | 8 ++++ libvncclient/rfbproto.c | 21 +++++++++++ libvncclient/vncviewer.c | 7 +++- libvncserver/main.c | 1 + libvncserver/rfbserver.c | 69 +++++++++++++++++++++++++++++++++- rfb/rfb.h | 9 ++++- rfb/rfbclient.h | 6 +++ rfb/rfbproto.h | 1 + 9 files changed, 122 insertions(+), 4 deletions(-) diff --git a/ChangeLog b/ChangeLog index 416b4a1..69d3ec8 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,7 @@ +2006-03-28 Steven Carr + * SDLvncviewer.c, rfbproto.c, vncviewer.c, main.c, rfbserver.c, + rfb.h, rfbclient.h, rfbproto.h: add new encoding: KeyboardLedState + 2006-03-28 Karl Runge * classes/ssl: patch to tightvnc Java viewer for SSL support plus other fixes (richcursor colors, Tab keysym, etc). diff --git a/client_examples/SDLvncviewer.c b/client_examples/SDLvncviewer.c index b32c49b..2e33b09 100644 --- a/client_examples/SDLvncviewer.c +++ b/client_examples/SDLvncviewer.c @@ -143,6 +143,12 @@ static void update(rfbClient* cl,int x,int y,int w,int h) { SDL_UpdateRect(rfbClientGetClientData(cl, SDL_Init), x, y, w, h); } +static void kbd_leds(rfbClient* cl, int value, int pad) { + /* note: pad is for future expansion 0=unused */ + fprintf(stderr,"Led State= 0x%02X\n", value); + fflush(stderr); +} + #ifdef __MINGW32__ #define LOG_TO_FILE #endif @@ -203,6 +209,8 @@ int main(int argc,char** argv) { cl=rfbGetClient(8,3,4); cl->MallocFrameBuffer=resize; cl->GotFrameBufferUpdate=update; + cl->HandleKeyboardLedState=kbd_leds; + if(!rfbInitClient(cl,&argc,argv)) return 1; diff --git a/libvncclient/rfbproto.c b/libvncclient/rfbproto.c index 7f79c92..fe58a5e 100644 --- a/libvncclient/rfbproto.c +++ b/libvncclient/rfbproto.c @@ -521,6 +521,7 @@ SetFormatAndEncodings(rfbClient* client) rfbEncodingQualityLevel0); } + if (client->appData.useRemoteCursor) { if (se->nEncodings < MAX_ENCODINGS) encs[se->nEncodings++] = rfbClientSwap32IfLE(rfbEncodingXCursor); @@ -530,6 +531,11 @@ SetFormatAndEncodings(rfbClient* client) encs[se->nEncodings++] = rfbClientSwap32IfLE(rfbEncodingPointerPos); } + /* Let's receive keyboard state encoding if available */ + if (se->nEncodings < MAX_ENCODINGS) { + encs[se->nEncodings++] = rfbClientSwap32IfLE(rfbEncodingKeyboardLedState); + } + if (se->nEncodings < MAX_ENCODINGS && requestLastRectEncoding) { encs[se->nEncodings++] = rfbClientSwap32IfLE(rfbEncodingLastRect); } @@ -586,6 +592,11 @@ SetFormatAndEncodings(rfbClient* client) encs[se->nEncodings++] = rfbClientSwap32IfLE(rfbEncodingPointerPos); } + /* Keyboard State Encodings */ + if (se->nEncodings < MAX_ENCODINGS) { + encs[se->nEncodings++] = rfbClientSwap32IfLE(rfbEncodingKeyboardLedState); + } + encs[se->nEncodings++] = rfbClientSwap32IfLE(rfbEncodingLastRect); } @@ -785,6 +796,16 @@ HandleRFBServerMessage(rfbClient* client) } continue; } + + if (rect.encoding == rfbEncodingKeyboardLedState) { + /* OK! We have received a keyboard state message!!! */ + client->KeyboardLedStateEnabled = 1; + if (client->HandleKeyboardLedState!=NULL) + client->HandleKeyboardLedState(client, rect.r.x, 0); + // stash it for the future + client->CurrentKeyboardLedState = rect.r.x; + continue; + } if ((rect.r.x + rect.r.w > client->si.framebufferWidth) || (rect.r.y + rect.r.h > client->si.framebufferHeight)) diff --git a/libvncclient/vncviewer.c b/libvncclient/vncviewer.c index 8ad5928..635b987 100644 --- a/libvncclient/vncviewer.c +++ b/libvncclient/vncviewer.c @@ -116,7 +116,10 @@ rfbClient* rfbGetClient(int bitsPerSample,int samplesPerPixel, client->programName=""; client->serverHost=""; client->serverPort=5900; - + + client->CurrentKeyboardLedState = 0; + client->HandleKeyboardLedState = DummyPoint; + client->format.bitsPerPixel = bytesPerPixel*8; client->format.depth = bitsPerSample*samplesPerPixel; client->appData.requestedDepth=client->format.depth; @@ -171,6 +174,8 @@ rfbClient* rfbGetClient(int bitsPerSample,int samplesPerPixel, client->GetPassword = ReadPassword; client->MallocFrameBuffer = MallocFrameBuffer; client->Bell = Dummy; + client->CurrentKeyboardLedState = 0; + client->HandleKeyboardLedState = DummyPoint; return client; } diff --git a/libvncserver/main.c b/libvncserver/main.c index c618280..3aa9673 100644 --- a/libvncserver/main.c +++ b/libvncserver/main.c @@ -854,6 +854,7 @@ rfbScreenInfoPtr rfbGetScreen(int* argc,char** argv, screen->setTranslateFunction = rfbSetTranslateFunction; screen->newClientHook = rfbDefaultNewClientHook; screen->displayHook = NULL; + screen->getKeyboardLedStateHook = NULL; /* initialize client list and iterator mutex */ rfbClientListInit(screen); diff --git a/libvncserver/rfbserver.c b/libvncserver/rfbserver.c index f565f05..93b6c0f 100644 --- a/libvncserver/rfbserver.c +++ b/libvncserver/rfbserver.c @@ -348,6 +348,8 @@ rfbNewTCPOrUDPClient(rfbScreenInfoPtr rfbScreen, cl->enableCursorPosUpdates = FALSE; cl->useRichCursorEncoding = FALSE; cl->enableLastRectEncoding = FALSE; + cl->enableKeyboardLedState = FALSE; + cl->lastKeyboardLedState = -1; cl->cursorX = rfbScreen->cursorX; cl->cursorY = rfbScreen->cursorY; cl->useNewFBSize = FALSE; @@ -729,6 +731,40 @@ static rfbBool rectSwapIfLEAndClip(uint16_t* x,uint16_t* y,uint16_t* w,uint16_t* return TRUE; } +/* + * Send keyboard state (PointerPos pseudo-encoding). + */ + +rfbBool +rfbSendKeyboardLedState(rfbClientPtr cl) +{ + rfbFramebufferUpdateRectHeader rect; + + if (cl->ublen + sz_rfbFramebufferUpdateRectHeader > UPDATE_BUF_SIZE) { + if (!rfbSendUpdateBuf(cl)) + return FALSE; + } + + rect.encoding = Swap32IfLE(rfbEncodingKeyboardLedState); + rect.r.x = Swap16IfLE(cl->lastKeyboardLedState); + 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; + + cl->cursorPosBytesSent += sz_rfbFramebufferUpdateRectHeader; + cl->cursorPosUpdatesSent++; + + if (!rfbSendUpdateBuf(cl)) + return FALSE; + + return TRUE; +} + + /* * rfbProcessClientNormalMessage is called when the client has sent a normal * protocol message. @@ -911,6 +947,13 @@ rfbProcessClientNormalMessage(rfbClientPtr cl) cl->useNewFBSize = TRUE; } break; + case rfbEncodingKeyboardLedState: + if (!cl->enableKeyboardLedState) { + rfbLog("Enabling KeyboardLedState protocol extension for client " + "%s\n", cl->host); + cl->enableKeyboardLedState = TRUE; + } + break; #ifdef LIBVNCSERVER_HAVE_LIBZ case rfbEncodingZRLE: if (cl->preferredEncoding == -1) { @@ -1175,7 +1218,9 @@ rfbSendFramebufferUpdate(rfbClientPtr cl, int dx, dy; rfbBool sendCursorShape = FALSE; rfbBool sendCursorPos = FALSE; + rfbBool sendKeyboardLedState = FALSE; rfbBool result = TRUE; + if(cl->screen->displayHook) cl->screen->displayHook(cl); @@ -1216,6 +1261,21 @@ rfbSendFramebufferUpdate(rfbClientPtr cl, if (cl->enableCursorPosUpdates && cl->cursorWasMoved) sendCursorPos = TRUE; + /* + * Do we plan to send a keyboard state update? + */ + if ((cl->enableKeyboardLedState) && + (cl->screen->getKeyboardLedStateHook!=NULL)) + { + int x; + x=cl->screen->getKeyboardLedStateHook(cl->screen); + if (x!=cl->lastKeyboardLedState) + { + sendKeyboardLedState = TRUE; + cl->lastKeyboardLedState=x; + } + } + LOCK(cl->updateMutex); /* @@ -1259,7 +1319,7 @@ rfbSendFramebufferUpdate(rfbClientPtr cl, sraRgnEmpty(updateRegion) && (cl->enableCursorShapeUpdates || (cl->cursorX == cl->screen->cursorX && cl->cursorY == cl->screen->cursorY)) && - !sendCursorShape && !sendCursorPos) { + !sendCursorShape && !sendCursorPos && !sendKeyboardLedState) { sraRgnDestroy(updateRegion); UNLOCK(cl->updateMutex); return TRUE; @@ -1395,7 +1455,7 @@ rfbSendFramebufferUpdate(rfbClientPtr cl, } fu->nRects = Swap16IfLE((uint16_t)(sraRgnCountRects(updateCopyRegion) + nUpdateRegionRects + - !!sendCursorShape + !!sendCursorPos)); + !!sendCursorShape + !!sendCursorPos + !!sendKeyboardLedState)); } else { fu->nRects = 0xFFFF; } @@ -1413,6 +1473,11 @@ rfbSendFramebufferUpdate(rfbClientPtr cl, goto updateFailed; } + if (sendKeyboardLedState) { + if (!rfbSendKeyboardLedState(cl)) + goto updateFailed; + } + if (!sraRgnEmpty(updateCopyRegion)) { if (!rfbSendCopyRegion(cl,updateCopyRegion,dx,dy)) goto updateFailed; diff --git a/rfb/rfb.h b/rfb/rfb.h index cf4665b..ffba2cd 100644 --- a/rfb/rfb.h +++ b/rfb/rfb.h @@ -135,6 +135,9 @@ typedef rfbBool (*rfbSetTranslateFunctionProcPtr)(struct _rfbClientRec* cl); typedef rfbBool (*rfbPasswordCheckProcPtr)(struct _rfbClientRec* cl,const char* encryptedPassWord,int len); typedef enum rfbNewClientAction (*rfbNewClientHookPtr)(struct _rfbClientRec* cl); typedef void (*rfbDisplayHookPtr)(struct _rfbClientRec* cl); +/* support the capability to view the caps/num/scroll states of the X server */ +typedef int (*rfbGetKeyboardLedStateHookPtr)(struct _rfbScreenInfo* screen); + typedef struct { uint32_t count; @@ -295,6 +298,9 @@ typedef struct _rfbScreenInfo /* displayHook is called just before a frame buffer update */ rfbDisplayHookPtr displayHook; + /* These hooks are called to pass keyboard state back to the client */ + rfbGetKeyboardLedStateHookPtr getKeyboardLedStateHook; + #ifdef LIBVNCSERVER_HAVE_LIBPTHREAD MUTEX(cursorMutex); rfbBool backgroundLoop; @@ -478,7 +484,8 @@ typedef struct _rfbClientRec { int tightQualityLevel; #endif #endif - + int lastKeyboardLedState; /* keep track of last value so we can send *change* events */ + rfbBool enableKeyboardLedState; /* client supports KeyboardState encoding */ rfbBool enableLastRectEncoding; /* client supports LastRect encoding */ rfbBool enableCursorShapeUpdates; /* client supports cursor shape updates */ rfbBool enableCursorPosUpdates; /* client supports cursor position updates */ diff --git a/rfb/rfbclient.h b/rfb/rfbclient.h index a7d77bb..1dfd56a 100644 --- a/rfb/rfbclient.h +++ b/rfb/rfbclient.h @@ -94,6 +94,7 @@ typedef struct { struct _rfbClient; +typedef void (*HandleKeyboardLedStateProc)(struct _rfbClient* client, int value, int pad); typedef rfbBool (*HandleCursorPosProc)(struct _rfbClient* client, int x, int y); typedef void (*SoftCursorLockAreaProc)(struct _rfbClient* client, int x, int y, int w, int h); typedef void (*SoftCursorUnlockScreenProc)(struct _rfbClient* client); @@ -196,7 +197,12 @@ typedef struct _rfbClient { rfbVNCRec* vncRec; + /* Keyboard State support (is 'Caps Lock' set on the remote display???) */ + int KeyboardLedStateEnabled; + int CurrentKeyboardLedState; + /* hooks */ + HandleKeyboardLedStateProc HandleKeyboardLedState; HandleCursorPosProc HandleCursorPos; SoftCursorLockAreaProc SoftCursorLockArea; SoftCursorUnlockScreenProc SoftCursorUnlockScreen; diff --git a/rfb/rfbproto.h b/rfb/rfbproto.h index cadbce4..5cd103a 100644 --- a/rfb/rfbproto.h +++ b/rfb/rfbproto.h @@ -445,6 +445,7 @@ typedef struct { #define rfbEncodingXCursor 0xFFFFFF10 #define rfbEncodingRichCursor 0xFFFFFF11 #define rfbEncodingPointerPos 0xFFFFFF18 +#define rfbEncodingKeyboardLedState 0xFFFFFF19 #define rfbEncodingLastRect 0xFFFFFF20 #define rfbEncodingNewFBSize 0xFFFFFF21