/* * 86Box A hypervisor and IBM PC system emulator that specializes in * running old operating systems and software designed for IBM * PC systems and compatibles from 1981 through fairly recent * system designs based on the PCI bus. * * This file is part of the 86Box distribution. * * Implement the VNC renderer. * * Version: @(#)win_vnc.c 1.0.2 2017/10/13 * * Authors: RichardG, * Fred N. van Kempen, * * Copyright 2017 Fred N. van Kempen. */ #include #include #include "../ibm.h" #include "../device.h" #include "../video/video.h" #include "../plat.h" #include "../plat_keyboard.h" #include "../ui.h" #define BITMAP MY_BITMAP #include #undef BITMAP #include "win.h" #include "win_vnc.h" extern void video_blit_complete(void); static rfbScreenInfoPtr rfbScreen; static int vnc_clients; static int updatingSize; static int allowedX, allowedY; static int keysyms_00[] = { 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // 00-07 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // 08-0f 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // 10-17 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // 18-1f 0x0039, 0x2a02, 0x2a28, 0x2a04, 0x2a05, 0x2a06, 0x2a08, 0x0028, // 20-27 0x2a0a, 0x2a0b, 0x2a09, 0x2a0d, 0x0033, 0x000c, 0x0034, 0x0035, // 28-2f 0x000b, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007, 0x0008, // 30-37 0x0009, 0x000a, 0x2a27, 0x0027, 0x2a33, 0x000d, 0x2a34, 0x2a35, // 38-3f 0x2a03, 0x2a1e, 0x2a30, 0x2a2e, 0x2a20, 0x2a12, 0x2a21, 0x2a22, // 40-47 0x2a23, 0x2a17, 0x2a24, 0x2a25, 0x2a26, 0x2a32, 0x2a31, 0x2a18, // 48-4f 0x2a19, 0x2a10, 0x2a13, 0x2a1f, 0x2a14, 0x2a16, 0x2a2f, 0x2a11, // 50-57 0x2a2d, 0x2a15, 0x2a2c, 0x001a, 0x0000, 0x001b, 0x2a07, 0x2a0c, // 58-5f 0x0029, 0x001e, 0x0030, 0x002e, 0x0020, 0x0012, 0x0021, 0x0022, // 60-67 0x0023, 0x0017, 0x0024, 0x0025, 0x0026, 0x0032, 0x0031, 0x0018, // 68-6f 0x0019, 0x0010, 0x0013, 0x001f, 0x0014, 0x0016, 0x002f, 0x0011, // 70-77 0x002d, 0x0015, 0x002c, 0x2a1a, 0x0000, 0x2a1b, 0x2a29, 0x0000, // 78-7f 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // 80-87 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // 88-8f 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // 90-97 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // 98-9f 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // a0-a7 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // a8-af 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // b0-b7 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // b8-bf 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // c0-c7 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // c8-cf 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // d0-d7 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // d8-df 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // e0-e7 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // e8-ef 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // f0-f7 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000 // f8-ff }; static int keysyms_ff[] = { 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // 00-07 0x000e, 0x000f, 0x0000, 0x004c, 0x0000, 0x001c, 0x0000, 0x0000, // 08-0f 0x0000, 0x0000, 0x0000, 0xff45, 0x0000, 0x0000, 0x0000, 0x0000, // 10-17 0x0000, 0x0000, 0x0000, 0x0001, 0x0000, 0x0000, 0x0000, 0x0000, // 18-1f 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // 20-27 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // 28-2f 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // 30-37 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // 38-3f 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // 40-47 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // 48-4f 0x0047, 0x00cb, 0xaac8, 0x00cd, 0x00d0, 0x0049, 0x0051, 0x004f, // 50-57 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // 58-5f 0x0000, 0x0000, 0x0000, 0x0052, 0x0000, 0x0000, 0x0000, 0x00dd, // 60-67 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // 68-6f 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // 70-77 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // 78-7f 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // 80-87 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x009c, 0x0000, 0x0000, // 88-8f 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // 90-97 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // 98-9f 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // a0-a7 0x0000, 0x0000, 0x0037, 0x004e, 0x0000, 0x004a, 0x0000, 0x00b5, // a8-af 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // b0-b7 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x003b, 0x003c, // b8-bf 0x003d, 0x003e, 0x003f, 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, // c0-c7 0x0057, 0x0058, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // c8-cf 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // d0-d7 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // d8-df 0x0000, 0x0036, 0x0000, 0x001d, 0x009d, 0x0000, 0x0000, 0x0000, // e0-e7 0x0000, 0x0038, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // e8-ef 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // f0-f7 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0053 // f8-ff }; static void vnc_clientgone(rfbClientPtr cl) { pclog("VNC: client disconnected: %s\n", cl->host); if (vnc_clients > 0) vnc_clients--; if (vnc_clients == 0) { /* No more clients, pause the emulator. */ plat_pause(1); pclog("VNC: no clients, pausing..\n"); } } static enum rfbNewClientAction vnc_newclient(rfbClientPtr cl) { /* Hook the ClientGone function so we know when they're gone. */ cl->clientGoneHook = vnc_clientgone; pclog("VNC: new client: %s\n", cl->host); if (++vnc_clients == 1) { /* We now have clients, un-pause the emulator. */ pclog("VNC: unpausing..\n"); plat_pause(0); } return(RFB_CLIENT_ACCEPT); } static void vnc_display(rfbClientPtr cl) { /* Avoid race condition between resize and update. */ if (!updatingSize && cl->newFBSizePending) { updatingSize = 1; pclog("VNC: updatingSize=1\n"); } else if (updatingSize && !cl->newFBSizePending) { updatingSize = 0; pclog("VNC: updatingSize=0\n"); allowedX = rfbScreen->width; allowedY = rfbScreen->height; } } static void vnc_kbdevent(rfbBool down, rfbKeySym k, rfbClientPtr cl) { int will_press = 0; int key; #if 0 pclog("VNC: kbdevent %d %x\n", down, k); #endif if ((k >> 8) == 0x00) { will_press = keysyms_00[k & 0xff]; } else if ((k >> 8) == 0xff) { will_press = keysyms_ff[k & 0xff]; } if (will_press <= 0) return; #if 0 pclog("VNC: translated to %x %x\n", (will_press >> 8) & 0xff, will_press & 0xff); #endif // first key key = (will_press >> 8) & 0xff; if (key > 0) recv_key[key] = down; // second key key = will_press & 0xff; if (key > 0) recv_key[key] = down; } static void vnc_memtoscreen(int x, int y, int y1, int y2, int w, int h) { int yy, i; /* y1 to = 0 && (y+yy) < 2048) memcpy((uint32_t *) &(((uint8_t *) rfbScreen->frameBuffer)[yy*2048*4]), &(((uint32_t *)buffer32->line[y+yy])[x]), w*4); } video_blit_complete(); if (! updatingSize) rfbMarkRectAsModified(rfbScreen, 0,0, allowedX,allowedY); } static void vnc_memtoscreen_8(int x, int y, int w, int h) { #if 1 pclog("VNC: memtoscreen_8 %i,%i %i,%i\n", x, y, w, h); #endif } int vnc_init(HWND h) { rfbPixelFormat rpf = { /* * Screen format: * 32bpp; 32 depth; * little endian; * true color; * max 255 R/G/B; * red shift 16; green shift 8; blue shift 0; * padding */ 32, 32, 0, 1, 255,255,255, 16, 8, 0, 0, 0 }; if (rfbScreen == NULL) { updatingSize = 0; allowedX = allowedY = 2048; rfbScreen = rfbGetScreen(0, NULL, 2048, 2048, 8, 3, 4); rfbScreen->desktopName = "86Box"; rfbScreen->frameBuffer = (char *)malloc(2048 * 2048 * 4); #if 1 rfbScreen->serverFormat = rpf; #else rfbScreen->serverFormat = {32, 32, 0, 1, 255,255,255, 16, 8, 0, 0, 0}; #endif rfbScreen->alwaysShared = TRUE; rfbScreen->displayHook = vnc_display; rfbScreen->kbdAddEvent = vnc_kbdevent; rfbScreen->newClientHook = vnc_newclient; rfbInitServer(rfbScreen); rfbRunEventLoop(rfbScreen, -1, TRUE); } video_setblit(vnc_memtoscreen_8, vnc_memtoscreen); pclog("VNC: init complete.\n"); vnc_clients = 0; return(1); } void vnc_close(void) { pclog("VNC: closed.\n"); } void vnc_resize(int x, int y) { if ((x != rfbScreen->width || y != rfbScreen->height) && x > 160 && y > 0) { pclog("VNC: updating resolution: %dx%d\n", x, y); allowedX = (rfbScreen->width < x) ? rfbScreen->width : x; allowedY = (rfbScreen->width < y) ? rfbScreen->width : y; rfbScreen->width = x; rfbScreen->height = y; rfbClientPtr cl; rfbClientIteratorPtr iterator = rfbGetClientIterator(rfbScreen); while ((cl = rfbClientIteratorNext(iterator)) != NULL) { LOCK(cl->updateMutex); cl->newFBSizePending = 1; UNLOCK(cl->updateMutex); } } } int vnc_pause(void) { return((vnc_clients > 0) ? 0 : 1); } void vnc_take_screenshot(wchar_t *fn) { pclog("VNC: take_screenshot\n"); }