qemu-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [Qemu-devel] USB Tablet Emulation


From: Brad Campbell
Subject: Re: [Qemu-devel] USB Tablet Emulation
Date: Mon, 10 Apr 2006 12:23:05 +0400
User-agent: Thunderbird 1.6a1 (X11/20060214)

Anthony Liguori wrote:
I spent some time cleaning this all up. The following integrates Brad's patches and the patch from http://gnome.dnsalias.net/patches/qemu-hidmousexp.patch

It adds a new emulated USB device that reports absolute coordinates. It also modifies SDL to operate in grabless mode when an absolute input device is enabled. I think it's pretty close to apply-able. To use, just specify: -usbdevice tablet

With Xorg from CVS, the evdev driver segfaults. This is apparently expected behavior. Hopefully it will be fixed soon. It works quite nicely under Win2k.

Here is the vnc patch to go on top of that and the latest cvs.


--
"Human beings, who are almost unique in having the ability
to learn from the experience of others, are also remarkable
for their apparent disinclination to do so." -- Douglas Adams
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 <sys/select.h>
 #endif
 
+#include <inttypes.h>
+
 #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 <SDL/SDL.h>
+#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 <port> 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 <rfb/rfb.h>
+
+/* keyboard stuff */
+#include <rfb/keysym.h>
+#include "vnc_keysym.h"
+#define KEYBOARD_HANDLE_UPPER_CASE
+#include "keymaps.c"
+
+
+#ifndef _WIN32
+#include <signal.h>
+#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 <ctl><alt> 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;i<X+W;i++)
+               for(j=Y;j<Y+H;j++) {
+                       int offset=i*bpp+j*screen->paddedWidthInBytes;
+                       
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(x<last_update.x) { last_update.w+=last_update.x-x; 
last_update.x=x; }
+               if(x+w>last_update.x+last_update.w) { 
last_update.w=x+w-last_update.w; }
+               if(y<last_update.y) { last_update.h+=last_update.y-y; 
last_update.y=y; }
+               if(y+h>last_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 <SDL_video.h>
+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;i<cmap->count;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},
+};

reply via email to

[Prev in Thread] Current Thread [Next in Thread]