qemu-devel
[Top][All Lists]
Advanced

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

[Qemu-devel] [PATCH 1/1] Add shared memory interface to QEMU


From: Anthony Liguori
Subject: [Qemu-devel] [PATCH 1/1] Add shared memory interface to QEMU
Date: Sun, 16 Jul 2006 13:13:09 -0500
User-agent: Thunderbird 1.5.0.4 (X11/20060615)

This is actually adds the shared memory interface to QEMU.

Regards,

Anthony Liguori
# HG changeset patch
# User address@hidden
# Node ID 0b4c6f94ee520884063f11f4631185368998cf9c
# Parent  b9f2ce1d04dc160035f2a8c44fa400912b8a01fd
Add shared memory interface for external GUIs.  The protocol is documented
in README.shmem.

diff -r b9f2ce1d04dc -r 0b4c6f94ee52 Makefile.target
--- a/Makefile.target   Sat Jul 15 03:03:35 2006
+++ b/Makefile.target   Sun Jul 16 16:25:28 2006
@@ -375,6 +375,7 @@
 VL_OBJS+=sdl.o
 endif
 VL_OBJS+=vnc.o
+VL_OBJS+=shmem.o
 ifdef CONFIG_COCOA
 VL_OBJS+=cocoa.o
 COCOA_LIBS=-F/System/Library/Frameworks -framework Cocoa -framework IOKit
diff -r b9f2ce1d04dc -r 0b4c6f94ee52 vl.c
--- a/vl.c      Sat Jul 15 03:03:35 2006
+++ b/vl.c      Sun Jul 16 16:25:28 2006
@@ -5221,6 +5221,7 @@
 #endif
            "-loadvm file    start right away with a saved state (loadvm in 
monitor)\n"
           "-vnc display    start a VNC server on display\n"
+          "-shmem dev      start the shared memory interface on char device 
'dev'\n"
            "\n"
            "During emulation, the following keys are useful:\n"
            "ctrl-alt-f      toggle full screen\n"
@@ -5299,6 +5300,7 @@
     QEMU_OPTION_smp,
     QEMU_OPTION_vnc,
     QEMU_OPTION_no_acpi,
+    QEMU_OPTION_shmem,
 };
 
 typedef struct QEMUOption {
@@ -5370,6 +5372,7 @@
     { "usbdevice", HAS_ARG, QEMU_OPTION_usbdevice },
     { "smp", HAS_ARG, QEMU_OPTION_smp },
     { "vnc", HAS_ARG, QEMU_OPTION_vnc },
+    { "shmem", HAS_ARG, QEMU_OPTION_shmem },
     
     /* temporary options */
     { "usb", 0, QEMU_OPTION_usb },
@@ -5604,6 +5607,7 @@
     QEMUMachine *machine;
     char usb_devices[MAX_USB_CMDLINE][128];
     int usb_devices_index;
+    const char *shmem_path = 0;
 
     LIST_INIT (&vm_change_state_head);
 #ifndef _WIN32
@@ -6020,6 +6024,9 @@
             case QEMU_OPTION_no_acpi:
                 acpi_enabled = 0;
                 break;
+           case QEMU_OPTION_shmem:
+               shmem_path = optarg;
+                break;
             }
         }
     }
