diff -urN -x CVS qemu-clean/configure qemu/configure --- qemu-clean/configure 2006-04-09 23:06:58.000000000 +0400 +++ qemu/configure 2006-04-10 11:08:05.000000000 +0400 @@ -181,6 +181,8 @@ ;; --disable-sdl) sdl="no" ;; + --disable-vnc) vnc="no" + ;; --enable-coreaudio) coreaudio="yes" ;; --enable-alsa) alsa="yes" @@ -240,6 +242,8 @@ echo " --interp-prefix=PREFIX where to find shared libraries, etc." echo " use %M for cpu name [$interp_prefix]" echo " --target-list=LIST set target list [$target_list]" +echo " --disable-vnc disable vnc support (else configure checks" +echo " for libvncserver-config in your PATH)" echo "" echo "kqemu kernel acceleration support:" echo " --disable-kqemu disable kqemu support" @@ -363,6 +367,19 @@ fi ########################################## +# VNC probe + +if test -z "$vnc"; then + +if libvncserver-config --version > /dev/null; then + vnc=yes +else + vnc=no +fi + +fi + +########################################## # SDL probe sdl_too_old=no @@ -448,6 +465,7 @@ echo "gprof enabled $gprof" echo "profiler $profiler" echo "static build $static" +echo "VNC support $vnc" if test "$darwin" = "yes" ; then echo "Cocoa support $cocoa" fi @@ -561,6 +579,8 @@ if test "$darwin" = "yes" ; then echo "CONFIG_DARWIN=yes" >> $config_mak echo "#define CONFIG_DARWIN 1" >> $config_h + echo "#define socklen_t int" >> $config_h + echo "#define sqrtf sqrt" >> $config_h fi if test "$gdbstub" = "yes" ; then echo "CONFIG_GDBSTUB=yes" >> $config_mak @@ -624,6 +644,16 @@ echo "#define _BSD 1" >> $config_h fi +if test "$vnc" = "yes"; then + echo "CONFIG_VNC=yes" >> $config_mak + echo "VNC_CFLAGS=`libvncserver-config --cflags`" >> $config_mak +fi + +if test "$sdl" = "yes"; then + echo "CONFIG_SDL=yes" >> $config_mak + echo "SDL_CFLAGS=`$sdl_config --cflags`" >> $config_mak +fi + for target in $target_list; do target_dir="$target" @@ -735,13 +765,22 @@ echo "#define CONFIG_USER_ONLY 1" >> $config_h fi +if test "$target_user_only" = "no"; then + if test "$vnc" = "yes"; then + echo "#define CONFIG_VNC 1" >> $config_h + echo "CONFIG_VNC=yes" >> $config_mak + echo "VNC_CFLAGS=`libvncserver-config --cflags`" >> $config_mak + echo "VNC_LIBS=`libvncserver-config --libs`" >> $config_mak + fi +fi + if test "$target_cpu" = "arm" -o "$target_cpu" = "armeb" ; then echo "CONFIG_SOFTFLOAT=yes" >> $config_mak echo "#define CONFIG_SOFTFLOAT 1" >> $config_h fi # sdl defines -if test "$target_user_only" = "no"; then +if test "$sdl" = "yes" -a "$target_user_only" = "no"; then if test "$target_softmmu" = "no" -o "$static" = "yes"; then sdl1=$sdl_static else diff -urN -x CVS qemu-clean/hw/pckbd.c qemu/hw/pckbd.c --- qemu-clean/hw/pckbd.c 2006-04-09 23:07:05.000000000 +0400 +++ qemu/hw/pckbd.c 2006-04-10 11:07:37.000000000 +0400 @@ -333,7 +333,11 @@ static void kbd_save(QEMUFile* f, void* opaque) { KBDState *s = (KBDState*)opaque; - + + /* release alt, ctrl */ + kbd_put_keycode(0x38|0x80); /* alt */ + kbd_put_keycode(0x1d|0x80); /* ctrl */ + qemu_put_8s(f, &s->write_cmd); qemu_put_8s(f, &s->status); qemu_put_8s(f, &s->mode); diff -urN -x CVS qemu-clean/keymaps.c qemu/keymaps.c --- qemu-clean/keymaps.c 2006-04-09 23:06:58.000000000 +0400 +++ qemu/keymaps.c 2006-04-10 11:07:37.000000000 +0400 @@ -93,6 +93,12 @@ if (keysym < MAX_NORMAL_KEYCODE) { //fprintf(stderr,"Setting keysym %s (%d) to %d\n",line,keysym,keycode); k->keysym2keycode[keysym] = keycode; +#ifdef KEYBOARD_HANDLE_UPPER_CASE + line[0]=toupper(line[0]); + keysym=get_keysym(line); + if(keysym) + k->keysym2keycode[keysym]=keycode; +#endif } else { if (k->extra_count >= MAX_EXTRA_COUNT) { fprintf(stderr, diff -urN -x CVS qemu-clean/Makefile.target qemu/Makefile.target --- qemu-clean/Makefile.target 2006-04-10 02:03:49.000000000 +0400 +++ qemu/Makefile.target 2006-04-10 11:07:37.000000000 +0400 @@ -345,6 +345,9 @@ ifdef CONFIG_GDBSTUB VL_OBJS+=gdbstub.o endif +ifdef CONFIG_VNC +VL_OBJS+=vnc.o +endif ifdef CONFIG_SDL VL_OBJS+=sdl.o endif @@ -390,7 +393,10 @@ endif $(QEMU_SYSTEM): $(VL_OBJS) libqemu.a - $(CC) $(VL_LDFLAGS) -o $@ $^ $(LIBS) $(SDL_LIBS) $(COCOA_LIBS) $(VL_LIBS) + $(CC) $(VL_LDFLAGS) -o $@ $^ $(LIBS) $(SDL_LIBS) $(COCOA_LIBS) $(VNC_LIBS) $(VL_LIBS) + +vnc.o: vnc.c keymaps.c vnc_keysym.h + $(CC) $(CFLAGS) $(DEFINES) $(VNC_CFLAGS) $(SDL_CFLAGS) -c -o $@ $< cocoa.o: cocoa.m $(CC) $(CFLAGS) $(DEFINES) -c -o $@ $< @@ -401,6 +407,9 @@ sdlaudio.o: sdlaudio.c $(CC) $(CFLAGS) $(DEFINES) $(SDL_CFLAGS) -c -o $@ $< +vl.o: vl.c + $(CC) $(CFLAGS) $(DEFINES) $(SDL_CFLAGS) -c -o $@ $< + depend: $(SRCS) $(CC) -MM $(CFLAGS) $(DEFINES) $^ 1>.depend diff -urN -x CVS qemu-clean/monitor.c qemu/monitor.c --- qemu-clean/monitor.c 2006-04-09 23:06:59.000000000 +0400 +++ qemu/monitor.c 2006-04-10 11:07:37.000000000 +0400 @@ -69,7 +69,10 @@ void term_flush(void) { if (term_outbuf_index > 0) { + if(monitor_hd) qemu_chr_write(monitor_hd, term_outbuf, term_outbuf_index); + else + fwrite(term_outbuf, term_outbuf_index, 1, stderr); term_outbuf_index = 0; } } diff -urN -x CVS qemu-clean/sdl.c qemu/sdl.c --- qemu-clean/sdl.c 2006-04-10 12:10:47.000000000 +0400 +++ qemu/sdl.c 2006-04-10 11:07:37.000000000 +0400 @@ -44,6 +44,10 @@ static SDL_Cursor *sdl_cursor_hidden; static int absolute_enabled = 0; +SDL_PixelFormat* sdl_get_format() { + return screen->format; +} + static void sdl_update(DisplayState *ds, int x, int y, int w, int h) { // printf("updating x=%d y=%d w=%d h=%d\n", x, y, w, h); diff -urN -x CVS qemu-clean/slirp/main.h qemu/slirp/main.h --- qemu-clean/slirp/main.h 2006-04-09 23:07:05.000000000 +0400 +++ qemu/slirp/main.h 2006-04-10 11:07:37.000000000 +0400 @@ -9,6 +9,8 @@ #include #endif +#include + #define TOWRITEMAX 512 extern struct timeval tt; diff -urN -x CVS qemu-clean/vl.c qemu/vl.c --- qemu-clean/vl.c 2006-04-10 12:10:47.000000000 +0400 +++ qemu/vl.c 2006-04-10 11:07:37.000000000 +0400 @@ -72,7 +72,7 @@ #ifdef CONFIG_SDL #ifdef __APPLE__ -#include +#include "SDL.h" #endif #endif /* CONFIG_SDL */ @@ -117,6 +117,8 @@ int bios_size; static DisplayState display_state; int nographic; +int usevnc; /* 1=vnc only, 2=vnc and sdl */ +int vnc_port = 0; const char* keyboard_layout = NULL; int64_t ticks_per_sec; int boot_device = 'c'; @@ -4142,6 +4144,13 @@ "-m megs set virtual RAM size to megs MB [default=%d]\n" "-smp n set the number of CPUs to 'n' [default=1]\n" "-nographic disable graphical output and redirect serial I/Os to console\n" +#ifdef CONFIG_VNC + "-vnc use vnc instead of sdl\n" + "-vncport use this vnc port. Default is auto-choosing\n" +#ifdef CONFIG_SDL + "-vnc-and-sdl use vnc and sdl simultaneously\n" +#endif +#endif #ifndef _WIN32 "-k language use keyboard layout (for example \"fr\" for French)\n" #endif @@ -4267,7 +4276,14 @@ QEMU_OPTION_boot, QEMU_OPTION_snapshot, QEMU_OPTION_m, + QEMU_OPTION_vncport, QEMU_OPTION_nographic, +#ifdef CONFIG_VNC + QEMU_OPTION_vnc, +#ifdef CONFIG_SDL + QEMU_OPTION_vnc_and_sdl, +#endif +#endif #ifdef HAS_AUDIO QEMU_OPTION_audio_help, QEMU_OPTION_soundhw, @@ -4328,7 +4344,14 @@ { "boot", HAS_ARG, QEMU_OPTION_boot }, { "snapshot", 0, QEMU_OPTION_snapshot }, { "m", HAS_ARG, QEMU_OPTION_m }, + { "vncport", HAS_ARG, QEMU_OPTION_vncport }, { "nographic", 0, QEMU_OPTION_nographic }, +#ifdef CONFIG_VNC + { "vnc", 0, QEMU_OPTION_vnc }, +#ifdef CONFIG_SDL + { "vnc-and-sdl", 0, QEMU_OPTION_vnc_and_sdl }, +#endif +#endif { "k", HAS_ARG, QEMU_OPTION_k }, #ifdef HAS_AUDIO { "audio-help", 0, QEMU_OPTION_audio_help }, @@ -4608,6 +4631,7 @@ #endif snapshot = 0; nographic = 0; + usevnc = 0; kernel_filename = NULL; kernel_cmdline = ""; #ifdef TARGET_PPC @@ -4742,6 +4766,16 @@ pstrcpy(serial_devices[0], sizeof(serial_devices[0]), "stdio"); nographic = 1; break; +#ifdef CONFIG_VNC + case QEMU_OPTION_vnc: + usevnc = 1; + break; +#ifdef CONFIG_SDL + case QEMU_OPTION_vnc_and_sdl: + usevnc = 2; + break; +#endif +#endif case QEMU_OPTION_kernel: kernel_filename = optarg; break; @@ -4819,6 +4853,9 @@ exit(1); } break; + case QEMU_OPTION_vncport: + vnc_port = atoi(optarg); + break; case QEMU_OPTION_d: { int mask; @@ -5125,6 +5162,13 @@ if (nographic) { dumb_display_init(ds); } else { + if (usevnc) { +#ifdef CONFIG_VNC + vnc_display_init(ds, (usevnc==2)); +#else + perror("qemu not configured with vnc support"); +#endif + } else { #if defined(CONFIG_SDL) sdl_display_init(ds, full_screen); #elif defined(CONFIG_COCOA) @@ -5133,6 +5177,7 @@ dumb_display_init(ds); #endif } + } monitor_hd = qemu_chr_open(monitor_device); if (!monitor_hd) { diff -urN -x CVS qemu-clean/vl.h qemu/vl.h --- qemu-clean/vl.h 2006-04-10 12:10:47.000000000 +0400 +++ qemu/vl.h 2006-04-10 11:07:37.000000000 +0400 @@ -684,6 +684,9 @@ unsigned long vga_ram_offset, int vga_ram_size, unsigned long vga_bios_offset, int vga_bios_size); +/* vnc.c */ +void vnc_display_init(DisplayState *ds, int useAlsoSDL); + /* cirrus_vga.c */ void pci_cirrus_vga_init(PCIBus *bus, DisplayState *ds, uint8_t *vga_ram_base, unsigned long vga_ram_offset, int vga_ram_size); @@ -757,6 +760,7 @@ /* pckbd.c */ void kbd_init(void); +extern const char* keyboard_layout; /* mc146818rtc.c */ diff -urN -x CVS qemu-clean/vnc.c qemu/vnc.c --- qemu-clean/vnc.c 1970-01-01 04:00:00.000000000 +0400 +++ qemu/vnc.c 2006-04-10 12:08:19.000000000 +0400 @@ -0,0 +1,600 @@ +/* + * QEMU VNC display driver (uses LibVNCServer, based on QEMU SDL driver) + * + * Copyright (c) 2003,2004,2005 Fabrice Bellard, Matthew Mastracci, + * Johannes E. Schindelin, Donald D. Dugger + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#include "vl.h" + +#include + +/* keyboard stuff */ +#include +#include "vnc_keysym.h" +#define KEYBOARD_HANDLE_UPPER_CASE +#include "keymaps.c" + + +#ifndef _WIN32 +#include +#endif + +static rfbScreenInfoPtr screen; +static DisplayState* ds_sdl; +static void* kbd_layout; // TODO: move into rfbClient +static int ctl_keys; // Ctrl+Alt starts calibration + +/* mouse stuff */ + +typedef struct mouse_magic_t { + /* When calibrating, mouse_calibration contains a copy of the + * current frame buffer. After a simulated mouse movement, the + * update function only gets (0,y1,width,y2) as bounding box + * of the changed region, so we refine that with the help of + * this copy, and then update the copy. */ + char* calibration; + /* Mouse handling using VNC used to be wrong, because if moving the + * mouse very fast, the pointer got even faster. The reason for this: + * when the mouse sends a delta of at least 4 (Windows: 3) pixels, + * it is treated as if it were double the amount. I call this the + * sonic wall. */ + int sonic_wall_x; + int sonic_wall_y; + /* Unfortunately, Windows and X behave differently, when the sonic + * wall was reached in one axis, but not the other: Windows treats + * them independently. I call this orthogonal. */ + char sonic_wall_is_orthogonal; + /* last_dy contains the last delta sent on the y axis. We don't + * use the x axis (see mouse_calibration). */ + //static int last_dy=0; +} mouse_magic_t; + +mouse_magic_t* init_mouse_magic() { + mouse_magic_t* ret=(mouse_magic_t*)malloc(sizeof(mouse_magic_t)); + + ret->calibration=0; +#ifdef EXPECT_WINDOWS_GUEST + ret->sonic_wall_x=3; + ret->sonic_wall_y=3; + ret->sonic_wall_is_orthogonal=1; +#else + ret->sonic_wall_x=4; + ret->sonic_wall_y=4; + ret->sonic_wall_is_orthogonal=0; +#endif + return ret; +} + +static void vnc_save(QEMUFile* f,void* opaque) +{ + mouse_magic_t* s=(mouse_magic_t*)opaque; + + qemu_put_be32s(f, &s->sonic_wall_x); + qemu_put_be32s(f, &s->sonic_wall_y); + qemu_put_8s(f, &s->sonic_wall_is_orthogonal); +} + +static int vnc_load(QEMUFile* f,void* opaque,int version_id) +{ + mouse_magic_t* s=(mouse_magic_t*)opaque; + + if (version_id != 1) + return -EINVAL; + + qemu_get_be32s(f, &s->sonic_wall_x); + qemu_get_be32s(f, &s->sonic_wall_y); + qemu_get_8s(f, &s->sonic_wall_is_orthogonal); + + return 0; +} + +static mouse_magic_t* mouse_magic; + +typedef struct { + int x,y,w,h; +} rectangle_t; +/* In order to calibrate the mouse, we have to know about the bounding boxes + * of the last changes. */ +static rectangle_t last_update, before_update; +static int updates_since_mouse=0; + +int mouse_maxx; +int mouse_maxy; +static int mouse_x,mouse_y; +static int new_mouse_x,new_mouse_y,new_mouse_z,new_mouse_buttons; + +static void init_mouse(int max_x,int max_y) { + mouse_maxx=max_x - 1; + mouse_maxy=max_y - 1; + mouse_x=new_mouse_x=max_x/2; + mouse_y=new_mouse_y=max_y/2; + new_mouse_z=new_mouse_buttons=0; + mouse_magic->calibration = 0; +} + +static void mouse_refresh() { + int dx=0,dy=0,dz=new_mouse_z; + static int counter=1; + + /* + * Simulate lifting the mouse by pressing left together + * e.g. don't send mouse events. + */ +#if 0 + if(1) { + if(dx!=0) { + if(1 || abs(dx)<10) { dx=(dx>0?2:-2); mouse_x-=dx/2; } + } + if(dy!=0) { + if(1 || abs(dy)<10) { dy=(dy>0?2:-2); mouse_y-=dy/2; } + } + } else + if(mouse_magic->sonic_wall_is_orthogonal) { + if(abs(dx)>=mouse_magic->sonic_wall_x) { dx/=2; mouse_x+=dx; } + if(abs(dy)>=mouse_magic->sonic_wall_y) { dy/=2; mouse_y+=dy; } + } else { + if(abs(dx)>=mouse_magic->sonic_wall_x || abs(dy)>=mouse_magic->sonic_wall_y) { + dx/=2; mouse_x+=dx; + dy/=2; mouse_y+=dy; + } + } +#endif + //fprintf(stderr,"sending mouse event %d,%d\n",dx,dy); + if (kbd_mouse_is_absolute()) { + dx = new_mouse_x * 0x7FFF / screen->width; + dy = new_mouse_y * 0x7FFF / screen->height; + } else { + if (ctl_keys == 3) { + mouse_x = new_mouse_x; + mouse_y = new_mouse_y; + return; + } + counter++; +// if(!mouse_magic->calibration && counter>=2) { counter=0; return; } + + dx=new_mouse_x-mouse_x; + dy=new_mouse_y-mouse_y; + } + +// printf("%i \n",new_mouse_buttons); + kbd_mouse_event(dx,dy,dz,new_mouse_buttons); + mouse_x+=dx; + mouse_y+=dy; + new_mouse_z=0; + + updates_since_mouse=0; +} + +static int calibration_step=0; +//static int calibration_count=0; + +static void mouse_find_bounding_box_of_difference(int* x,int* y,int* w,int* h) { + int i,j,X=*x,Y=*y,W=*w,H=*h; + int bpp=screen->depth/8; + + *x=screen->width; *w=-*x; + *y=screen->height; *h=-*y; + for(i=X;ipaddedWidthInBytes; + if(memcmp(mouse_magic->calibration+offset,screen->frameBuffer+offset,bpp)) { + if(i<((*x))) { (*w)+=(*x)-i; (*x)=i; } + if(i>(*x)+(*w)) (*w)=i-(*x); + if(j<(*y)) { (*h)+=(*y)-j; (*y)=j; } + if(j>(*y)+(*h)) (*h)=j-(*y); + } + } + if(h>0) + memcpy(mouse_magic->calibration+Y*screen->paddedWidthInBytes, + screen->frameBuffer+Y*screen->paddedWidthInBytes, + H*screen->paddedWidthInBytes); +} + +static void start_mouse_calibration() { + int size = screen->height*screen->paddedWidthInBytes; + if(mouse_magic->calibration) + free(mouse_magic->calibration); + mouse_magic->calibration = malloc(size); + memcpy(mouse_magic->calibration, screen->frameBuffer, size); + calibration_step=0; + // calibration_count=-1; + //calibration_count=1000; updates_since_mouse=1; + term_printf("Starting mouse calibration:\n"); +} + +static void stop_mouse_calibration() { + if(mouse_magic->calibration) + free(mouse_magic->calibration); + mouse_magic->calibration = 0; +} + +#if 0 +static void adjust_last_update(int x,int y,int w,int h,char enlarge) +{ + if(enlarge && !(last_update.w<=0 || last_update.h<=0)) { + if(w<=0||h<=0) + return; + if(xlast_update.x+last_update.w) { last_update.w=x+w-last_update.w; } + if(ylast_update.y+last_update.h) { last_update.h=y+h-last_update.h; } + } else { + last_update.x=x; + last_update.y=y; + last_update.w=w; + last_update.h=h; + } +} +#endif + +static void mouse_calibration_update(int x,int y,int w,int h) { + mouse_find_bounding_box_of_difference(&x,&y,&w,&h); + if(w<=0 || h<=0) + return; + last_update.x=x; + last_update.y=y; + last_update.w=w; + last_update.h=h; + updates_since_mouse++; +#if 0 + adjust_last_update(x,y,w,h,(updates_since_mouse>1)); + if(last_dy<0) { + fprintf(stderr,"\t\t\tcount: %d, dy: %d, real_dy: %d\n", + updates_since_mouse,last_dy,y-before_update.y); + } else if (last_dy>0) { + fprintf(stderr,"\t\t\tcount: %d, dy: %d, real_dy: %d\n", + updates_since_mouse,last_dy,y+h-before_update.y-before_update.h); + } //else + fprintf(stderr,"got update with last_dy=%d: %d,%d - %d,%d\n", + last_dy,x,y,w,h); +#endif +} + +static void mouse_calibration_refresh() { + static rectangle_t cursor; + static int x,y; + static int idle_counter; + //fprintf(stderr,"refresh: %d\n",updates_since_mouse); + + if(calibration_step==0) + idle_counter=0; + else { + idle_counter++; + if(idle_counter<10) + return; + idle_counter=0; + if(updates_since_mouse!=1) { + term_printf("Calibration failed: updates=%d\n",updates_since_mouse); + stop_mouse_calibration(); + return; + } + } + /* fprintf(stderr,"step: %d\n",calibration_step); + fprintf(stderr,"-%d,%d,%d,%d\n", + before_update.x,before_update.y,before_update.w,before_update.h); + fprintf(stderr,"+%d,%d,%d,%d\n", + last_update.x,last_update.y,last_update.w,last_update.h); + */ + if(calibration_step==0) { + x=0; y=1; + kbd_mouse_event(0,-1,0,0); + calibration_step++; + } else if(calibration_step==1) { + // find out the initial position of the cursor + cursor=last_update; + cursor.h--; + calibration_step++; + mouse_magic->sonic_wall_y=-1; + last_update=cursor; + x=0; y=2; + goto move_calibrate; + } else if(calibration_step==2) { + // find out the sonic_wall + if(last_update.y==before_update.y-2*y) { + mouse_magic->sonic_wall_y=y; + // test orthogonality + calibration_step++; + x=mouse_magic->sonic_wall_y+1; y=1; + goto move_calibrate; + } else if(last_update.y<=2) { + if(y<6) + term_printf("Calibration failed: not enough head room!\n"); + else + term_printf("Calibration finished.\n"); + mouse_magic->sonic_wall_x=mouse_magic->sonic_wall_y=32768; + goto stop_calibration; + } else if(last_update.y!=before_update.y-y) { + if(last_update.y==before_update.y-y/2) { + term_printf("XP detected!\n"); + } else { + term_printf("Calibration failed: delta=%d (expected: %d)\n",last_update.y-before_update.y,-y); + goto stop_calibration; + } + } else { + y++; +move_calibrate: + kbd_mouse_event(-x,-y,0,0); + before_update=last_update; + } + } else if(calibration_step==3) { + if(last_update.y==before_update.y-2) + mouse_magic->sonic_wall_is_orthogonal=0; + else if(last_update.y==before_update.y-1) + mouse_magic->sonic_wall_is_orthogonal=-1; + else + term_printf("Calibration failed: no clue of orthogonal.\n"); + mouse_magic->sonic_wall_x=mouse_magic->sonic_wall_y; + if(last_update.x==before_update.x-mouse_magic->sonic_wall_x) + mouse_magic->sonic_wall_x++; + else if(last_update.x!=before_update.x-x*2) + term_printf("Calibration failed: could not determine horizontal sonic wall x\n"); + term_printf("Calibration finished\n"); +stop_calibration: + /* + mouse_x+=last_update.x-cursor.x; + mouse_y+=last_update.y-cursor.y-1; + */ + mouse_x=last_update.x; + mouse_y=last_update.y; + stop_mouse_calibration(); + } + updates_since_mouse=0; +} + +/* end of mouse stuff */ + +static void vnc_update(DisplayState *ds, int x, int y, int w, int h) +{ + if(ds_sdl) + ds_sdl->dpy_update(ds_sdl,x,y,w,h); + if(0) term_printf("updating x=%d y=%d w=%d h=%d\n", x, y, w, h); + rfbMarkRectAsModified(screen,x,y,x+w,y+h); + if(mouse_magic->calibration) { + mouse_calibration_update(x,y,w,h); + } +} + +#ifdef CONFIG_SDL +#include +extern SDL_PixelFormat* sdl_get_format(); +#endif +extern int vnc_port; + +static void vnc_resize(DisplayState *ds, int w, int h) +{ + int depth = screen->bitsPerPixel; + rfbClientIteratorPtr iter; + rfbClientPtr cl; + + if(w==screen->width && h==screen->height) + return; + + if(ds_sdl) { +#ifdef CONFIG_SDL + SDL_PixelFormat* sdl_format; + ds_sdl->dpy_resize(ds_sdl,w,h); + ds->data = ds_sdl->data; + ds->linesize = screen->paddedWidthInBytes = ds_sdl->linesize; + screen->serverFormat.bitsPerPixel = screen->serverFormat.depth + = screen->bitsPerPixel = depth = ds->depth = ds_sdl->depth; + w = ds->width = ds_sdl->width; + h = ds->height = ds_sdl->height; + sdl_format=sdl_get_format(); + if(sdl_format->palette==0) { + screen->serverFormat.trueColour=TRUE; + screen->serverFormat.redShift=sdl_format->Rshift; + screen->serverFormat.greenShift=sdl_format->Gshift; + screen->serverFormat.blueShift=sdl_format->Bshift; + screen->serverFormat.redMax=sdl_format->Rmask>>screen->serverFormat.redShift; + screen->serverFormat.greenMax=sdl_format->Gmask>>screen->serverFormat.greenShift; + screen->serverFormat.blueMax=sdl_format->Bmask>>screen->serverFormat.blueShift; + } else { + rfbColourMap* cmap=&(screen->colourMap); + int i; + screen->serverFormat.trueColour=FALSE; + cmap->is16=FALSE; + cmap->count=sdl_format->palette->ncolors; + if(cmap->data.bytes==0) + cmap->data.bytes=malloc(256*3); + for(i=0;icount;i++) { + cmap->data.bytes[3*i+0]=sdl_format->palette->colors[i].r; + cmap->data.bytes[3*i+1]=sdl_format->palette->colors[i].g; + cmap->data.bytes[3*i+2]=sdl_format->palette->colors[i].b; + } + } +#else + term_printf("Warning: SDL not configured\n"); +#endif + } else { + ds->data = (unsigned char*)realloc(ds->data, w*h*depth/8); + ds->linesize = screen->paddedWidthInBytes = w*2; + ds->width = w; + ds->height = h; + ds->depth = depth; + screen->paddedWidthInBytes = w*depth/8; + } + screen->frameBuffer = ds->data; + + screen->width = w; + screen->height = h; + + iter=rfbGetClientIterator(screen); + while((cl=rfbClientIteratorNext(iter))) + if(cl->useNewFBSize) + cl->newFBSizePending = TRUE; + else + rfbLog("Warning: Client %s does not support NewFBSize!\n",cl->host); + rfbReleaseClientIterator(iter); + + if(mouse_magic->calibration) { + term_printf("Warning: mouse calibration interrupted by video mode change\n"); + stop_mouse_calibration(); + } + init_mouse(w,h); +} + +static void vnc_process_key(rfbBool down, rfbKeySym keySym, rfbClientPtr cl) +{ + /* handle Ctrl+Alt (AKA magic keys) first */ + if(down) { + if(keySym==XK_Control_L) + ctl_keys|=1; + else if(keySym==XK_Alt_L) + ctl_keys|=2; + else if((ctl_keys&3)==3) + return; + } else { + if (keySym == XK_Control_L) + ctl_keys &= ~1; + else if (keySym == XK_Alt_L) + ctl_keys &= ~2; + else if((ctl_keys&3)==3) { + switch(keySym) { + case XK_m: + start_mouse_calibration(); + break; + case XK_1 ... XK_9: + //fprintf(stderr,"switch to %d\n",keySym-XK_1); + console_select(keySym - XK_1); + if (!is_graphic_console()) { + /* tell the vga console to redisplay itself */ + vga_hw_invalidate(); + vnc_update(0,0,0,screen->width,screen->height); + } + break; + } + return; + } + } + + if(is_graphic_console()) { + int keycode=keysym2scancode(kbd_layout, keySym); + if(keycode>=0x80) + keycode=(keycode<<8)^0x80e0; + //fprintf(stdout,"vnc key out %s: 0x%x,\n",down?"down":"up",keycode); + while(keycode!=0) { + kbd_put_keycode((keycode&0xff)|(down?0:0x80)); + keycode>>=8; + } + } else if(down) { + if(!(keySym>=XK_Shift_L && keySym<=XK_Hyper_R) + && !(keySym>=XK_ISO_Lock && keySym<=XK_Pointer_DfltBtnPrev)) + kbd_put_keysym(keySym); + //fprintf(stderr,"vnc key %s: 0x%x (magic=%d)\n",down?"down":"up",keySym,ctl_keys); + } +} + +static void vnc_process_mouse(int buttonMask, int x, int y, rfbClientPtr cl) +{ + new_mouse_x=x; new_mouse_y=y; new_mouse_buttons=0; + if(buttonMask&1) new_mouse_buttons|=MOUSE_EVENT_LBUTTON; + if(buttonMask&2) new_mouse_buttons|=MOUSE_EVENT_MBUTTON; + if(buttonMask&4) new_mouse_buttons|=MOUSE_EVENT_RBUTTON; + if(buttonMask&8) new_mouse_z--; + if(buttonMask&16) new_mouse_z++; + if(mouse_magic->calibration && (kbd_mouse_is_absolute() == 0)) { + printf("mouse_calibration_refresg\n"); + mouse_calibration_refresh(); + } else { + // printf("mouse_refresh\n"); + mouse_refresh(); + } + +} + +static void vnc_refresh(DisplayState *ds) { + if(ds_sdl) + ds_sdl->dpy_refresh(ds_sdl); + else if(!is_graphic_console()) + vga_hw_update(); + rfbProcessEvents(screen,0); +} + +static void vnc_cleanup(void) +{ + rfbScreenCleanup(screen); +} + +void vnc_display_init(DisplayState *ds, int useAlsoSDL) +{ + if(!keyboard_layout) { + fprintf(stderr, "No keyboard language specified\n"); + exit(1); + } + + kbd_layout=init_keyboard_layout(keyboard_layout); + if(!kbd_layout) { + fprintf(stderr, "Could not initialize keyboard\n"); + exit(1); + } + + mouse_magic=init_mouse_magic(); + register_savevm("vnc", 0, 1, vnc_save, vnc_load, mouse_magic); + + rfbLog=rfbErr=term_printf; + screen=rfbGetScreen(0,0,0,0,5,3,2); + if(screen==0) { + fprintf(stderr, "Could not initialize VNC - exiting\n"); + exit(1); + } + + screen->serverFormat.redShift = 11; + screen->serverFormat.greenShift = 5; + screen->serverFormat.blueShift = 0; + screen->serverFormat.redMax = 31; + screen->serverFormat.greenMax = 63; + screen->serverFormat.blueMax = 31; + + if(useAlsoSDL) { +#ifdef CONFIG_SDL + ds_sdl=(DisplayState*)malloc(sizeof(DisplayState)); + sdl_display_init(ds_sdl,0); + screen->frameBuffer = ds_sdl->data; +#else + term_printf("SDL not configured!\n"); +#endif + } else + screen->frameBuffer = malloc(640*400*2); + + screen->desktopName = "QEMU/VNC"; + screen->cursor = 0; + + /* Did we get a VNC port in the command line? */ + if (vnc_port) { + screen->autoPort = FALSE; + screen->port = vnc_port; + } + else + screen->autoPort = TRUE; + + screen->kbdAddEvent = vnc_process_key; + screen->ptrAddEvent = vnc_process_mouse; + rfbInitServer(screen); + + vnc_resize(ds,640,400); + + ds->dpy_update = vnc_update; + ds->dpy_resize = vnc_resize; + ds->dpy_refresh = vnc_refresh; + + atexit(vnc_cleanup); +} + diff -urN -x CVS qemu-clean/vnc_keysym.h qemu/vnc_keysym.h --- qemu-clean/vnc_keysym.h 1970-01-01 04:00:00.000000000 +0400 +++ qemu/vnc_keysym.h 2006-04-10 11:07:37.000000000 +0400 @@ -0,0 +1,278 @@ +typedef struct { + const char* name; + int keysym; +} name2keysym_t; +static name2keysym_t name2keysym[]={ +/* ascii */ + { "space", 0x020}, + { "exclam", 0x021}, + { "quotedbl", 0x022}, + { "numbersign", 0x023}, + { "dollar", 0x024}, + { "percent", 0x025}, + { "ampersand", 0x026}, + { "apostrophe", 0x027}, + { "parenleft", 0x028}, + { "parenright", 0x029}, + { "asterisk", 0x02a}, + { "plus", 0x02b}, + { "comma", 0x02c}, + { "minus", 0x02d}, + { "period", 0x02e}, + { "slash", 0x02f}, + { "0", 0x030}, + { "1", 0x031}, + { "2", 0x032}, + { "3", 0x033}, + { "4", 0x034}, + { "5", 0x035}, + { "6", 0x036}, + { "7", 0x037}, + { "8", 0x038}, + { "9", 0x039}, + { "colon", 0x03a}, + { "semicolon", 0x03b}, + { "less", 0x03c}, + { "equal", 0x03d}, + { "greater", 0x03e}, + { "question", 0x03f}, + { "at", 0x040}, + { "A", 0x041}, + { "B", 0x042}, + { "C", 0x043}, + { "D", 0x044}, + { "E", 0x045}, + { "F", 0x046}, + { "G", 0x047}, + { "H", 0x048}, + { "I", 0x049}, + { "J", 0x04a}, + { "K", 0x04b}, + { "L", 0x04c}, + { "M", 0x04d}, + { "N", 0x04e}, + { "O", 0x04f}, + { "P", 0x050}, + { "Q", 0x051}, + { "R", 0x052}, + { "S", 0x053}, + { "T", 0x054}, + { "U", 0x055}, + { "V", 0x056}, + { "W", 0x057}, + { "X", 0x058}, + { "Y", 0x059}, + { "Z", 0x05a}, + { "bracketleft", 0x05b}, + { "backslash", 0x05c}, + { "bracketright", 0x05d}, + { "asciicircum", 0x05e}, + { "underscore", 0x05f}, + { "grave", 0x060}, + { "a", 0x061}, + { "b", 0x062}, + { "c", 0x063}, + { "d", 0x064}, + { "e", 0x065}, + { "f", 0x066}, + { "g", 0x067}, + { "h", 0x068}, + { "i", 0x069}, + { "j", 0x06a}, + { "k", 0x06b}, + { "l", 0x06c}, + { "m", 0x06d}, + { "n", 0x06e}, + { "o", 0x06f}, + { "p", 0x070}, + { "q", 0x071}, + { "r", 0x072}, + { "s", 0x073}, + { "t", 0x074}, + { "u", 0x075}, + { "v", 0x076}, + { "w", 0x077}, + { "x", 0x078}, + { "y", 0x079}, + { "z", 0x07a}, + { "braceleft", 0x07b}, + { "bar", 0x07c}, + { "braceright", 0x07d}, + { "asciitilde", 0x07e}, + +/* latin 1 extensions */ +{ "nobreakspace", 0x0a0}, +{ "exclamdown", 0x0a1}, +{ "cent", 0x0a2}, +{ "sterling", 0x0a3}, +{ "currency", 0x0a4}, +{ "yen", 0x0a5}, +{ "brokenbar", 0x0a6}, +{ "section", 0x0a7}, +{ "diaeresis", 0x0a8}, +{ "copyright", 0x0a9}, +{ "ordfeminine", 0x0aa}, +{ "guillemotleft", 0x0ab}, +{ "notsign", 0x0ac}, +{ "hyphen", 0x0ad}, +{ "registered", 0x0ae}, +{ "macron", 0x0af}, +{ "degree", 0x0b0}, +{ "plusminus", 0x0b1}, +{ "twosuperior", 0x0b2}, +{ "threesuperior", 0x0b3}, +{ "acute", 0x0b4}, +{ "mu", 0x0b5}, +{ "paragraph", 0x0b6}, +{ "periodcentered", 0x0b7}, +{ "cedilla", 0x0b8}, +{ "onesuperior", 0x0b9}, +{ "masculine", 0x0ba}, +{ "guillemotright", 0x0bb}, +{ "onequarter", 0x0bc}, +{ "onehalf", 0x0bd}, +{ "threequarters", 0x0be}, +{ "questiondown", 0x0bf}, +{ "Agrave", 0x0c0}, +{ "Aacute", 0x0c1}, +{ "Acircumflex", 0x0c2}, +{ "Atilde", 0x0c3}, +{ "Adiaeresis", 0x0c4}, +{ "Aring", 0x0c5}, +{ "AE", 0x0c6}, +{ "Ccedilla", 0x0c7}, +{ "Egrave", 0x0c8}, +{ "Eacute", 0x0c9}, +{ "Ecircumflex", 0x0ca}, +{ "Ediaeresis", 0x0cb}, +{ "Igrave", 0x0cc}, +{ "Iacute", 0x0cd}, +{ "Icircumflex", 0x0ce}, +{ "Idiaeresis", 0x0cf}, +{ "ETH", 0x0d0}, +{ "Eth", 0x0d0}, +{ "Ntilde", 0x0d1}, +{ "Ograve", 0x0d2}, +{ "Oacute", 0x0d3}, +{ "Ocircumflex", 0x0d4}, +{ "Otilde", 0x0d5}, +{ "Odiaeresis", 0x0d6}, +{ "multiply", 0x0d7}, +{ "Ooblique", 0x0d8}, +{ "Oslash", 0x0d8}, +{ "Ugrave", 0x0d9}, +{ "Uacute", 0x0da}, +{ "Ucircumflex", 0x0db}, +{ "Udiaeresis", 0x0dc}, +{ "Yacute", 0x0dd}, +{ "THORN", 0x0de}, +{ "Thorn", 0x0de}, +{ "ssharp", 0x0df}, +{ "agrave", 0x0e0}, +{ "aacute", 0x0e1}, +{ "acircumflex", 0x0e2}, +{ "atilde", 0x0e3}, +{ "adiaeresis", 0x0e4}, +{ "aring", 0x0e5}, +{ "ae", 0x0e6}, +{ "ccedilla", 0x0e7}, +{ "egrave", 0x0e8}, +{ "eacute", 0x0e9}, +{ "ecircumflex", 0x0ea}, +{ "ediaeresis", 0x0eb}, +{ "igrave", 0x0ec}, +{ "iacute", 0x0ed}, +{ "icircumflex", 0x0ee}, +{ "idiaeresis", 0x0ef}, +{ "eth", 0x0f0}, +{ "ntilde", 0x0f1}, +{ "ograve", 0x0f2}, +{ "oacute", 0x0f3}, +{ "ocircumflex", 0x0f4}, +{ "otilde", 0x0f5}, +{ "odiaeresis", 0x0f6}, +{ "division", 0x0f7}, +{ "oslash", 0x0f8}, +{ "ooblique", 0x0f8}, +{ "ugrave", 0x0f9}, +{ "uacute", 0x0fa}, +{ "ucircumflex", 0x0fb}, +{ "udiaeresis", 0x0fc}, +{ "yacute", 0x0fd}, +{ "thorn", 0x0fe}, +{ "ydiaeresis", 0x0ff}, +{"EuroSign", XK_EuroSign}, + + /* modifiers */ +{"Control_L", XK_Control_L}, +{"Control_R", XK_Control_R}, +{"Alt_L", XK_Alt_L}, +{"Alt_R", XK_Alt_R}, +{"Caps_Lock", XK_Caps_Lock}, +{"Meta_L", XK_Meta_L}, +{"Meta_R", XK_Meta_R}, +{"Shift_L", XK_Shift_L}, +{"Shift_R", XK_Shift_R}, +{"Super_L", XK_Super_L}, +{"Super_R", XK_Super_R}, + + /* special keys */ +{"BackSpace", XK_BackSpace}, +{"Tab", XK_Tab}, +{"Return", XK_Return}, +{"Right", XK_Right}, +{"Left", XK_Left}, +{"Up", XK_Up}, +{"Down", XK_Down}, +{"Page_Down", XK_Page_Down}, +{"Page_Up", XK_Page_Up}, +{"Insert", XK_Insert}, +{"Delete", XK_Delete}, +{"Home", XK_Home}, +{"End", XK_End}, +{"Scroll_Lock", XK_Scroll_Lock}, +{"F1", XK_F1}, +{"F2", XK_F2}, +{"F3", XK_F3}, +{"F4", XK_F4}, +{"F5", XK_F5}, +{"F6", XK_F6}, +{"F7", XK_F7}, +{"F8", XK_F8}, +{"F9", XK_F9}, +{"F10", XK_F10}, +{"F11", XK_F11}, +{"F12", XK_F12}, +{"F13", XK_F13}, +{"F14", XK_F14}, +{"F15", XK_F15}, +{"Sys_Req", XK_Sys_Req}, +{"KP_0", XK_KP_0}, +{"KP_1", XK_KP_1}, +{"KP_2", XK_KP_2}, +{"KP_3", XK_KP_3}, +{"KP_4", XK_KP_4}, +{"KP_5", XK_KP_5}, +{"KP_6", XK_KP_6}, +{"KP_7", XK_KP_7}, +{"KP_8", XK_KP_8}, +{"KP_9", XK_KP_9}, +{"KP_Add", XK_KP_Add}, +{"KP_Decimal", XK_KP_Decimal}, +{"KP_Divide", XK_KP_Divide}, +{"KP_Enter", XK_KP_Enter}, +{"KP_Equal", XK_KP_Equal}, +{"KP_Multiply", XK_KP_Multiply}, +{"KP_Subtract", XK_KP_Subtract}, +{"help", XK_Help}, +{"Menu", XK_Menu}, +/*{"Power", XK_Power},*/ +{"Print", XK_Print}, +{"Mode_switch", XK_Mode_switch}, +/*{"Multi_Key", XK_Multi_Key},*/ +{"Num_Lock", XK_Num_Lock}, +{"Pause", XK_Pause}, +{"Escape", XK_Escape}, + +{0,0}, +};