summaryrefslogtreecommitdiffstats
path: root/client_examples/SDLvncviewer.c
diff options
context:
space:
mode:
Diffstat (limited to 'client_examples/SDLvncviewer.c')
-rw-r--r--client_examples/SDLvncviewer.c431
1 files changed, 200 insertions, 231 deletions
diff --git a/client_examples/SDLvncviewer.c b/client_examples/SDLvncviewer.c
index 8fe6f57..d17b74e 100644
--- a/client_examples/SDLvncviewer.c
+++ b/client_examples/SDLvncviewer.c
@@ -5,7 +5,6 @@
#include <SDL.h>
#include <signal.h>
#include <rfb/rfbclient.h>
-#include "scrap.h"
struct { int sdl; int rfb; } buttonMapping[]={
{1, rfbButton1Mask},
@@ -16,14 +15,22 @@ struct { int sdl; int rfb; } buttonMapping[]={
{0,0}
};
+struct { char mask; int bits_stored; } utf8Mapping[]= {
+ {0b00111111, 6},
+ {0b01111111, 7},
+ {0b00011111, 5},
+ {0b00001111, 4},
+ {0b00000111, 3},
+ {0,0}
+};
+
static int enableResizable = 1, viewOnly, listenLoop, buttonMask;
-#ifdef SDL_ASYNCBLIT
- int sdlFlags = SDL_HWSURFACE | SDL_ASYNCBLIT | SDL_HWACCEL;
-#else
- int sdlFlags = SDL_HWSURFACE | SDL_HWACCEL;
-#endif
-static int realWidth, realHeight, bytesPerPixel, rowStride;
-static char *sdlPixels;
+int sdlFlags;
+SDL_Texture *sdlTexture;
+SDL_Renderer *sdlRenderer;
+SDL_Window *sdlWindow;
+/* client's pointer position */
+int x,y;
static int rightAltKeyDown, leftAltKeyDown;
@@ -32,53 +39,72 @@ static rfbBool resize(rfbClient* client) {
depth=client->format.bitsPerPixel;
if (enableResizable)
- sdlFlags |= SDL_RESIZABLE;
+ sdlFlags |= SDL_WINDOW_RESIZABLE;
client->updateRect.x = client->updateRect.y = 0;
client->updateRect.w = width; client->updateRect.h = height;
- rfbBool okay=SDL_VideoModeOK(width,height,depth,sdlFlags);
- if(!okay)
- for(depth=24;!okay && depth>4;depth/=2)
- okay=SDL_VideoModeOK(width,height,depth,sdlFlags);
- if(okay) {
- SDL_Surface* sdl=SDL_SetVideoMode(width,height,depth,sdlFlags);
- rfbClientSetClientData(client, SDL_Init, sdl);
- client->width = sdl->pitch / (depth / 8);
- if (sdlPixels) {
- free(client->frameBuffer);
- sdlPixels = NULL;
- }
- client->frameBuffer=sdl->pixels;
-
- client->format.bitsPerPixel=depth;
- client->format.redShift=sdl->format->Rshift;
- client->format.greenShift=sdl->format->Gshift;
- client->format.blueShift=sdl->format->Bshift;
- client->format.redMax=sdl->format->Rmask>>client->format.redShift;
- client->format.greenMax=sdl->format->Gmask>>client->format.greenShift;
- client->format.blueMax=sdl->format->Bmask>>client->format.blueShift;
- SetFormatAndEncodings(client);
+ /* (re)create the surface used as the client's framebuffer */
+ SDL_FreeSurface(rfbClientGetClientData(client, SDL_Init));
+ SDL_Surface* sdl=SDL_CreateRGBSurface(0,
+ width,
+ height,
+ depth,
+ 0,0,0,0);
+ if(!sdl)
+ rfbClientErr("resize: error creating surface: %s\n", SDL_GetError());
+
+ rfbClientSetClientData(client, SDL_Init, sdl);
+ client->width = sdl->pitch / (depth / 8);
+ client->frameBuffer=sdl->pixels;
+
+ client->format.bitsPerPixel=depth;
+ client->format.redShift=sdl->format->Rshift;
+ client->format.greenShift=sdl->format->Gshift;
+ client->format.blueShift=sdl->format->Bshift;
+ client->format.redMax=sdl->format->Rmask>>client->format.redShift;
+ client->format.greenMax=sdl->format->Gmask>>client->format.greenShift;
+ client->format.blueMax=sdl->format->Bmask>>client->format.blueShift;
+ SetFormatAndEncodings(client);
+
+ /* create or resize the window */
+ if(!sdlWindow) {
+ sdlWindow = SDL_CreateWindow(client->desktopName,
+ SDL_WINDOWPOS_UNDEFINED,
+ SDL_WINDOWPOS_UNDEFINED,
+ width,
+ height,
+ sdlFlags);
+ if(!sdlWindow)
+ rfbClientErr("resize: error creating window: %s\n", SDL_GetError());
} else {
- SDL_Surface* sdl=rfbClientGetClientData(client, SDL_Init);
- rfbClientLog("Could not set resolution %dx%d!\n",
- client->width,client->height);
- if(sdl) {
- client->width=sdl->pitch / (depth / 8);
- client->height=sdl->h;
- } else {
- client->width=0;
- client->height=0;
- }
- return FALSE;
+ SDL_SetWindowSize(sdlWindow, width, height);
+ }
+
+ /* create the renderer if it does not already exist */
+ if(!sdlRenderer) {
+ sdlRenderer = SDL_CreateRenderer(sdlWindow, -1, 0);
+ if(!sdlRenderer)
+ rfbClientErr("resize: error creating renderer: %s\n", SDL_GetError());
+ SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "linear"); /* make the scaled rendering look smoother. */
}
- SDL_WM_SetCaption(client->desktopName, "SDL");
+ SDL_RenderSetLogicalSize(sdlRenderer, width, height); /* this is a departure from the SDL1.2-based version, but more in the sense of a VNC viewer in keeeping aspect ratio */
+
+ /* (re)create the texture that sits in between the surface->pixels and the renderer */
+ if(sdlTexture)
+ SDL_DestroyTexture(sdlTexture);
+ sdlTexture = SDL_CreateTexture(sdlRenderer,
+ SDL_PIXELFORMAT_ARGB8888,
+ SDL_TEXTUREACCESS_STREAMING,
+ width, height);
+ if(!sdlTexture)
+ rfbClientErr("resize: error creating texture: %s\n", SDL_GetError());
return TRUE;
}
static rfbKeySym SDL_key2rfbKeySym(SDL_KeyboardEvent* e) {
rfbKeySym k = 0;
- SDLKey sym = e->keysym.sym;
+ SDL_Keycode sym = e->keysym.sym;
switch (sym) {
case SDLK_BACKSPACE: k = XK_BackSpace; break;
@@ -87,18 +113,17 @@ static rfbKeySym SDL_key2rfbKeySym(SDL_KeyboardEvent* e) {
case SDLK_RETURN: k = XK_Return; break;
case SDLK_PAUSE: k = XK_Pause; break;
case SDLK_ESCAPE: k = XK_Escape; break;
- case SDLK_SPACE: k = XK_space; break;
case SDLK_DELETE: k = XK_Delete; break;
- case SDLK_KP0: k = XK_KP_0; break;
- case SDLK_KP1: k = XK_KP_1; break;
- case SDLK_KP2: k = XK_KP_2; break;
- case SDLK_KP3: k = XK_KP_3; break;
- case SDLK_KP4: k = XK_KP_4; break;
- case SDLK_KP5: k = XK_KP_5; break;
- case SDLK_KP6: k = XK_KP_6; break;
- case SDLK_KP7: k = XK_KP_7; break;
- case SDLK_KP8: k = XK_KP_8; break;
- case SDLK_KP9: k = XK_KP_9; break;
+ case SDLK_KP_0: k = XK_KP_0; break;
+ case SDLK_KP_1: k = XK_KP_1; break;
+ case SDLK_KP_2: k = XK_KP_2; break;
+ case SDLK_KP_3: k = XK_KP_3; break;
+ case SDLK_KP_4: k = XK_KP_4; break;
+ case SDLK_KP_5: k = XK_KP_5; break;
+ case SDLK_KP_6: k = XK_KP_6; break;
+ case SDLK_KP_7: k = XK_KP_7; break;
+ case SDLK_KP_8: k = XK_KP_8; break;
+ case SDLK_KP_9: k = XK_KP_9; break;
case SDLK_KP_PERIOD: k = XK_KP_Decimal; break;
case SDLK_KP_DIVIDE: k = XK_KP_Divide; break;
case SDLK_KP_MULTIPLY: k = XK_KP_Multiply; break;
@@ -130,165 +155,58 @@ static rfbKeySym SDL_key2rfbKeySym(SDL_KeyboardEvent* e) {
case SDLK_F13: k = XK_F13; break;
case SDLK_F14: k = XK_F14; break;
case SDLK_F15: k = XK_F15; break;
- case SDLK_NUMLOCK: k = XK_Num_Lock; break;
+ case SDLK_NUMLOCKCLEAR: k = XK_Num_Lock; break;
case SDLK_CAPSLOCK: k = XK_Caps_Lock; break;
- case SDLK_SCROLLOCK: k = XK_Scroll_Lock; break;
+ case SDLK_SCROLLLOCK: k = XK_Scroll_Lock; break;
case SDLK_RSHIFT: k = XK_Shift_R; break;
case SDLK_LSHIFT: k = XK_Shift_L; break;
case SDLK_RCTRL: k = XK_Control_R; break;
case SDLK_LCTRL: k = XK_Control_L; break;
case SDLK_RALT: k = XK_Alt_R; break;
case SDLK_LALT: k = XK_Alt_L; break;
- case SDLK_RMETA: k = XK_Meta_R; break;
- case SDLK_LMETA: k = XK_Meta_L; break;
- case SDLK_LSUPER: k = XK_Super_L; break;
- case SDLK_RSUPER: k = XK_Super_R; break;
+ case SDLK_LGUI: k = XK_Super_L; break;
+ case SDLK_RGUI: k = XK_Super_R; break;
#if 0
case SDLK_COMPOSE: k = XK_Compose; break;
#endif
case SDLK_MODE: k = XK_Mode_switch; break;
case SDLK_HELP: k = XK_Help; break;
- case SDLK_PRINT: k = XK_Print; break;
+ case SDLK_PRINTSCREEN: k = XK_Print; break;
case SDLK_SYSREQ: k = XK_Sys_Req; break;
- case SDLK_BREAK: k = XK_Break; break;
default: break;
}
- /* both SDL and X11 keysyms match ASCII in the range 0x01-0x7f */
- if (k == 0 && sym > 0x0 && sym < 0x100) {
- k = sym;
- if (e->keysym.mod & (KMOD_LSHIFT | KMOD_RSHIFT)) {
- if (k >= '1' && k <= '9')
- k &= ~0x10;
- else if (k >= 'a' && k <= 'f')
- k &= ~0x20;
- }
- }
- if (k == 0) {
- if (e->keysym.unicode < 0x100)
- k = e->keysym.unicode;
- else
- rfbClientLog("Unknown keysym: %d\n", sym);
- }
+ /* SDL_TEXTINPUT does not generate characters if ctrl is down, so handle those here */
+ if (k == 0 && sym > 0x0 && sym < 0x100 && e->keysym.mod & KMOD_CTRL)
+ k = sym;
return k;
}
-static uint32_t get(rfbClient *cl, int x, int y)
-{
- switch (bytesPerPixel) {
- case 1: return ((uint8_t *)cl->frameBuffer)[x + y * cl->width];
- case 2: return ((uint16_t *)cl->frameBuffer)[x + y * cl->width];
- case 4: return ((uint32_t *)cl->frameBuffer)[x + y * cl->width];
- default:
- rfbClientErr("Unknown bytes/pixel: %d", bytesPerPixel);
- exit(1);
+/* UTF-8 decoding is from https://rosettacode.org/wiki/UTF-8_encode_and_decode which is under GFDL 1.2 */
+static rfbKeySym utf8char2rfbKeySym(const char chr[4]) {
+ int bytes = strlen(chr);
+ int shift = utf8Mapping[0].bits_stored * (bytes - 1);
+ rfbKeySym codep = (*chr++ & utf8Mapping[bytes].mask) << shift;
+ int i;
+ for(i = 1; i < bytes; ++i, ++chr) {
+ shift -= utf8Mapping[0].bits_stored;
+ codep |= ((char)*chr & utf8Mapping[0].mask) << shift;
}
-}
-
-static void put(int x, int y, uint32_t v)
-{
- switch (bytesPerPixel) {
- case 1: ((uint8_t *)sdlPixels)[x + y * rowStride] = v; break;
- case 2: ((uint16_t *)sdlPixels)[x + y * rowStride] = v; break;
- case 4: ((uint32_t *)sdlPixels)[x + y * rowStride] = v; break;
- default:
- rfbClientErr("Unknown bytes/pixel: %d", bytesPerPixel);
- exit(1);
- }
-}
-
-static void resizeRectangleToReal(rfbClient *cl, int x, int y, int w, int h)
-{
- int i0 = x * realWidth / cl->width;
- int i1 = ((x + w) * realWidth - 1) / cl->width + 1;
- int j0 = y * realHeight / cl->height;
- int j1 = ((y + h) * realHeight - 1) / cl->height + 1;
- int i, j;
-
- for (j = j0; j < j1; j++)
- for (i = i0; i < i1; i++) {
- int x0 = i * cl->width / realWidth;
- int x1 = ((i + 1) * cl->width - 1) / realWidth + 1;
- int y0 = j * cl->height / realHeight;
- int y1 = ((j + 1) * cl->height - 1) / realHeight + 1;
- uint32_t r = 0, g = 0, b = 0;
-
- for (y = y0; y < y1; y++)
- for (x = x0; x < x1; x++) {
- uint32_t v = get(cl, x, y);
-#define REDSHIFT cl->format.redShift
-#define REDMAX cl->format.redMax
-#define GREENSHIFT cl->format.greenShift
-#define GREENMAX cl->format.greenMax
-#define BLUESHIFT cl->format.blueShift
-#define BLUEMAX cl->format.blueMax
- r += (v >> REDSHIFT) & REDMAX;
- g += (v >> GREENSHIFT) & GREENMAX;
- b += (v >> BLUESHIFT) & BLUEMAX;
- }
- r /= (x1 - x0) * (y1 - y0);
- g /= (x1 - x0) * (y1 - y0);
- b /= (x1 - x0) * (y1 - y0);
-
- put(i, j, (r << REDSHIFT) | (g << GREENSHIFT) |
- (b << BLUESHIFT));
- }
+ return codep;
}
static void update(rfbClient* cl,int x,int y,int w,int h) {
- if (sdlPixels) {
- resizeRectangleToReal(cl, x, y, w, h);
- w = ((x + w) * realWidth - 1) / cl->width + 1;
- h = ((y + h) * realHeight - 1) / cl->height + 1;
- x = x * realWidth / cl->width;
- y = y * realHeight / cl->height;
- w -= x;
- h -= y;
- }
- SDL_UpdateRect(rfbClientGetClientData(cl, SDL_Init), x, y, w, h);
-}
-
-static void setRealDimension(rfbClient *client, int w, int h)
-{
- SDL_Surface* sdl;
-
- if (w < 0) {
- const SDL_VideoInfo *info = SDL_GetVideoInfo();
- w = info->current_h;
- h = info->current_w;
- }
-
- if (w == realWidth && h == realHeight)
- return;
-
- if (!sdlPixels) {
- int size;
-
- sdlPixels = (char *)client->frameBuffer;
- rowStride = client->width;
-
- bytesPerPixel = client->format.bitsPerPixel / 8;
- size = client->width * bytesPerPixel * client->height;
- client->frameBuffer = malloc(size);
- if (!client->frameBuffer) {
- rfbClientErr("Could not allocate %d bytes", size);
- exit(1);
- }
- memcpy(client->frameBuffer, sdlPixels, size);
- }
-
- sdl = rfbClientGetClientData(client, SDL_Init);
- if (sdl->w != w || sdl->h != h) {
- int depth = sdl->format->BitsPerPixel;
- sdl = SDL_SetVideoMode(w, h, depth, sdlFlags);
- rfbClientSetClientData(client, SDL_Init, sdl);
- sdlPixels = sdl->pixels;
- rowStride = sdl->pitch / (depth / 8);
- }
-
- realWidth = w;
- realHeight = h;
- update(client, 0, 0, client->width, client->height);
+ SDL_Surface *sdl = rfbClientGetClientData(cl, SDL_Init);
+ /* update texture from surface->pixels */
+ SDL_Rect r = {x,y,w,h};
+ if(SDL_UpdateTexture(sdlTexture, &r, sdl->pixels + y*sdl->pitch + x*4, sdl->pitch) < 0)
+ rfbClientErr("update: failed to update texture: %s\n", SDL_GetError());
+ /* copy texture to renderer and show */
+ if(SDL_RenderClear(sdlRenderer) < 0)
+ rfbClientErr("update: failed to clear renderer: %s\n", SDL_GetError());
+ if(SDL_RenderCopy(sdlRenderer, sdlTexture, NULL, NULL) < 0)
+ rfbClientErr("update: failed to copy texture to renderer: %s\n", SDL_GetError());
+ SDL_RenderPresent(sdlRenderer);
}
static void kbd_leds(rfbClient* cl, int value, int pad) {
@@ -374,17 +292,69 @@ static void cleanup(rfbClient* cl)
static rfbBool handleSDLEvent(rfbClient *cl, SDL_Event *e)
{
switch(e->type) {
-#if SDL_MAJOR_VERSION > 1 || SDL_MINOR_VERSION >= 2
- case SDL_VIDEOEXPOSE:
+ case SDL_WINDOWEVENT:
+ switch (e->window.event) {
+ case SDL_WINDOWEVENT_EXPOSED:
SendFramebufferUpdateRequest(cl, 0, 0,
cl->width, cl->height, FALSE);
break;
-#endif
+ case SDL_WINDOWEVENT_FOCUS_GAINED:
+ if (SDL_HasClipboardText()) {
+ char *text = SDL_GetClipboardText();
+ if(text) {
+ rfbClientLog("sending clipboard text '%s'\n", text);
+ SendClientCutText(cl, text, strlen(text));
+ }
+ }
+
+ break;
+ case SDL_WINDOWEVENT_FOCUS_LOST:
+ if (rightAltKeyDown) {
+ SendKeyEvent(cl, XK_Alt_R, FALSE);
+ rightAltKeyDown = FALSE;
+ rfbClientLog("released right Alt key\n");
+ }
+ if (leftAltKeyDown) {
+ SendKeyEvent(cl, XK_Alt_L, FALSE);
+ leftAltKeyDown = FALSE;
+ rfbClientLog("released left Alt key\n");
+ }
+ break;
+ }
+ break;
+ case SDL_MOUSEWHEEL:
+ {
+ int steps;
+ if (viewOnly)
+ break;
+
+ if(e->wheel.y > 0)
+ for(steps = 0; steps < e->wheel.y; ++steps) {
+ SendPointerEvent(cl, x, y, rfbButton4Mask);
+ SendPointerEvent(cl, x, y, 0);
+ }
+ if(e->wheel.y < 0)
+ for(steps = 0; steps > e->wheel.y; --steps) {
+ SendPointerEvent(cl, x, y, rfbButton5Mask);
+ SendPointerEvent(cl, x, y, 0);
+ }
+ if(e->wheel.x > 0)
+ for(steps = 0; steps < e->wheel.x; ++steps) {
+ SendPointerEvent(cl, x, y, 0b01000000);
+ SendPointerEvent(cl, x, y, 0);
+ }
+ if(e->wheel.x < 0)
+ for(steps = 0; steps > e->wheel.x; --steps) {
+ SendPointerEvent(cl, x, y, 0b00100000);
+ SendPointerEvent(cl, x, y, 0);
+ }
+ break;
+ }
case SDL_MOUSEBUTTONUP:
case SDL_MOUSEBUTTONDOWN:
case SDL_MOUSEMOTION:
{
- int x, y, state, i;
+ int state, i;
if (viewOnly)
break;
@@ -407,10 +377,6 @@ static rfbBool handleSDLEvent(rfbClient *cl, SDL_Event *e)
break;
}
}
- if (sdlPixels) {
- x = x * cl->width / realWidth;
- y = y * cl->height / realHeight;
- }
SendPointerEvent(cl, x, y, buttonMask);
buttonMask &= ~(rfbButton4Mask | rfbButton5Mask);
break;
@@ -426,6 +392,13 @@ static rfbBool handleSDLEvent(rfbClient *cl, SDL_Event *e)
if (e->key.keysym.sym == SDLK_LALT)
leftAltKeyDown = e->type == SDL_KEYDOWN;
break;
+ case SDL_TEXTINPUT:
+ if (viewOnly)
+ break;
+ rfbKeySym sym = utf8char2rfbKeySym(e->text.text);
+ SendKeyEvent(cl, sym, TRUE);
+ SendKeyEvent(cl, sym, FALSE);
+ break;
case SDL_QUIT:
if(listenLoop)
{
@@ -437,32 +410,6 @@ static rfbBool handleSDLEvent(rfbClient *cl, SDL_Event *e)
rfbClientCleanup(cl);
exit(0);
}
- case SDL_ACTIVEEVENT:
- if (!e->active.gain && rightAltKeyDown) {
- SendKeyEvent(cl, XK_Alt_R, FALSE);
- rightAltKeyDown = FALSE;
- rfbClientLog("released right Alt key\n");
- }
- if (!e->active.gain && leftAltKeyDown) {
- SendKeyEvent(cl, XK_Alt_L, FALSE);
- leftAltKeyDown = FALSE;
- rfbClientLog("released left Alt key\n");
- }
-
- if (e->active.gain && lost_scrap()) {
- static char *data = NULL;
- static int len = 0;
- get_scrap(T('T', 'E', 'X', 'T'), &len, &data);
- if (len)
- SendClientCutText(cl, data, len);
- }
- break;
- case SDL_SYSWMEVENT:
- clipboard_filter(e);
- break;
- case SDL_VIDEORESIZE:
- setRealDimension(cl, e->resize.w, e->resize.h);
- break;
default:
rfbClientLog("ignore SDL event: 0x%x\n", e->type);
}
@@ -471,7 +418,33 @@ static rfbBool handleSDLEvent(rfbClient *cl, SDL_Event *e)
static void got_selection(rfbClient *cl, const char *text, int len)
{
- put_scrap(T('T', 'E', 'X', 'T'), len, text);
+ rfbClientLog("received clipboard text '%s'\n", text);
+ if(SDL_SetClipboardText(text) != 0)
+ rfbClientErr("could not set received clipboard text: %s\n", SDL_GetError());
+}
+
+
+static rfbCredential* get_credential(rfbClient* cl, int credentialType){
+ rfbCredential *c = malloc(sizeof(rfbCredential));
+ c->userCredential.username = malloc(RFB_BUF_SIZE);
+ c->userCredential.password = malloc(RFB_BUF_SIZE);
+
+ if(credentialType != rfbCredentialTypeUser) {
+ rfbClientErr("something else than username and password required for authentication\n");
+ return NULL;
+ }
+
+ rfbClientLog("username and password required for authentication!\n");
+ printf("user: ");
+ fgets(c->userCredential.username, RFB_BUF_SIZE, stdin);
+ printf("pass: ");
+ fgets(c->userCredential.password, RFB_BUF_SIZE, stdin);
+
+ /* remove trailing newlines */
+ c->userCredential.username[strcspn(c->userCredential.username, "\n")] = 0;
+ c->userCredential.password[strcspn(c->userCredential.password, "\n")] = 0;
+
+ return c;
}
@@ -508,9 +481,6 @@ int main(int argc,char** argv) {
argc = j;
SDL_Init(SDL_INIT_VIDEO | SDL_INIT_NOPARACHUTE);
- SDL_EnableUNICODE(1);
- SDL_EnableKeyRepeat(SDL_DEFAULT_REPEAT_DELAY,
- SDL_DEFAULT_REPEAT_INTERVAL);
atexit(SDL_Quit);
signal(SIGINT, exit);
@@ -523,6 +493,7 @@ int main(int argc,char** argv) {
cl->HandleKeyboardLedState=kbd_leds;
cl->HandleTextChat=text_chat;
cl->GotXCutText = got_selection;
+ cl->GetCredential = get_credential;
cl->listenPort = LISTEN_PORT_OFFSET;
cl->listen6Port = LISTEN_PORT_OFFSET;
if(!rfbInitClient(cl,&argc,argv))
@@ -532,8 +503,6 @@ int main(int argc,char** argv) {
break;
}
- init_scrap();
-
while(1) {
if(SDL_PollEvent(&e)) {
/*