@@ -6133,6 +6140,19 @@
         dumb_display_init(ds);
     } else if (vnc_display != -1) {
        vnc_display_init(ds, vnc_display);
+    } else if (shmem_path) {
+       CharDriverState *s;
+
+       s = qemu_chr_open(shmem_path);
+       if (!s) {
+           fprintf(stderr, "qemu: could not open shmem device '%s'\n", 
+                   shmem_path);
+           exit(1);
+       }
+       if (!strcmp(shmem_path, "vc"))
+           qemu_chr_printf(s, "shmem console\n");
+
+       shmem_display_init(ds, s);
     } else {
 #if defined(CONFIG_SDL)
         sdl_display_init(ds, full_screen);
diff -r b9f2ce1d04dc -r 0b4c6f94ee52 vl.h
--- a/vl.h      Sat Jul 15 03:03:35 2006
+++ b/vl.h      Sun Jul 16 16:25:28 2006
@@ -767,6 +767,9 @@
 /* vnc.c */
 void vnc_display_init(DisplayState *ds, int display);
 
+/* shmem.c */
+void shmem_display_init(DisplayState *ds, CharDriverState *s);
+
 /* ide.c */
 #define MAX_DISKS 4
 
diff -r b9f2ce1d04dc -r 0b4c6f94ee52 README.shmem
--- /dev/null   Sat Jul 15 03:03:35 2006
+++ b/README.shmem      Sun Jul 16 16:25:28 2006
@@ -0,0 +1,96 @@
+QEMU Shared Memory Interface
+
+Changelog
+
+07-15-2006  Anthony Liguori <address@hidden>
+  - initial draft
+
+The shared memory interface in qemu provides a way to write external GUIs that
+perform almost as well as an integrated GUI.  This document attempts to
+described the protocol used to interact with this interface.
+
+Overview
+
+The transport for the shared memory interface is a QEMU character device.
+Currently, QEMU supports a wide variety of devices (TCP/UDP sockets,
+ptys, etc).  The shared memory interface is enabled with the -shmem option.
+The format of the argument for this option is similar to the -serial or
+-monitor options.
+
+The protocol used is asynchronous and line based.  Line's are terminated with
+a \n (or possibly a \r\n).  For the rest of this document, I will refer to
+commands sent by QEMU as server commands and commands sent by the other end
+of the character device as client commands.
+
+Server Commands
+
+ERROR [string]
+
+This command is sent when an error has occurred (usually from a bad command).
+String is a human-readable description of the problem.  These errors are
+usually not fatal.
+
+MOUSE-ABSOLUTE
+
+This command signals to the client that the mouse is now in absolute mode.
+This is a hint to the client so that it can handle mouse grab appropriately.
+
+MOUSE-RELATIVE
+
+This command signals to the client that the mouse is now in relative mode.
+This is a hint to the client so that it can handle mouse grab appropriately.
+
+RESIZE width, height
+
+This command signals to the client that the guest has resized the VGA screen.
+After a client receives this command, it should allocate an appropriately
+sized shared memory segment and notify the server about this with the SHMID
+command.
+
+UPDATE x, y, width, height
+
+This command signals to the client that the guest has updated a portion of the
+VGA screen described by the rectangle (x, y, width, height).
+
+ATTACHED shmid
+
+This command signals to the client that the server has attached to the shared
+memory segment specified by shmid.  The purpose of this command is to allow
+the client to know when to mark the shared memory segment as deleted.  This
+cannot be relied upon in cases where an exit may occur so the client should
+take precautions and remove any shared memory segment whenever it is no longer
+needed (for instance, after a RESIZE and before the client exits).
+
+Client Commands
+
+SHMID shmid, size, width, height, depth, linesize
+
+This command reports a shared memory segment that the server should use to
+render the display too.  shmid is a shared memory id (returned from shmget()).
+size is the size of the memory (in bytes).  width and height represent the
+size of the image in pixels.  depth is the number of bits per pixel.  Finally,
+linesize is the number of bytes per line in the image.
+
+A client should wait for an ATTACHED server command before removing the shared
+memory segment.
+
+MOUSE x, y, buttons
+
+This command reports a change in mouse state to the server.  x and y are the
+absolute position of the mouse (relative to the upper left corner of the guests
+screen).  Both of these values may be negative when in relative mode.  buttons
+is a bitmask representing which mouse buttons are active.  The first bit in the
+mask represents the right mouse button, the second represents the left button,
+and the third represents the middle mouse button.
+
+KEY-DOWN key
+
+This command reports a key press event to the server.  key is the name of the
+key that has been depressed.  The format of key is identical to that used to
+represent keys in the keyboard layout files.
+
+KEY-UP key
+
+This command reports that a key has been released to the server.  key is the
+name of the key that has been released.  The format of key is identical to that
+used to represent keys in the keyboard layout files.
diff -r b9f2ce1d04dc -r 0b4c6f94ee52 shmem.c
--- /dev/null   Sat Jul 15 03:03:35 2006
+++ b/shmem.c   Sun Jul 16 16:25:28 2006
@@ -0,0 +1,249 @@
+/*
+ * QEMU Shared Memory display driver
+ * 
+ * Copyright (C) 2006 Anthony Liguori <address@hidden>
+ * 
+ * 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 "shmem_keysym.h"
+#include "keymaps.c"
+
+#include <sys/ipc.h>
+#include <sys/shm.h>
+
+typedef struct _ShmemState
+{
+    CharDriverState *chr;
+    DisplayState *ds;
+    char buffer[1024];
+    int n_buffer;
+    uint8_t *dummy;
+    int old_x, old_y;
+    int mouse_mode; /* 0 is relative; 1 is absolute */
+    kbd_layout_t *kbd_layout;
+} ShmemState;
+
+static int shmem_can_read(void *opaque)
+{
+    return 1024;
+}
+
+static void shmem_cmd_shmid(ShmemState *s, int shmid, int size,
+                           int width, int height, int depth, int linesize)
+{
+    uint8_t *addr;
+
+    addr = shmat(shmid, NULL, 0);
+    if (addr == (void *)-1) {
+       qemu_chr_printf(s->chr, "ERROR could not attach to shm:%d\n", shmid);
+       return;
+    }
+
+    qemu_chr_printf(s->chr, "ATTACHED %d\n", shmid);
+
+    if (s->ds->data && s->ds->data != s->dummy)
+       shmdt(s->ds->data);
+
+    s->ds->data = addr;
+    s->ds->linesize = linesize;
+    s->ds->depth = depth;
+    s->ds->width = width;
+    s->ds->height = height;
+
+    vga_hw_invalidate();
+    vga_hw_update();
+}
+
+static void shmem_update_mouse_type(ShmemState *s)
+{
+    if (kbd_mouse_is_absolute()) {
+       if (s->mouse_mode != 1) {
+           s->mouse_mode = 1;
+           qemu_chr_printf(s->chr, "MOUSE-ABSOLUTE\n");
+       }
+    } else if (s->mouse_mode != 0) {
+       s->mouse_mode = 0;
+       qemu_chr_printf(s->chr, "MOUSE-RELATIVE\n");
+    }
+}
+
+static void shmem_cmd_mouse(ShmemState *s, int x, int y, int z, int buttons)
+{
+    if (s->old_x != -1) {
+       int dx, dy;
+
+       if (kbd_mouse_is_absolute()) {
+           dx = x * 0x7FFF / s->ds->width;
+           dy = y * 0x7FFF / s->ds->height;
+       } else {
+           dx = x - s->old_x;
+           dy = y - s->old_y;
+       }
+
+       shmem_update_mouse_type(s);
+
+       kbd_mouse_event(dx, dy, z, buttons);
+    }
+
+    s->old_x = x;
+    s->old_y = y;
+}
+
+static int keyname2keysym(const char *key)
+{
+    int i;
+
+    for (i = 0; name2keysym[i].name; i++) {
+       if (strcmp(name2keysym[i].name, key) == 0)
+           return name2keysym[i].keysym;
+    }
+
+    return 0;
+}
+
+static void shmem_cmd_key(ShmemState *s, const char *key, int down)
+{
+    int keycode;
+    int keysym;
+
+    keysym = keyname2keysym(key);
+    if (keysym == 0) {
+       qemu_chr_printf(s->chr, "ERROR unknown key `%s'\n", key);
+       return;
+    }
+    keycode = keysym2scancode(s->kbd_layout, keysym & 0xFFFF);
+
+    if (keycode & 0x80)
+       kbd_put_keycode(0xe0);
+    if (down)
+       kbd_put_keycode(keycode & 0x7F);
+    else
+       kbd_put_keycode(keycode | 0x80);
+}
+
+static void shmem_handle_command(ShmemState *s, const char *cmd)
+{
+    int shmid, size, depth, linesize, width, height;
+    int x, y, z, buttons;
+    char key[1024];
+
+    if (sscanf(cmd, "SHMID %d, %d, %d, %d, %d, %d\n",
+              &shmid, &size, &width, &height, &depth, &linesize) == 6) {
+       shmem_cmd_shmid(s, shmid, size, width, height, depth, linesize);
+    } else if (sscanf(cmd, "MOUSE %d, %d, %d, %d\n",
+                     &x, &y, &z, &buttons) == 4) {
+       shmem_cmd_mouse(s, x, y, z, buttons);
+    } else if (sscanf(cmd, "KEY-DOWN %1023s\n", key) == 1) {
+       shmem_cmd_key(s, key, 1);
+    } else if (sscanf(cmd, "KEY-UP %1023s\n", key) == 1) {
+       shmem_cmd_key(s, key, 0);
+    } else {
+       qemu_chr_printf(s->chr, "ERROR unknown command: `%s'\n", cmd);
+    }
+}
+
+static void shmem_read(void *opaque, const uint8_t *buf, int size)
+{
+    ShmemState *s = opaque;
+    int offset = 0;
+
+    while (offset < size) {
+       char *nl;
+       int len;
+
+       len = MIN(sizeof(s->buffer) - s->n_buffer - 1, size - offset);
+       memcpy(s->buffer + s->n_buffer, buf + offset, len);
+       s->n_buffer += len;
+       s->buffer[s->n_buffer] = 0;
+       offset += len;
+
+       while ((nl = strchr(s->buffer, '\n'))) {
+           int remainder = s->n_buffer - (nl - s->buffer) - 1;
+           *nl = 0;
+           shmem_handle_command(s, s->buffer);
+           memmove(s->buffer, nl + 1, remainder);
+           s->n_buffer = remainder;
+       }
+    }
+}
+
+static void shmem_dpy_resize(DisplayState *ds, int w, int h)
+{
+    ShmemState *s = ds->opaque;
+
+    if (w == ds->width && h == ds->height)
+       return;
+
+    qemu_chr_printf(s->chr, "RESIZE %d, %d\n", w, h);
+
+    s->dummy = realloc(s->dummy, w * h);
+    if (s->dummy == NULL)
+       exit(1);
+
+    ds->depth = 8;
+    ds->width = w;
+    ds->height = h;
+    ds->linesize = w;
+    ds->data = s->dummy;
+}
+
+static void shmem_dpy_update(DisplayState *ds, int x, int y, int w, int h)
+{
+    ShmemState *s = ds->opaque;
+    qemu_chr_printf(s->chr, "UPDATE %d, %d, %d, %d\n", x, y, w, h);
+}
+
+static void shmem_dpy_refresh(DisplayState *ds)
+{
+    vga_hw_update();
+}
+
+void shmem_display_init(DisplayState *ds, CharDriverState *chr)
+{
+    ShmemState *s;
+
+    s = qemu_mallocz(sizeof(ShmemState));
+    if (!s)
+       exit(1);
+
+    s->chr = chr;
+    s->ds = ds;
+    s->old_x = -1;
+    s->old_y = -1;
+    s->mouse_mode = 0;
+
+    if (!keyboard_layout)
+       keyboard_layout = "en-us";
+
+    s->kbd_layout = init_keyboard_layout(keyboard_layout);
+    if (!s->kbd_layout)
+       exit(1);
+
+    ds->dpy_update = shmem_dpy_update;
+    ds->dpy_resize = shmem_dpy_resize;
+    ds->dpy_refresh = shmem_dpy_refresh;
+    ds->opaque = s;
+
+    shmem_dpy_resize(ds, 640, 480);
+
+    qemu_chr_add_read_handler(chr, shmem_can_read, shmem_read, s);
+}
diff -r b9f2ce1d04dc -r 0b4c6f94ee52 shmem_keysym.h
--- /dev/null   Sat Jul 15 03:03:35 2006
+++ b/shmem_keysym.h    Sun Jul 16 16:25:28 2006
@@ -0,0 +1,277 @@
+typedef struct {
+       const char* name;
+       int keysym;
+} name2keysym_t;
+static name2keysym_t name2keysym[]={
+/* ascii */
+    { "space",                1},
+    { "exclam",               2},
+    { "quotedbl",             3},
+    { "numbersign",           4},
+    { "dollar",               5},
+    { "percent",              6},
+    { "ampersand",            7},
+    { "apostrophe",           8},
+    { "parenleft",            9},
+    { "parenright",           10},
+    { "asterisk",             11},
+    { "plus",                 12},
+    { "comma",                13},
+    { "minus",                14},
+    { "period",               15},
+    { "slash",                16},
+    { "0",                    17},
+    { "1",                    18},
+    { "2",                    19},
+    { "3",                    20},
+    { "4",                    21},
+    { "5",                    22},
+    { "6",                    23},
+    { "7",                    24},
+    { "8",                    25},
+    { "9",                    26},
+    { "colon",                27},
+    { "semicolon",            28},
+    { "less",                 29},
+    { "equal",                30},
+    { "greater",              31},
+    { "question",             32},
+    { "at",                   33},
+    { "A",                    34},
+    { "B",                    35},
+    { "C",                    36},
+    { "D",                    37},
+    { "E",                    38},
+    { "F",                    39},
+    { "G",                    40},
+    { "H",                    41},
+    { "I",                    42},
+    { "J",                    43},
+    { "K",                    44},
+    { "L",                    45},
+    { "M",                    46},
+    { "N",                    47},
+    { "O",                    48},
+    { "P",                    49},
+    { "Q",                    40},
+    { "R",                    41},
+    { "S",                    42},
+    { "T",                    43},
+    { "U",                    44},
+    { "V",                    45},
+    { "W",                    46},
+    { "X",                    47},
+    { "Y",                    48},
+    { "Z",                    49},
+    { "bracketleft",          50},
+    { "backslash",            51},
+    { "bracketright",         52},
+    { "asciicircum",          53},
+    { "underscore",           54},
+    { "grave",                55},
+    { "a",                    56},
+    { "b",                    57},
+    { "c",                    58},
+    { "d",                    59},
+    { "e",                    60},
+    { "f",                    61},
+    { "g",                    62},
+    { "h",                    63},
+    { "i",                    64},
+    { "j",                    65},
+    { "k",                    66},
+    { "l",                    67},
+    { "m",                    68},
+    { "n",                    69},
+    { "o",                    70},
+    { "p",                    71},
+    { "q",                    72},
+    { "r",                    73},
+    { "s",                    74},
+    { "t",                    75},
+    { "u",                    76},
+    { "v",                    77},
+    { "w",                    78},
+    { "x",                    79},
+    { "y",                    80},
+    { "z",                    81},
+    { "braceleft",            82},
+    { "bar",                  83},
+    { "braceright",           84},
+    { "asciitilde",           85},
+                                 
+/* latin 1 extensions */         
+{ "nobreakspace",         86}, 
+{ "exclamdown",           87}, 
+{ "cent",                88}, 
+{ "sterling",             89},
+{ "currency",             90},
+{ "yen",                  91},
+{ "brokenbar",            92},
+{ "section",              93},
+{ "diaeresis",            94},
+{ "copyright",            95},
+{ "ordfeminine",          96},
+{ "guillemotleft",        97},
+{ "notsign",              98},
+{ "hyphen",               99},
+{ "registered",           100},
+{ "macron",               101},
+{ "degree",               102},
+{ "plusminus",            103},
+{ "twosuperior",          104},
+{ "threesuperior",        105},
+{ "acute",                106},
+{ "mu",                   107},
+{ "paragraph",            108},
+{ "periodcentered",       109},
+{ "cedilla",              110},
+{ "onesuperior",          111},
+{ "masculine",            112},
+{ "guillemotright",       113},
+{ "onequarter",           114},
+{ "onehalf",              115},
+{ "threequarters",        116},
+{ "questiondown",         117},
+{ "Agrave",               118},
+{ "Aacute",               119},
+{ "Acircumflex",          120},
+{ "Atilde",               121},
+{ "Adiaeresis",           122},
+{ "Aring",                123},
+{ "AE",                   124},
+{ "Ccedilla",             125},
+{ "Egrave",               126},
+{ "Eacute",               127},
+{ "Ecircumflex",          128},
+{ "Ediaeresis",           129},
+{ "Igrave",               130},
+{ "Iacute",               131},
+{ "Icircumflex",          132},
+{ "Idiaeresis",           133},
+{ "ETH",                  134},
+{ "Eth",                  135},
+{ "Ntilde",               136},
+{ "Ograve",               137},
+{ "Oacute",               138},
+{ "Ocircumflex",          139},
+{ "Otilde",               140},
+{ "Odiaeresis",           141},
+{ "multiply",             142},
+{ "Ooblique",             143},
+{ "Oslash",               144},
+{ "Ugrave",               145},
+{ "Uacute",               146},
+{ "Ucircumflex",          147},
+{ "Udiaeresis",           148},
+{ "Yacute",               149},
+{ "THORN",                140},
+{ "Thorn",                141},
+{ "ssharp",               142},
+{ "agrave",               143},
+{ "aacute",               144},
+{ "acircumflex",          145},
+{ "atilde",               146},
+{ "adiaeresis",           147},
+{ "aring",                148},
+{ "ae",                   149},
+{ "ccedilla",             150},
+{ "egrave",               151},
+{ "eacute",               152},
+{ "ecircumflex",          153},
+{ "ediaeresis",           154},
+{ "igrave",               155},
+{ "iacute",               156},
+{ "icircumflex",          157},
+{ "idiaeresis",           158},
+{ "eth",                  159},
+{ "ntilde",               160},
+{ "ograve",               161},
+{ "oacute",               162},
+{ "ocircumflex",          163},
+{ "otilde",               164},
+{ "odiaeresis",           165},
+{ "division",             166},
+{ "oslash",               167},
+{ "ooblique",             168},
+{ "ugrave",               169},
+{ "uacute",               170},
+{ "ucircumflex",          171},
+{ "udiaeresis",           172},
+{ "yacute",               173},
+{ "thorn",                174},
+{ "ydiaeresis",           175},
+{ "EuroSign",             176},
+                          
+    /* modifiers */       
+{"Control_L",             177},
+{"Control_R",             178},
+{"Alt_L",                 179},
+{"Alt_R",                 180},
+{"Caps_Lock",            181},
+{"Meta_L",               182},
+{"Meta_R",               183},
+{"Shift_L",              184},
+{"Shift_R",              185},
+{"Super_L",              186},
+{"Super_R",              187},
+
+    /* special keys */
+{"BackSpace",            188},
+{"Tab",                  189},
+{"Return",               190},
+{"Right",                191},
+{"Left",                 192},
+{"Up",                   193},
+{"Down",                 194},
+{"Page_Down",            195},
+{"Page_Up",              196},
+{"Insert",               197},
+{"Delete",               198},
+{"Home",                 199},
+{"End",                          200},
+{"Scroll_Lock",                  201},
+{"F1",                   202},
+{"F2",                   203},
+{"F3",                   204},
+{"F4",                   205},
+{"F5",                   206},
+{"F6",                   207},
+{"F7",                   208},
+{"F8",                   209},
+{"F9",                   210},
+{"F10",                          211},
+{"F11",                          212},
+{"F12",                          213},
+{"F13",                          214},
+{"F14",                          215},
+{"F15",                          216},
+{"Sys_Req",              217},
+{"KP_0",                 218},
+{"KP_1",                 219},
+{"KP_2",                 220},
+{"KP_3",                 221},
+{"KP_4",                 222},
+{"KP_5",                 223},
+{"KP_6",                 224},
+{"KP_7",                 225},
+{"KP_8",                 226},
+{"KP_9",                 227},
+{"KP_Add",               228},
+{"KP_Decimal",           229},
+{"KP_Divide",            230},
+{"KP_Enter",             231},
+{"KP_Equal",             232},
+{"KP_Multiply",                  233},
+{"KP_Subtract",                  234},
+{"help",                 235},
+{"Menu",                 236},
+{"Power",                237},
+{"Print",                238},
+{"Mode_switch",                  239},
+{"Multi_Key",            240},
+{"Num_Lock",             241},
+{"Pause",                242},
+{"Escape",               243},
+{0},                         
+};

reply via email to

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