diff options
Diffstat (limited to 'tools/ioemu/gui/rfb.cc')
-rw-r--r-- | tools/ioemu/gui/rfb.cc | 1508 |
1 files changed, 1508 insertions, 0 deletions
diff --git a/tools/ioemu/gui/rfb.cc b/tools/ioemu/gui/rfb.cc new file mode 100644 index 0000000000..f67f80e895 --- /dev/null +++ b/tools/ioemu/gui/rfb.cc @@ -0,0 +1,1508 @@ +///////////////////////////////////////////////////////////////////////// +// $Id: rfb.cc,v 1.26.2.1 2004/02/02 22:35:30 cbothamy Exp $ +///////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2000 Psyon.Org! +// +// Donald Becker +// http://www.psyon.org +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +// Define BX_PLUGGABLE in files that can be compiled into plugins. For +// platforms that require a special tag on exported symbols, BX_PLUGGABLE +// is used to know when we are exporting symbols and when we are importing. +#define BX_PLUGGABLE + +#include "bochs.h" +#if BX_WITH_RFB + +#include "icon_bochs.h" +#include "font/vga.bitmap.h" + +class bx_rfb_gui_c : public bx_gui_c { +public: + bx_rfb_gui_c (void) {} + DECLARE_GUI_VIRTUAL_METHODS() +}; + +// declare one instance of the gui object and call macro to insert the +// plugin code +static bx_rfb_gui_c *theGui = NULL; +IMPLEMENT_GUI_PLUGIN_CODE(rfb) + +#define LOG_THIS theGui-> + +#ifdef WIN32 + +#include <winsock.h> +#include <process.h> +#include "rfb.h" + +#else + +#include <sys/socket.h> +#include <netinet/tcp.h> +#include <netinet/in.h> +#include <unistd.h> +#include <sys/errno.h> +#include <pthread.h> +typedef unsigned long CARD32; +typedef unsigned short CARD16; +typedef short INT16; +typedef unsigned char CARD8; +typedef int SOCKET; + +#endif + +#include "rfbproto.h" + +static bool keep_alive; +static bool client_connected; + +#define BX_RFB_PORT_MIN 5900 +#define BX_RFB_PORT_MAX 5949 +static unsigned short rfbPort; + +// Headerbar stuff +unsigned rfbBitmapCount = 0; +struct { + char *bmap; + unsigned xdim; + unsigned ydim; +} rfbBitmaps[BX_MAX_PIXMAPS]; + +unsigned rfbHeaderbarBitmapCount = 0; +struct { + unsigned int index; + unsigned int xorigin; + unsigned int yorigin; + unsigned int alignment; + void (*f)(void); +} rfbHeaderbarBitmaps[BX_MAX_HEADERBAR_ENTRIES]; + +//Keyboard stuff +#define KEYBOARD true +#define MOUSE false +#define MAX_KEY_EVENTS 512 +struct { + bool type; + int key; + int down; + int x; + int y; +} rfbKeyboardEvent[MAX_KEY_EVENTS]; +static unsigned long rfbKeyboardEvents = 0; +static bool bKeyboardInUse = false; + +// Misc Stuff +struct { + unsigned int x; + unsigned int y; + unsigned int width; + unsigned int height; + bool updated; +} rfbUpdateRegion; + +static char *rfbScreen; +static char rfbPallet[256]; + +static long rfbDimensionX, rfbDimensionY; +static long rfbStretchedX, rfbStretchedY; +static long rfbHeaderbarY; +static long rfbTileX = 0; +static long rfbTileY = 0; +static unsigned long rfbCursorX = 0; +static unsigned long rfbCursorY = 0; +static unsigned long rfbOriginLeft = 0; +static unsigned long rfbOriginRight = 0; + +static unsigned int text_rows=25, text_cols=80; +static unsigned int font_height=16, font_width=8; + +//static unsigned long ServerThread = 0; +//static unsigned long ServerThreadID = 0; + +static SOCKET sGlobal; + +void ServerThreadInit(void *indata); +void HandleRfbClient(SOCKET sClient); +int ReadExact(int sock, char *buf, int len); +int WriteExact(int sock, char *buf, int len); +void DrawBitmap(int x, int y, int width, int height, char *bmap, char color, bool update_client); +void DrawChar(int x, int y, int width, int height, int fonty, char *bmap, char color); +void UpdateScreen(unsigned char *newBits, int x, int y, int width, int height, bool update_client); +void SendUpdate(int x, int y, int width, int height); +void StartThread(); +void rfbKeyPressed(Bit32u key, int press_release); +void rfbMouseMove(int x, int y, int bmask); +void DrawColorPallet(); + +static const rfbPixelFormat BGR233Format = { + 8, 8, 1, 1, 7, 7, 3, 0, 3, 6 +}; + +// Set this for the endian of your machine. 0 = big, 1 = little +static const int rfbEndianTest = 1; + +#define Swap16(s) ((((s) & 0xff) << 8) | (((s) >> 8) & 0xff)) +#define Swap32(l) (((l) >> 24) | (((l) & 0x00ff0000) >> 8) | (((l) & 0x0000ff00) << 8) | ((l) << 24)) +#define Swap16IfLE(s) (*(const char *)&rfbEndianTest ? Swap16(s) : (s)) +#define Swap32IfLE(l) (*(const char *)&rfbEndianTest ? Swap32(l) : (l)) +#define PF_EQ(x,y) ((x.bitsPerPixel == y.bitsPerPixel) && (x.depth == y.depth) && (x.trueColour == y.trueColour) && ((x.bigEndian == y.bigEndian) || (x.bitsPerPixel == 8)) && (!x.trueColour || ((x.redMax == y.redMax) && (x.greenMax == y.greenMax) && (x.blueMax == y.blueMax) && (x.redShift == y.redShift) && (x.greenShift == y.greenShift) && (x.blueShift == y.blueShift)))) + +// This file defines stubs for the GUI interface, which is a +// place to start if you want to port bochs to a platform, for +// which there is no support for your native GUI, or if you want to compile +// bochs without any native GUI support (no output window or +// keyboard input will be possible). +// Look in 'x.cc', 'beos.cc', and 'win32.cc' for specific +// implementations of this interface. -Kevin + + +// ::SPECIFIC_INIT() +// +// Called from gui.cc, once upon program startup, to allow for the +// specific GUI code (X11, BeOS, ...) to be initialized. +// +// argc, argv: not used right now, but the intention is to pass native GUI +// specific options from the command line. (X11 options, BeOS options,...) +// +// tilewidth, tileheight: for optimization, graphics_tile_update() passes +// only updated regions of the screen to the gui code to be redrawn. +// These define the dimensions of a region (tile). +// headerbar_y: A headerbar (toolbar) is display on the top of the +// VGA window, showing floppy status, and other information. It +// always assumes the width of the current VGA mode width, but +// it's height is defined by this parameter. + +void bx_rfb_gui_c::specific_init(int argc, char **argv, unsigned tilewidth, unsigned tileheight, unsigned headerbar_y) +{ + unsigned char fc, vc; + + put("RFB"); + UNUSED(bochs_icon_bits); + + // the ask menu doesn't work on the client side + io->set_log_action(LOGLEV_PANIC, ACT_FATAL); + + rfbHeaderbarY = headerbar_y; + rfbDimensionX = 640; + rfbDimensionY = 480 + rfbHeaderbarY; + rfbStretchedX = rfbDimensionX; + rfbStretchedY = rfbDimensionY; + rfbTileX = tilewidth; + rfbTileY = tileheight; + + for(int i = 0; i < 256; i++) { + for(int j = 0; j < 16; j++) { + vc = bx_vgafont[i].data[j]; + fc = 0; + for (int b = 0; b < 8; b++) { + fc |= (vc & 0x01) << (7 - b); + vc >>= 1; + } + vga_charmap[i*32+j] = fc; + } + } + + rfbScreen = (char *)malloc(rfbDimensionX * rfbDimensionY); + memset(&rfbPallet, 0, sizeof(rfbPallet)); + rfbPallet[63] = (char)0xFF; + + rfbUpdateRegion.x = rfbDimensionX; + rfbUpdateRegion.y = rfbDimensionY; + rfbUpdateRegion.width = 0; + rfbUpdateRegion.height = 0; + rfbUpdateRegion.updated = false; + + keep_alive = true; + client_connected = false; + StartThread(); + +#ifdef WIN32 + Sleep(1000); + SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_BELOW_NORMAL); +#endif + if (bx_options.Oprivate_colormap->get ()) { + BX_ERROR(( "private_colormap option ignored." )); + } + int counter = 30; + while ((!client_connected) && (counter--)) { +#ifdef WIN32 + Sleep(1000); +#else + sleep(1); +#endif + } + if (counter < 0) BX_PANIC(("timeout! no client present")); +} + +bool InitWinsock() +{ +#ifdef WIN32 + WSADATA wsaData; + if(WSAStartup(MAKEWORD(1,1), &wsaData) != 0) return false; +#endif + return true; +} + +bool StopWinsock() +{ +#ifdef WIN32 + WSACleanup(); +#endif + return true; +} + +void ServerThreadInit(void *indata) +{ + SOCKET sServer; + SOCKET sClient; + struct sockaddr_in sai; + unsigned int sai_size; + int port_ok = 0; + +#ifdef WIN32 + SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_IDLE); +#endif + if(!InitWinsock()) { + BX_PANIC(( "could not initialize winsock.")); + goto end_of_thread; + } + + sServer = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); + if(sServer == -1) { + BX_PANIC(( "could not create socket." )); + goto end_of_thread; + } + for (rfbPort = BX_RFB_PORT_MIN; rfbPort <= BX_RFB_PORT_MAX; rfbPort++) { + sai.sin_addr.s_addr = INADDR_ANY; + sai.sin_family = AF_INET; + sai.sin_port = htons(rfbPort); + BX_INFO (("Trying port %d", rfbPort)); + if(bind(sServer, (struct sockaddr *)&sai, sizeof(sai)) == -1) { + BX_INFO(( "Could not bind socket.")); + continue; + } + if(listen(sServer, SOMAXCONN) == -1) { + BX_INFO(( "Could not listen on socket.")); + continue; + } + // success + port_ok = 1; + break; + } + if (!port_ok) { + BX_PANIC (("RFB could not bind any port between %d and %d\n", + BX_RFB_PORT_MIN, + BX_RFB_PORT_MAX)); + goto end_of_thread; + } + BX_INFO (("listening for connections on port %i", rfbPort)); + fprintf (stderr, "RFB: listening for connections on port %i\n", rfbPort); + sai_size = sizeof(sai); + while(keep_alive) { + sClient = accept(sServer, (struct sockaddr *)&sai, (socklen_t*)&sai_size); + if(sClient != -1) { + HandleRfbClient(sClient); + sGlobal = -1; + close(sClient); + } else { + close(sClient); + } + } + +end_of_thread: + StopWinsock(); +} + +void HandleRfbClient(SOCKET sClient) +{ + char rfbName[] = "Bochs-RFB"; + rfbProtocolVersionMsg pv; + int one = 1; + CARD32 auth; + rfbClientInitMsg cim; + rfbServerInitMsg sim; + + client_connected = true; + setsockopt(sClient, IPPROTO_TCP, TCP_NODELAY, (const char *)&one, sizeof(one)); + fprintf(stderr, "# RFB: accepted client connection.\n"); + sprintf(pv, rfbProtocolVersionFormat, rfbProtocolMajorVersion, rfbProtocolMinorVersion); + + if(WriteExact(sClient, pv, sz_rfbProtocolVersionMsg) < 0) { + fprintf(stderr, "# ERROR: RFB: could not send protocol version.\n"); + return; + } + if(ReadExact(sClient, pv, sz_rfbProtocolVersionMsg) < 0) { + fprintf(stderr, "# ERROR: RFB: could not recieve client protocol version.\n"); + return; + } + + auth = Swap32IfLE(rfbNoAuth); + if(WriteExact(sClient, (char *)&auth, sizeof(auth)) < 0) { + fprintf(stderr, "# ERROR: RFB: could not send authorization method.\n"); + return; + } + + if(ReadExact(sClient, (char *)&cim, sz_rfbClientInitMsg) < 0) { + fprintf(stderr, "# ERROR: RFB: could not recieve client initialization message.\n"); + return; + } + + sim.framebufferWidth = Swap16IfLE((short)rfbDimensionX); + sim.framebufferHeight = Swap16IfLE((short)rfbDimensionY); + sim.format = BGR233Format; + sim.format.redMax = Swap16IfLE(sim.format.redMax); + sim.format.greenMax = Swap16IfLE(sim.format.greenMax); + sim.format.blueMax = Swap16IfLE(sim.format.blueMax); + sim.nameLength = strlen(rfbName); + sim.nameLength = Swap32IfLE(sim.nameLength); + if(WriteExact(sClient, (char *)&sim, sz_rfbServerInitMsg) < 0) { + fprintf(stderr, "# ERROR: RFB: could send server initialization message.\n"); + return; + } + if(WriteExact(sClient, rfbName, strlen(rfbName)) < 0) { + fprintf(stderr, "# ERROR: RFB: could not send server name.\n"); + return; + } + + sGlobal = sClient; + while(keep_alive) { + CARD8 msgType; + int n; + + if((n = recv(sClient, (char *)&msgType, 1, MSG_PEEK)) <= 0) { + if(n == 0) { + fprintf(stderr, "# RFB: client closed connection.\n"); + } else { + fprintf(stderr, "# RFB: error recieving data.\n"); + } + return; + } + + switch(msgType) { + case rfbSetPixelFormat: + { + rfbSetPixelFormatMsg spf; + ReadExact(sClient, (char *)&spf, sizeof(rfbSetPixelFormatMsg)); + + spf.format.bitsPerPixel = spf.format.bitsPerPixel; + spf.format.depth = spf.format.depth; + spf.format.trueColour = (spf.format.trueColour ? 1 : 0); + spf.format.bigEndian = (spf.format.bigEndian ? 1 : 0); + spf.format.redMax = Swap16IfLE(spf.format.redMax); + spf.format.greenMax = Swap16IfLE(spf.format.greenMax); + spf.format.blueMax = Swap16IfLE(spf.format.blueMax); + spf.format.redShift = spf.format.redShift; + spf.format.greenShift = spf.format.greenShift; + spf.format.blueShift = spf.format.blueShift; + + if (!PF_EQ(spf.format, BGR233Format)) { + fprintf(stderr,"# ERROR: RFB: client has wrong pixel format\n"); + //return; + } + break; + } + case rfbFixColourMapEntries: + { + rfbFixColourMapEntriesMsg fcme; + ReadExact(sClient, (char *)&fcme, sizeof(rfbFixColourMapEntriesMsg)); + break; + } + case rfbSetEncodings: + { + rfbSetEncodingsMsg se; + int i; + CARD32 enc; + ReadExact(sClient, (char *)&se, sizeof(rfbSetEncodingsMsg)); + se.nEncodings = Swap16IfLE(se.nEncodings); + for(i = 0; i < se.nEncodings; i++) { + if((n = ReadExact(sClient, (char *)&enc, sizeof(CARD32))) <= 0) { + if(n == 0) { + fprintf(stderr, "# RFB: client closed connection.\n"); + } else { + fprintf(stderr, "# RFB: error recieving data.\n"); + } + return; + } + } + break; + } + case rfbFramebufferUpdateRequest: + { + rfbFramebufferUpdateRequestMsg fur; + + ReadExact(sClient, (char *)&fur, sizeof(rfbFramebufferUpdateRequestMsg)); + if(!fur.incremental) { + rfbUpdateRegion.x = 0; + rfbUpdateRegion.y = 0; + rfbUpdateRegion.width = rfbDimensionX; + rfbUpdateRegion.height = rfbDimensionY; + rfbUpdateRegion.updated = true; + } //else { + // if(fur.x < rfbUpdateRegion.x) rfbUpdateRegion.x = fur.x; + // if(fur.y < rfbUpdateRegion.x) rfbUpdateRegion.y = fur.y; + // if(((fur.x + fur.w) - rfbUpdateRegion.x) > rfbUpdateRegion.width) rfbUpdateRegion.width = ((fur.x + fur.w) - rfbUpdateRegion.x); + // if(((fur.y + fur.h) - rfbUpdateRegion.y) > rfbUpdateRegion.height) rfbUpdateRegion.height = ((fur.y + fur.h) - rfbUpdateRegion.y); + //} + //rfbUpdateRegion.updated = true; + break; + } + case rfbKeyEvent: + { + rfbKeyEventMsg ke; + ReadExact(sClient, (char *)&ke, sizeof(rfbKeyEventMsg)); + ke.key = Swap32IfLE(ke.key); + while(bKeyboardInUse); + bKeyboardInUse = true; + if (rfbKeyboardEvents >= MAX_KEY_EVENTS) break; + rfbKeyboardEvent[rfbKeyboardEvents].type = KEYBOARD; + rfbKeyboardEvent[rfbKeyboardEvents].key = ke.key; + rfbKeyboardEvent[rfbKeyboardEvents].down = ke.down; + rfbKeyboardEvents++; + bKeyboardInUse = false; + break; + } + case rfbPointerEvent: + { + rfbPointerEventMsg pe; + ReadExact(sClient, (char *)&pe, sizeof(rfbPointerEventMsg)); + while(bKeyboardInUse); + bKeyboardInUse = true; + if (rfbKeyboardEvents >= MAX_KEY_EVENTS) break; + rfbKeyboardEvent[rfbKeyboardEvents].type = MOUSE; + rfbKeyboardEvent[rfbKeyboardEvents].x = Swap16IfLE(pe.x); + rfbKeyboardEvent[rfbKeyboardEvents].y = Swap16IfLE(pe.y); + rfbKeyboardEvent[rfbKeyboardEvents].down = pe.buttonMask; + rfbKeyboardEvents++; + bKeyboardInUse = false; + break; + } + case rfbClientCutText: + { + rfbClientCutTextMsg cct; + ReadExact(sClient, (char *)&cct, sizeof(rfbClientCutTextMsg)); + break; + } + } + } +} +// ::HANDLE_EVENTS() +// +// Called periodically (vga_update_interval in .bochsrc) so the +// the gui code can poll for keyboard, mouse, and other +// relevant events. + +void bx_rfb_gui_c::handle_events(void) +{ + unsigned int i = 0; + while(bKeyboardInUse); + bKeyboardInUse = true; + if(rfbKeyboardEvents > 0) { + for(i = 0; i < rfbKeyboardEvents; i++) { + if(rfbKeyboardEvent[i].type == KEYBOARD) { + rfbKeyPressed(rfbKeyboardEvent[i].key, rfbKeyboardEvent[i].down); + } else { //type == MOUSE; + rfbMouseMove(rfbKeyboardEvent[i].x, rfbKeyboardEvent[i].y, rfbKeyboardEvent[i].down); + } + } + rfbKeyboardEvents = 0; + } + bKeyboardInUse = false; + + if(rfbUpdateRegion.updated) { + SendUpdate(rfbUpdateRegion.x, rfbUpdateRegion.y, rfbUpdateRegion.width, rfbUpdateRegion.height); + rfbUpdateRegion.x = rfbDimensionX; + rfbUpdateRegion.y = rfbDimensionY; + rfbUpdateRegion.width = 0; + rfbUpdateRegion.height = 0; + } + rfbUpdateRegion.updated = false; +} + + +// ::FLUSH() +// +// Called periodically, requesting that the gui code flush all pending +// screen update requests. + +void bx_rfb_gui_c::flush(void) +{ +} + + +// ::CLEAR_SCREEN() +// +// Called to request that the VGA region is cleared. Don't +// clear the area that defines the headerbar. +void bx_rfb_gui_c::clear_screen(void) +{ + memset(&rfbScreen[rfbDimensionX * rfbHeaderbarY], 0, rfbDimensionX * (rfbDimensionY - rfbHeaderbarY)); +} + + + +// ::TEXT_UPDATE() +// +// Called in a VGA text mode, to update the screen with +// new content. +// +// old_text: array of character/attributes making up the contents +// of the screen from the last call. See below +// new_text: array of character/attributes making up the current +// contents, which should now be displayed. See below +// +// format of old_text & new_text: each is 4000 bytes long. +// This represents 80 characters wide by 25 high, with +// each character being 2 bytes. The first by is the +// character value, the second is the attribute byte. +// I currently don't handle the attribute byte. +// +// cursor_x: new x location of cursor +// cursor_y: new y location of cursor + +void bx_rfb_gui_c::text_update(Bit8u *old_text, Bit8u *new_text, unsigned long cursor_x, unsigned long cursor_y, bx_vga_tminfo_t tm_info, unsigned nrows) +{ + unsigned char *old_line, *new_line; + unsigned char cAttr, cChar; + unsigned int curs, hchars, offset, rows, x, y, xc, yc; + bx_bool force_update=0; + + UNUSED(nrows); + + if(charmap_updated) { + force_update = 1; + charmap_updated = 0; + } + + // first invalidate character at previous and new cursor location + if ( (rfbCursorY < text_rows) && (rfbCursorX < text_cols) ) { + curs = rfbCursorY * tm_info.line_offset + rfbCursorX * 2; + old_text[curs] = ~new_text[curs]; + } + if((tm_info.cs_start <= tm_info.cs_end) && (tm_info.cs_start < font_height) && + (cursor_y < text_rows) && (cursor_x < text_cols)) { + curs = cursor_y * tm_info.line_offset + cursor_x * 2; + old_text[curs] = ~new_text[curs]; + } else { + curs = 0xffff; + } + + rows = text_rows; + y = 0; + do { + hchars = text_cols; + new_line = new_text; + old_line = old_text; + offset = y * tm_info.line_offset; + yc = y * font_height + rfbHeaderbarY; + x = 0; + do { + if (force_update || (old_text[0] != new_text[0]) + || (old_text[1] != new_text[1])) { + cChar = new_text[0]; + cAttr = new_text[1]; + xc = x * 8; + DrawChar(xc, yc, 8, font_height, 0, (char *)&vga_charmap[cChar<<5], cAttr); + if(yc < rfbUpdateRegion.y) rfbUpdateRegion.y = yc; + if((yc + font_height - rfbUpdateRegion.y) > rfbUpdateRegion.height) rfbUpdateRegion.height = (yc + font_height - rfbUpdateRegion.y); + if(xc < rfbUpdateRegion.x) rfbUpdateRegion.x = xc; + if((xc + 8 - rfbUpdateRegion.x) > rfbUpdateRegion.width) rfbUpdateRegion.width = (xc + 8 - rfbUpdateRegion.x); + rfbUpdateRegion.updated = true; + if (offset == curs) { + cAttr = ((cAttr >> 4) & 0xF) + ((cAttr & 0xF) << 4); + DrawChar(xc, yc + tm_info.cs_start, 8, tm_info.cs_end - tm_info.cs_start + 1, + tm_info.cs_start, (char *)&vga_charmap[cChar<<5], cAttr); + } + } + x++; + new_text+=2; + old_text+=2; + offset+=2; + } while (--hchars); + y++; + new_text = new_line + tm_info.line_offset; + old_text = old_line + tm_info.line_offset; + } while (--rows); + + rfbCursorX = cursor_x; + rfbCursorY = cursor_y; +} + + int +bx_rfb_gui_c::get_clipboard_text(Bit8u **bytes, Bit32s *nbytes) +{ + return 0; +} + + int +bx_rfb_gui_c::set_clipboard_text(char *text_snapshot, Bit32u len) +{ + return 0; +} + + +// ::PALETTE_CHANGE() +// +// Allocate a color in the native GUI, for this color, and put +// it in the colormap location 'index'. +// returns: 0=no screen update needed (color map change has direct effect) +// 1=screen updated needed (redraw using current colormap) + +bx_bool bx_rfb_gui_c::palette_change(unsigned index, unsigned red, unsigned green, unsigned blue) +{ + rfbPallet[index] = (((red * 7 + 127) / 255) << 0) | (((green * 7 + 127) / 255) << 3) | (((blue * 3 + 127) / 255) << 6); + return(1); +} + + +// ::GRAPHICS_TILE_UPDATE() +// +// Called to request that a tile of graphics be drawn to the +// screen, since info in this region has changed. +// +// tile: array of 8bit values representing a block of pixels with +// dimension equal to the 'tilewidth' & 'tileheight' parameters to +// ::specific_init(). Each value specifies an index into the +// array of colors you allocated for ::palette_change() +// x0: x origin of tile +// y0: y origin of tile +// +// note: origin of tile and of window based on (0,0) being in the upper +// left of the window. +void bx_rfb_gui_c::graphics_tile_update(Bit8u *tile, unsigned x0, unsigned y0) +{ + UpdateScreen(tile, x0, y0 + rfbHeaderbarY, rfbTileX, rfbTileY, false); + if(x0 < rfbUpdateRegion.x) rfbUpdateRegion.x = x0; + if((y0 + rfbHeaderbarY) < rfbUpdateRegion.y) rfbUpdateRegion.y = y0 + rfbHeaderbarY; + if(((y0 + rfbHeaderbarY + rfbTileY) - rfbUpdateRegion.y) > rfbUpdateRegion.height) rfbUpdateRegion.height = ((y0 + rfbHeaderbarY + rfbTileY) - rfbUpdateRegion.y); + if(((x0 + rfbTileX) - rfbUpdateRegion.x) > rfbUpdateRegion.width) rfbUpdateRegion.width = ((x0 + rfbTileX) - rfbUpdateRegion.x); + rfbUpdateRegion.updated = true; +} + + + +// ::DIMENSION_UPDATE() +// +// Called when the VGA mode changes it's X,Y dimensions. +// Resize the window to this size, but you need to add on +// the height of the headerbar to the Y value. +// +// x: new VGA x size +// y: new VGA y size (add headerbar_y parameter from ::specific_init(). +// fheight: new VGA character height in text mode +// fwidth : new VGA character width in text mode +// bpp : bits per pixel in graphics mode + + void +bx_rfb_gui_c::dimension_update(unsigned x, unsigned y, unsigned fheight, unsigned fwidth, unsigned bpp) +{ + if (bpp > 8) { + BX_PANIC(("%d bpp graphics mode not supported yet", bpp)); + } + if (fheight > 0) { + font_height = fheight; + font_width = fwidth; + text_cols = x / fwidth; + text_rows = y / fheight; + } else { + if ((x > 640) || (y > 480)) { + BX_PANIC(("dimension_update(): RFB doesn't support graphics modes > 640x480 (%dx%d)", x, y)); + } + } +} + + +// ::CREATE_BITMAP() +// +// Create a monochrome bitmap of size 'xdim' by 'ydim', which will +// be drawn in the headerbar. Return an integer ID to the bitmap, +// with which the bitmap can be referenced later. +// +// bmap: packed 8 pixels-per-byte bitmap. The pixel order is: +// bit0 is the left most pixel, bit7 is the right most pixel. +// xdim: x dimension of bitmap +// ydim: y dimension of bitmap + +unsigned bx_rfb_gui_c::create_bitmap(const unsigned char *bmap, unsigned xdim, unsigned ydim) +{ + if(rfbBitmapCount >= BX_MAX_PIXMAPS) { + fprintf(stderr, "# RFB: too many pixmaps.\n"); + return 0; + } + rfbBitmaps[rfbBitmapCount].bmap = (char *)malloc((xdim * ydim) / 8); + rfbBitmaps[rfbBitmapCount].xdim = xdim; + rfbBitmaps[rfbBitmapCount].ydim = ydim; + memcpy(rfbBitmaps[rfbBitmapCount].bmap, bmap, (xdim * ydim) / 8); + + rfbBitmapCount++; + return(rfbBitmapCount - 1); +} + + +// ::HEADERBAR_BITMAP() +// +// Called to install a bitmap in the bochs headerbar (toolbar). +// +// bmap_id: will correspond to an ID returned from +// ::create_bitmap(). 'alignment' is either BX_GRAVITY_LEFT +// or BX_GRAVITY_RIGHT, meaning install the bitmap in the next +// available leftmost or rightmost space. +// alignment: is either BX_GRAVITY_LEFT or BX_GRAVITY_RIGHT, +// meaning install the bitmap in the next +// available leftmost or rightmost space. +// f: a 'C' function pointer to callback when the mouse is clicked in +// the boundaries of this bitmap. + +unsigned bx_rfb_gui_c::headerbar_bitmap(unsigned bmap_id, unsigned alignment, void (*f)(void)) +{ + int hb_index; + + if((rfbHeaderbarBitmapCount + 1) > BX_MAX_HEADERBAR_ENTRIES) { + return 0; + } + + rfbHeaderbarBitmapCount++; + hb_index = rfbHeaderbarBitmapCount - 1; + rfbHeaderbarBitmaps[hb_index].index = bmap_id; + rfbHeaderbarBitmaps[hb_index].alignment = alignment; + rfbHeaderbarBitmaps[hb_index].f = f; + if (alignment == BX_GRAVITY_LEFT) { + rfbHeaderbarBitmaps[hb_index].xorigin = rfbOriginLeft; + rfbHeaderbarBitmaps[hb_index].yorigin = 0; + rfbOriginLeft += rfbBitmaps[bmap_id].xdim; + } else { // BX_GRAVITY_RIGHT + rfbOriginRight += rfbBitmaps[bmap_id].xdim; + rfbHeaderbarBitmaps[hb_index].xorigin = rfbOriginRight; + rfbHeaderbarBitmaps[hb_index].yorigin = 0; + } + return hb_index; +} + + +// ::SHOW_HEADERBAR() +// +// Show (redraw) the current headerbar, which is composed of +// currently installed bitmaps. + +void bx_rfb_gui_c::show_headerbar(void) +{ + char *newBits; + unsigned int i, xorigin; + + newBits = (char *)malloc(rfbDimensionX * rfbHeaderbarY); + memset(newBits, 0, (rfbDimensionX * rfbHeaderbarY)); + DrawBitmap(0, 0, rfbDimensionX, rfbHeaderbarY, newBits, (char)0xf0, false); + for(i = 0; i < rfbHeaderbarBitmapCount; i++) { + if(rfbHeaderbarBitmaps[i].alignment == BX_GRAVITY_LEFT) { + xorigin = rfbHeaderbarBitmaps[i].xorigin; + } else { + xorigin = rfbDimensionX - rfbHeaderbarBitmaps[i].xorigin; + } + DrawBitmap(xorigin, 0, rfbBitmaps[rfbHeaderbarBitmaps[i].index].xdim, rfbBitmaps[rfbHeaderbarBitmaps[i].index].ydim, rfbBitmaps[rfbHeaderbarBitmaps[i].index].bmap, (char)0xf0, false); + } + free(newBits); +} + + +// ::REPLACE_BITMAP() +// +// Replace the bitmap installed in the headerbar ID slot 'hbar_id', +// with the one specified by 'bmap_id'. 'bmap_id' will have +// been generated by ::create_bitmap(). The old and new bitmap +// must be of the same size. This allows the bitmap the user +// sees to change, when some action occurs. For example when +// the user presses on the floppy icon, it then displays +// the ejected status. +// +// hbar_id: headerbar slot ID +// bmap_id: bitmap ID + +void bx_rfb_gui_c::replace_bitmap(unsigned hbar_id, unsigned bmap_id) +{ + rfbHeaderbarBitmaps[hbar_id].index = bmap_id; +} + + +// ::EXIT() +// +// Called before bochs terminates, to allow for a graceful +// exit from the native GUI mechanism. +void bx_rfb_gui_c::exit(void) +{ + unsigned int i; + keep_alive = false; + StopWinsock(); + free(rfbScreen); + for(i = 0; i < rfbBitmapCount; i++) { + free(rfbBitmaps[i].bmap); + } + fprintf(stderr, "# RFB: bx_rfb_gui_c::exit()\n"); +} + +/* +* ReadExact reads an exact number of bytes on a TCP socket. Returns 1 if +* those bytes have been read, 0 if the other end has closed, or -1 if an error +* occurred (errno is set to ETIMEDOUT if it timed out). +*/ + +int ReadExact(int sock, char *buf, int len) +{ + int n; + + while (len > 0) { + n = recv(sock, buf, len, 0); + if (n > 0) { + buf += n; + len -= n; + } else { + return n; + } + } + return 1; +} + +/* +* WriteExact writes an exact number of bytes on a TCP socket. Returns 1 if +* those bytes have been written, or -1 if an error occurred (errno is set to +* ETIMEDOUT if it timed out). +*/ + +int WriteExact(int sock, char *buf, int len) +{ + int n; + + while (len > 0) { + n = send(sock, buf, len,0); + + if (n > 0) { + buf += n; + len -= n; + } else if (n == 0) { + fprintf(stderr,"WriteExact: write returned 0?\n"); + return n; + } else { + return n; + } + } + return 1; +} + +void DrawBitmap(int x, int y, int width, int height, char *bmap, char color, bool update_client) +{ + int i; + unsigned char *newBits; + char fgcolor, bgcolor; + char vgaPallet[] = { (char)0x00, //Black + (char)0x01, //Dark Blue + (char)0x02, //Dark Green + (char)0x03, //Dark Cyan + (char)0x04, //Dark Red + (char)0x05, //Dark Magenta + (char)0x06, //Brown + (char)0x07, //Light Gray + (char)0x38, //Dark Gray + (char)0x09, //Light Blue + (char)0x12, //Green + (char)0x1B, //Cyan + (char)0x24, //Light Red + (char)0x2D, //Magenta + (char)0x36, //Yellow + (char)0x3F //White + }; + + bgcolor = vgaPallet[(color >> 4) & 0xF]; + fgcolor = vgaPallet[color & 0xF]; + newBits = (unsigned char *)malloc(width * height); + memset(newBits, 0, (width * height)); + for(i = 0; i < (width * height) / 8; i++) { + newBits[i * 8 + 0] = (bmap[i] & 0x01) ? fgcolor : bgcolor; + newBits[i * 8 + 1] = (bmap[i] & 0x02) ? fgcolor : bgcolor; + newBits[i * 8 + 2] = (bmap[i] & 0x04) ? fgcolor : bgcolor; + newBits[i * 8 + 3] = (bmap[i] & 0x08) ? fgcolor : bgcolor; + newBits[i * 8 + 4] = (bmap[i] & 0x10) ? fgcolor : bgcolor; + newBits[i * 8 + 5] = (bmap[i] & 0x20) ? fgcolor : bgcolor; + newBits[i * 8 + 6] = (bmap[i] & 0x40) ? fgcolor : bgcolor; + newBits[i * 8 + 7] = (bmap[i] & 0x80) ? fgcolor : bgcolor; + } + UpdateScreen(newBits, x, y, width, height, update_client); + //DrawColorPallet(); + free(newBits); +} + +void DrawChar(int x, int y, int width, int height, int fonty, char *bmap, char color) +{ + static unsigned char newBits[8 * 32]; + unsigned char mask; + int bytes = width * height; + char fgcolor, bgcolor; + char vgaPallet[] = { (char)0x00, //Black + (char)0x01, //Dark Blue + (char)0x02, //Dark Green + (char)0x03, //Dark Cyan + (char)0x04, //Dark Red + (char)0x05, //Dark Magenta + (char)0x06, //Brown + (char)0x07, //Light Gray + (char)0x38, //Dark Gray + (char)0x09, //Light Blue + (char)0x12, //Green + (char)0x1B, //Cyan + (char)0x24, //Light Red + (char)0x2D, //Magenta + (char)0x36, //Yellow + (char)0x3F //White + }; + + bgcolor = vgaPallet[(color >> 4) & 0xF]; + fgcolor = vgaPallet[color & 0xF]; + + for(int i = 0; i < bytes; i+=width) { + mask = 0x80; + for(int j = 0; j < width; j++) { + newBits[i + j] = (bmap[fonty] & mask) ? fgcolor : bgcolor; + mask >>= 1; + } + fonty++; + } + UpdateScreen(newBits, x, y, width, height, false); + //DrawColorPallet(); +} + +void DrawColorPallet() +{ + unsigned char bits[100]; + int x = 0, y = 0, c; + for(c = 0; c < 256; c++) { + memset(&bits, rfbPallet[c], 100); + UpdateScreen(bits, x, y, 10, 10, false); + x += 10; + if(x > 70) { + y += 10; + x = 0; + } + } +} + +void UpdateScreen(unsigned char *newBits, int x, int y, int width, int height, bool update_client) +{ + int i, c; + for(i = 0; i < height; i++) { + for(c = 0; c < width; c++) { + newBits[(i * width) + c] = rfbPallet[newBits[(i * width) + c]]; + } + memcpy(&rfbScreen[y * rfbDimensionX + x], &newBits[i * width], width); + y++; + } + if(update_client) { + if(sGlobal == -1) return; + rfbFramebufferUpdateMsg fum; + rfbFramebufferUpdateRectHeader furh; + fum.type = rfbFramebufferUpdate; + fum.nRects = Swap16IfLE(1); + WriteExact(sGlobal, (char *)&fum, sz_rfbFramebufferUpdateMsg); + furh.r.x = Swap16IfLE(x); + furh.r.y = Swap16IfLE((y - i)); + furh.r.w = Swap16IfLE((short)width); + furh.r.h = Swap16IfLE((short)height); + furh.encoding = Swap32IfLE(rfbEncodingRaw); + WriteExact(sGlobal, (char *)&furh, sz_rfbFramebufferUpdateRectHeader); + WriteExact(sGlobal, (char *)newBits, width * height); + } +} + +void SendUpdate(int x, int y, int width, int height) +{ + char *newBits; + int i; + + if(x < 0 || y < 0 || (x + width) > rfbDimensionX || (y + height) > rfbDimensionY) { + fprintf(stderr, "# RFB: Dimensions out of bounds. x=%i y=%i w=%i h=%i\n", x, y, width, height); + } + if(sGlobal != -1) { + rfbFramebufferUpdateMsg fum; + rfbFramebufferUpdateRectHeader furh; + + fum.type = rfbFramebufferUpdate; + fum.nRects = Swap16IfLE(1); + + furh.r.x = Swap16IfLE(x); + furh.r.y = Swap16IfLE(y); + furh.r.w = Swap16IfLE((short)width); + furh.r.h = Swap16IfLE((short)height); + furh.encoding = Swap32IfLE(rfbEncodingRaw); + + newBits = (char *)malloc(width * height); + for(i = 0; i < height; i++) { + memcpy(&newBits[i * width], &rfbScreen[y * rfbDimensionX + x], width); + y++; + } + + WriteExact(sGlobal, (char *)&fum, sz_rfbFramebufferUpdateMsg); + WriteExact(sGlobal, (char *)&furh, sz_rfbFramebufferUpdateRectHeader); + WriteExact(sGlobal, (char *)newBits, width * height); + + free(newBits); + } +} + +void StartThread() +{ +#ifdef WIN32 + _beginthread(ServerThreadInit, 0, NULL); +#else + pthread_t thread; + pthread_create(&thread, NULL, (void *(*)(void *))&ServerThreadInit, NULL); +#endif +} + +/***********************/ +/* Keyboard Definitons */ +/* And */ +/* Functions */ +/***********************/ + +#define XK_space 0x020 +#define XK_asciitilde 0x07e + +#define XK_dead_grave 0xFE50 +#define XK_dead_acute 0xFE51 +#define XK_dead_circumflex 0xFE52 +#define XK_dead_tilde 0xFE53 + +#define XK_BackSpace 0xFF08 +#define XK_Tab 0xFF09 +#define XK_Linefeed 0xFF0A +#define XK_Clear 0xFF0B +#define XK_Return 0xFF0D +#define XK_Pause 0xFF13 +#define XK_Scroll_Lock 0xFF14 +#define XK_Sys_Req 0xFF15 +#define XK_Escape 0xFF1B + +#define XK_Delete 0xFFFF + +#define XK_Home 0xFF50 +#define XK_Left 0xFF51 +#define XK_Up 0xFF52 +#define XK_Right 0xFF53 +#define XK_Down 0xFF54 +#define XK_Page_Up 0xFF55 +#define XK_Page_Down 0xFF56 +#define XK_End 0xFF57 +#define XK_Begin 0xFF58 + +#define XK_Select 0xFF60 +#define XK_Print 0xFF61 +#define XK_Execute 0xFF62 +#define XK_Insert 0xFF63 + +#define XK_Cancel 0xFF69 +#define XK_Help 0xFF6A +#define XK_Break 0xFF6B +#define XK_Num_Lock 0xFF7F + +#define XK_KP_Space 0xFF80 +#define XK_KP_Tab 0xFF89 +#define XK_KP_Enter 0xFF8D + +#define XK_KP_Home 0xFF95 +#define XK_KP_Left 0xFF96 +#define XK_KP_Up 0xFF97 +#define XK_KP_Right 0xFF98 +#define XK_KP_Down 0xFF99 +#define XK_KP_Prior 0xFF9A +#define XK_KP_Page_Up 0xFF9A +#define XK_KP_Next 0xFF9B +#define XK_KP_Page_Down 0xFF9B +#define XK_KP_End 0xFF9C +#define XK_KP_Begin 0xFF9D +#define XK_KP_Insert 0xFF9E +#define XK_KP_Delete 0xFF9F +#define XK_KP_Equal 0xFFBD +#define XK_KP_Multiply 0xFFAA +#define XK_KP_Add 0xFFAB +#define XK_KP_Separator 0xFFAC +#define XK_KP_Subtract 0xFFAD +#define XK_KP_Decimal 0xFFAE +#define XK_KP_Divide 0xFFAF + +#define XK_KP_F1 0xFF91 +#define XK_KP_F2 0xFF92 +#define XK_KP_F3 0xFF93 +#define XK_KP_F4 0xFF94 + +#define XK_KP_0 0xFFB0 +#define XK_KP_1 0xFFB1 +#define XK_KP_2 0xFFB2 +#define XK_KP_3 0xFFB3 +#define XK_KP_4 0xFFB4 +#define XK_KP_5 0xFFB5 +#define XK_KP_6 0xFFB6 +#define XK_KP_7 0xFFB7 +#define XK_KP_8 0xFFB8 +#define XK_KP_9 0xFFB9 + +#define XK_F1 0xFFBE +#define XK_F2 0xFFBF +#define XK_F3 0xFFC0 +#define XK_F4 0xFFC1 +#define XK_F5 0xFFC2 +#define XK_F6 0xFFC3 +#define XK_F7 0xFFC4 +#define XK_F8 0xFFC5 +#define XK_F9 0xFFC6 +#define XK_F10 0xFFC7 +#define XK_F11 0xFFC8 +#define XK_F12 0xFFC9 +#define XK_F13 0xFFCA +#define XK_F14 0xFFCB +#define XK_F15 0xFFCC +#define XK_F16 0xFFCD +#define XK_F17 0xFFCE +#define XK_F18 0xFFCF +#define XK_F19 0xFFD0 +#define XK_F20 0xFFD1 +#define XK_F21 0xFFD2 +#define XK_F22 0xFFD3 +#define XK_F23 0xFFD4 +#define XK_F24 0xFFD5 + + +#define XK_Shift_L 0xFFE1 +#define XK_Shift_R 0xFFE2 +#define XK_Control_L 0xFFE3 +#define XK_Control_R 0xFFE4 +#define XK_Caps_Lock 0xFFE5 +#define XK_Shift_Lock 0xFFE6 +#define XK_Meta_L 0xFFE7 +#define XK_Meta_R 0xFFE8 +#define XK_Alt_L 0xFFE9 +#define XK_Alt_R 0xFFEA + +Bit32u rfb_ascii_to_key_event[0x5f] = { + // !"#$%&' + BX_KEY_SPACE, + BX_KEY_1, + BX_KEY_SINGLE_QUOTE, + BX_KEY_3, + BX_KEY_4, + BX_KEY_5, + BX_KEY_7, + BX_KEY_SINGLE_QUOTE, + + // ()*+,-./ + BX_KEY_9, + BX_KEY_0, + BX_KEY_8, + BX_KEY_EQUALS, + BX_KEY_COMMA, + BX_KEY_MINUS, + BX_KEY_PERIOD, + BX_KEY_SLASH, + + // 01234567 + BX_KEY_0, + BX_KEY_1, + BX_KEY_2, + BX_KEY_3, + BX_KEY_4, + BX_KEY_5, + BX_KEY_6, + BX_KEY_7, + + // 89:;<=>? + BX_KEY_8, + BX_KEY_9, + BX_KEY_SEMICOLON, + BX_KEY_SEMICOLON, + BX_KEY_COMMA, + BX_KEY_EQUALS, + BX_KEY_PERIOD, + BX_KEY_SLASH, + + // @ABCDEFG + BX_KEY_2, + BX_KEY_A, + BX_KEY_B, + BX_KEY_C, + BX_KEY_D, + BX_KEY_E, + BX_KEY_F, + BX_KEY_G, + + + // HIJKLMNO + BX_KEY_H, + BX_KEY_I, + BX_KEY_J, + BX_KEY_K, + BX_KEY_L, + BX_KEY_M, + BX_KEY_N, + BX_KEY_O, + + + // PQRSTUVW + BX_KEY_P, + BX_KEY_Q, + BX_KEY_R, + BX_KEY_S, + BX_KEY_T, + BX_KEY_U, + BX_KEY_V, + BX_KEY_W, + + // XYZ[\]^_ + BX_KEY_X, + BX_KEY_Y, + BX_KEY_Z, + BX_KEY_LEFT_BRACKET, + BX_KEY_BACKSLASH, + BX_KEY_RIGHT_BRACKET, + BX_KEY_6, + BX_KEY_MINUS, + + // `abcdefg + BX_KEY_GRAVE, + BX_KEY_A, + BX_KEY_B, + BX_KEY_C, + BX_KEY_D, + BX_KEY_E, + BX_KEY_F, + BX_KEY_G, + + // hijklmno + BX_KEY_H, + BX_KEY_I, + BX_KEY_J, + BX_KEY_K, + BX_KEY_L, + BX_KEY_M, + BX_KEY_N, + BX_KEY_O, + + // pqrstuvw + BX_KEY_P, + BX_KEY_Q, + BX_KEY_R, + BX_KEY_S, + BX_KEY_T, + BX_KEY_U, + BX_KEY_V, + BX_KEY_W, + + // xyz{|}~ + BX_KEY_X, + BX_KEY_Y, + BX_KEY_Z, + BX_KEY_LEFT_BRACKET, + BX_KEY_BACKSLASH, + BX_KEY_RIGHT_BRACKET, + BX_KEY_GRAVE + }; + +void rfbKeyPressed(Bit32u key, int press_release) +{ + Bit32u key_event; + + if((key >= XK_space) && (key <= XK_asciitilde)) { + key_event = rfb_ascii_to_key_event[key - XK_space]; + } else { + switch (key) { + case XK_KP_1: +#ifdef XK_KP_End + case XK_KP_End: +#endif + key_event = BX_KEY_KP_END; break; + + case XK_KP_2: +#ifdef XK_KP_Down + case XK_KP_Down: +#endif + key_event = BX_KEY_KP_DOWN; break; + + case XK_KP_3: +#ifdef XK_KP_Page_Down + case XK_KP_Page_Down: +#endif + key_event = BX_KEY_KP_PAGE_DOWN; break; + + case XK_KP_4: +#ifdef XK_KP_Left + case XK_KP_Left: +#endif + key_event = BX_KEY_KP_LEFT; break; + + case XK_KP_5: +#ifdef XK_KP_Begin + case XK_KP_Begin: +#endif + key_event = BX_KEY_KP_5; break; + + case XK_KP_6: +#ifdef XK_KP_Right + case XK_KP_Right: +#endif + key_event = BX_KEY_KP_RIGHT; break; + + case XK_KP_7: +#ifdef XK_KP_Home + case XK_KP_Home: +#endif + key_event = BX_KEY_KP_HOME; break; + + case XK_KP_8: +#ifdef XK_KP_Up + case XK_KP_Up: +#endif + key_event = BX_KEY_KP_UP; break; + + case XK_KP_9: +#ifdef XK_KP_Page_Up + case XK_KP_Page_Up: +#endif + key_event = BX_KEY_KP_PAGE_UP; break; + + case XK_KP_0: +#ifdef XK_KP_Insert + case XK_KP_Insert: +#endif + key_event = BX_KEY_KP_INSERT; break; + + case XK_KP_Decimal: +#ifdef XK_KP_Delete + case XK_KP_Delete: +#endif + key_event = BX_KEY_KP_DELETE; break; + +#ifdef XK_KP_Enter + case XK_KP_Enter: key_event = BX_KEY_KP_ENTER; break; +#endif + + case XK_KP_Subtract: key_event = BX_KEY_KP_SUBTRACT; break; + case XK_KP_Add: key_event = BX_KEY_KP_ADD; break; + + case XK_KP_Multiply: key_event = BX_KEY_KP_MULTIPLY; break; + case XK_KP_Divide: key_event = BX_KEY_KP_DIVIDE; break; + + + case XK_Up: key_event = BX_KEY_UP; break; + case XK_Down: key_event = BX_KEY_DOWN; break; + case XK_Left: key_event = BX_KEY_LEFT; break; + case XK_Right: key_event = BX_KEY_RIGHT; break; + + + case XK_Delete: key_event = BX_KEY_DELETE; break; + case XK_BackSpace: key_event = BX_KEY_BACKSPACE; break; + case XK_Tab: key_event = BX_KEY_TAB; break; +#ifdef XK_ISO_Left_Tab + case XK_ISO_Left_Tab: key_event = BX_KEY_TAB; break; +#endif + case XK_Return: key_event = BX_KEY_ENTER; break; + case XK_Escape: key_event = BX_KEY_ESC; break; + case XK_F1: key_event = BX_KEY_F1; break; + case XK_F2: key_event = BX_KEY_F2; break; + case XK_F3: key_event = BX_KEY_F3; break; + case XK_F4: key_event = BX_KEY_F4; break; + case XK_F5: key_event = BX_KEY_F5; break; + case XK_F6: key_event = BX_KEY_F6; break; + case XK_F7: key_event = BX_KEY_F7; break; + case XK_F8: key_event = BX_KEY_F8; break; + case XK_F9: key_event = BX_KEY_F9; break; + case XK_F10: key_event = BX_KEY_F10; break; + case XK_F11: key_event = BX_KEY_F11; break; + case XK_F12: key_event = BX_KEY_F12; break; + case XK_Control_L: key_event = BX_KEY_CTRL_L; break; +#ifdef XK_Control_R + case XK_Control_R: key_event = BX_KEY_CTRL_R; break; +#endif + case XK_Shift_L: key_event = BX_KEY_SHIFT_L; break; + case XK_Shift_R: key_event = BX_KEY_SHIFT_R; break; + case XK_Alt_L: key_event = BX_KEY_ALT_L; break; +#ifdef XK_Alt_R + case XK_Alt_R: key_event = BX_KEY_ALT_R; break; +#endif + case XK_Caps_Lock: key_event = BX_KEY_CAPS_LOCK; break; + case XK_Num_Lock: key_event = BX_KEY_NUM_LOCK; break; +#ifdef XK_Scroll_Lock + case XK_Scroll_Lock: key_event = BX_KEY_SCRL_LOCK; break; +#endif +#ifdef XK_Print + case XK_Print: key_event = BX_KEY_PRINT; break; +#endif +#ifdef XK_Pause + case XK_Pause: key_event = BX_KEY_PAUSE; break; +#endif + + case XK_Insert: key_event = BX_KEY_INSERT; break; + case XK_Home: key_event = BX_KEY_HOME; break; + case XK_End: key_event = BX_KEY_END; break; + case XK_Page_Up: key_event = BX_KEY_PAGE_UP; break; + case XK_Page_Down: key_event = BX_KEY_PAGE_DOWN; break; + + default: + BX_ERROR(("rfbKeyPress(): key %04x unhandled!", key)); + fprintf(stderr, "RFB: rfbKeyPress(): key %04x unhandled!\n", key); + return; + break; + } + } + + if (press_release) key_event |= BX_KEY_RELEASED; + DEV_kbd_gen_scancode(key_event); +} + +void rfbMouseMove(int x, int y, int bmask) +{ + static int oldx = -1; + static int oldy = -1; + int xorigin; + + if (oldx == oldy == -1) { + oldx = x; + oldy = y; + return; + } + if(y > rfbHeaderbarY) { + //DEV_mouse_motion(x, y - rfbHeaderbarY, buttons); + DEV_mouse_motion(x - oldx, oldy - y, bmask); + oldx = x; + oldy = y; + } else { + if (bmask == 1) { + for (unsigned i=0; i<rfbHeaderbarBitmapCount; i++) { + if (rfbHeaderbarBitmaps[i].alignment == BX_GRAVITY_LEFT) + xorigin = rfbHeaderbarBitmaps[i].xorigin; + else + xorigin = rfbDimensionX - rfbHeaderbarBitmaps[i].xorigin; + if ( (x>=xorigin) && (x<(xorigin+int(rfbBitmaps[rfbHeaderbarBitmaps[i].index].xdim))) ) { + rfbHeaderbarBitmaps[i].f(); + return; + } + } + } + } +} + + void +bx_rfb_gui_c::mouse_enabled_changed_specific (bx_bool val) +{ +} + +#endif /* if BX_WITH_RFB */ |