mirror of
https://github.com/xen-project/xen.git
synced 2026-10-28 18:21:39 +01:00
terminates, and that it cleans up its area of xenstore. Tidy up argument parsing a little while I'm here. Signed-off-by: Steven Smith <sos22@cam.ac.uk>
343 lines
7.2 KiB
C
343 lines
7.2 KiB
C
#include <SDL.h>
|
|
#include <errno.h>
|
|
#include <sys/types.h>
|
|
#include <sys/select.h>
|
|
#include <stdlib.h>
|
|
#include <linux/input.h>
|
|
#include <getopt.h>
|
|
#include <string.h>
|
|
#include "xenfb.h"
|
|
|
|
struct SDLFBData
|
|
{
|
|
SDL_Surface *dst;
|
|
SDL_Surface *src;
|
|
};
|
|
|
|
/*
|
|
* Map from scancode to Linux input layer keycode. Scancodes are
|
|
* hardware-specific. This map assumes a standard AT or PS/2
|
|
* keyboard.
|
|
*
|
|
* Why use scancodes? We can't use key symbols, because they don't
|
|
* identify keys --- they're what keys are mapped to. The standard
|
|
* German keymap, for instance, maps both KEY_COMMA and KEY_102ND to
|
|
* SDLK_LESS.
|
|
*/
|
|
static int keymap[256] = {
|
|
[9] = KEY_ESC,
|
|
[10] = KEY_1,
|
|
[11] = KEY_2,
|
|
[12] = KEY_3,
|
|
[13] = KEY_4,
|
|
[14] = KEY_5,
|
|
[15] = KEY_6,
|
|
[16] = KEY_7,
|
|
[17] = KEY_8,
|
|
[18] = KEY_9,
|
|
[19] = KEY_0,
|
|
[20] = KEY_MINUS,
|
|
[21] = KEY_EQUAL,
|
|
[22] = KEY_BACKSPACE,
|
|
[23] = KEY_TAB,
|
|
[24] = KEY_Q,
|
|
[25] = KEY_W,
|
|
[26] = KEY_E,
|
|
[27] = KEY_R,
|
|
[28] = KEY_T,
|
|
[29] = KEY_Y,
|
|
[30] = KEY_U,
|
|
[31] = KEY_I,
|
|
[32] = KEY_O,
|
|
[33] = KEY_P,
|
|
[34] = KEY_LEFTBRACE,
|
|
[35] = KEY_RIGHTBRACE,
|
|
[36] = KEY_ENTER,
|
|
[37] = KEY_LEFTCTRL,
|
|
[38] = KEY_A,
|
|
[39] = KEY_S,
|
|
[40] = KEY_D,
|
|
[41] = KEY_F,
|
|
[42] = KEY_G,
|
|
[43] = KEY_H,
|
|
[44] = KEY_J,
|
|
[45] = KEY_K,
|
|
[46] = KEY_L,
|
|
[47] = KEY_SEMICOLON,
|
|
[48] = KEY_APOSTROPHE,
|
|
[49] = KEY_GRAVE,
|
|
[50] = KEY_LEFTSHIFT,
|
|
[51] = KEY_BACKSLASH,
|
|
[52] = KEY_Z,
|
|
[53] = KEY_X,
|
|
[54] = KEY_C,
|
|
[55] = KEY_V,
|
|
[56] = KEY_B,
|
|
[57] = KEY_N,
|
|
[58] = KEY_M,
|
|
[59] = KEY_COMMA,
|
|
[60] = KEY_DOT,
|
|
[61] = KEY_SLASH,
|
|
[62] = KEY_RIGHTSHIFT,
|
|
[63] = KEY_KPASTERISK,
|
|
[64] = KEY_LEFTALT,
|
|
[65] = KEY_SPACE,
|
|
[66] = KEY_CAPSLOCK,
|
|
[67] = KEY_F1,
|
|
[68] = KEY_F2,
|
|
[69] = KEY_F3,
|
|
[70] = KEY_F4,
|
|
[71] = KEY_F5,
|
|
[72] = KEY_F6,
|
|
[73] = KEY_F7,
|
|
[74] = KEY_F8,
|
|
[75] = KEY_F9,
|
|
[76] = KEY_F10,
|
|
[77] = KEY_NUMLOCK,
|
|
[78] = KEY_SCROLLLOCK,
|
|
[79] = KEY_KP7,
|
|
[80] = KEY_KP8,
|
|
[81] = KEY_KP9,
|
|
[82] = KEY_KPMINUS,
|
|
[83] = KEY_KP4,
|
|
[84] = KEY_KP5,
|
|
[85] = KEY_KP6,
|
|
[86] = KEY_KPPLUS,
|
|
[87] = KEY_KP1,
|
|
[88] = KEY_KP2,
|
|
[89] = KEY_KP3,
|
|
[90] = KEY_KP0,
|
|
[91] = KEY_KPDOT,
|
|
[94] = KEY_102ND, /* FIXME is this correct? */
|
|
[95] = KEY_F11,
|
|
[96] = KEY_F12,
|
|
[108] = KEY_KPENTER,
|
|
[109] = KEY_RIGHTCTRL,
|
|
[112] = KEY_KPSLASH,
|
|
[111] = KEY_SYSRQ,
|
|
[113] = KEY_RIGHTALT,
|
|
[97] = KEY_HOME,
|
|
[98] = KEY_UP,
|
|
[99] = KEY_PAGEUP,
|
|
[100] = KEY_LEFT,
|
|
[102] = KEY_RIGHT,
|
|
[103] = KEY_END,
|
|
[104] = KEY_DOWN,
|
|
[105] = KEY_PAGEDOWN,
|
|
[106] = KEY_INSERT,
|
|
[107] = KEY_DELETE,
|
|
[110] = KEY_PAUSE,
|
|
[115] = KEY_LEFTMETA,
|
|
[116] = KEY_RIGHTMETA,
|
|
[117] = KEY_MENU,
|
|
};
|
|
|
|
static int btnmap[] = {
|
|
[SDL_BUTTON_LEFT] = BTN_LEFT,
|
|
[SDL_BUTTON_MIDDLE] = BTN_MIDDLE,
|
|
[SDL_BUTTON_RIGHT] = BTN_RIGHT,
|
|
/* FIXME not 100% sure about these: */
|
|
[SDL_BUTTON_WHEELUP] = BTN_FORWARD,
|
|
[SDL_BUTTON_WHEELDOWN] BTN_BACK
|
|
};
|
|
|
|
static void sdl_update(struct xenfb *xenfb, int x, int y, int width, int height)
|
|
{
|
|
struct SDLFBData *data = xenfb->user_data;
|
|
SDL_Rect r = { x, y, width, height };
|
|
SDL_BlitSurface(data->src, &r, data->dst, &r);
|
|
SDL_UpdateRect(data->dst, x, y, width, height);
|
|
}
|
|
|
|
static int sdl_on_event(struct xenfb *xenfb, SDL_Event *event)
|
|
{
|
|
int x, y, ret;
|
|
|
|
switch (event->type) {
|
|
case SDL_KEYDOWN:
|
|
case SDL_KEYUP:
|
|
if (keymap[event->key.keysym.scancode] == 0)
|
|
break;
|
|
ret = xenfb_send_key(xenfb,
|
|
event->type == SDL_KEYDOWN,
|
|
keymap[event->key.keysym.scancode]);
|
|
if (ret < 0)
|
|
fprintf(stderr, "Key %d %s lost (%s)\n",
|
|
keymap[event->key.keysym.scancode],
|
|
event->type == SDL_KEYDOWN ? "down" : "up",
|
|
strerror(errno));
|
|
break;
|
|
case SDL_MOUSEMOTION:
|
|
if (xenfb->abs_pointer_wanted) {
|
|
SDL_GetMouseState(&x, &y);
|
|
ret = xenfb_send_position(xenfb, x, y);
|
|
} else {
|
|
SDL_GetRelativeMouseState(&x, &y);
|
|
ret = xenfb_send_motion(xenfb, x, y);
|
|
}
|
|
if (ret < 0)
|
|
fprintf(stderr, "Pointer to %d,%d lost (%s)\n",
|
|
x, y, strerror(errno));
|
|
break;
|
|
case SDL_MOUSEBUTTONDOWN:
|
|
case SDL_MOUSEBUTTONUP:
|
|
if (event->button.button >= sizeof(btnmap) / sizeof(*btnmap))
|
|
break;
|
|
if (btnmap[event->button.button] == 0)
|
|
break;
|
|
ret = xenfb_send_key(xenfb,
|
|
event->type == SDL_MOUSEBUTTONDOWN,
|
|
btnmap[event->button.button]);
|
|
if (ret < 0)
|
|
fprintf(stderr, "Button %d %s lost (%s)\n",
|
|
btnmap[event->button.button] - BTN_MOUSE,
|
|
event->type == SDL_MOUSEBUTTONDOWN ? "down" : "up",
|
|
strerror(errno));
|
|
break;
|
|
case SDL_QUIT:
|
|
return 0;
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
|
|
static struct option options[] = {
|
|
{ "domid", 1, NULL, 'd' },
|
|
{ "title", 1, NULL, 't' },
|
|
{ NULL }
|
|
};
|
|
|
|
int main(int argc, char **argv)
|
|
{
|
|
struct xenfb *xenfb;
|
|
int domid = -1;
|
|
char * title = NULL;
|
|
fd_set readfds;
|
|
int nfds;
|
|
struct SDLFBData data;
|
|
SDL_Rect r;
|
|
struct timeval tv;
|
|
SDL_Event event;
|
|
int do_quit = 0;
|
|
int opt;
|
|
char *endp;
|
|
int retval;
|
|
|
|
while ((opt = getopt_long(argc, argv, "d:t:", options,
|
|
NULL)) != -1) {
|
|
switch (opt) {
|
|
case 'd':
|
|
domid = strtol(optarg, &endp, 10);
|
|
if (endp == optarg || *endp) {
|
|
fprintf(stderr, "Invalid domain id specified\n");
|
|
exit(1);
|
|
}
|
|
break;
|
|
case 't':
|
|
title = strdup(optarg);
|
|
break;
|
|
case '?':
|
|
exit(1);
|
|
}
|
|
}
|
|
if (optind != argc) {
|
|
fprintf(stderr, "Invalid options!\n");
|
|
exit(1);
|
|
}
|
|
if (domid <= 0) {
|
|
fprintf(stderr, "Domain ID must be specified!\n");
|
|
exit(1);
|
|
}
|
|
|
|
xenfb = xenfb_new();
|
|
if (xenfb == NULL) {
|
|
fprintf(stderr, "Could not create framebuffer (%s)\n",
|
|
strerror(errno));
|
|
exit(1);
|
|
}
|
|
|
|
if (xenfb_attach_dom(xenfb, domid) < 0) {
|
|
fprintf(stderr, "Could not connect to domain (%s)\n",
|
|
strerror(errno));
|
|
exit(1);
|
|
}
|
|
|
|
if (SDL_Init(SDL_INIT_VIDEO) < 0) {
|
|
fprintf(stderr, "Could not initialize SDL\n");
|
|
exit(1);
|
|
}
|
|
|
|
data.dst = SDL_SetVideoMode(xenfb->width, xenfb->height, xenfb->depth,
|
|
SDL_SWSURFACE);
|
|
if (!data.dst) {
|
|
fprintf(stderr, "SDL_SetVideoMode failed\n");
|
|
exit(1);
|
|
}
|
|
|
|
data.src = SDL_CreateRGBSurfaceFrom(xenfb->pixels,
|
|
xenfb->width, xenfb->height,
|
|
xenfb->depth, xenfb->row_stride,
|
|
0xFF0000, 0xFF00, 0xFF, 0);
|
|
|
|
if (!data.src) {
|
|
fprintf(stderr, "SDL_CreateRGBSurfaceFrom failed\n");
|
|
exit(1);
|
|
}
|
|
|
|
if (title == NULL)
|
|
title = strdup("xen-sdlfb");
|
|
SDL_WM_SetCaption(title, title);
|
|
|
|
r.x = r.y = 0;
|
|
r.w = xenfb->width;
|
|
r.h = xenfb->height;
|
|
SDL_BlitSurface(data.src, &r, data.dst, &r);
|
|
SDL_UpdateRect(data.dst, 0, 0, xenfb->width, xenfb->height);
|
|
|
|
xenfb->update = sdl_update;
|
|
xenfb->user_data = &data;
|
|
|
|
SDL_ShowCursor(0);
|
|
|
|
/*
|
|
* We need to wait for fds becoming ready or SDL events to
|
|
* arrive. We time out the select after 10ms to poll for SDL
|
|
* events. Clunky, but works. Could avoid the clunkiness
|
|
* with a separate thread.
|
|
*/
|
|
for (;;) {
|
|
FD_ZERO(&readfds);
|
|
nfds = xenfb_select_fds(xenfb, &readfds);
|
|
tv = (struct timeval){0, 10000};
|
|
|
|
if (select(nfds, &readfds, NULL, NULL, &tv) < 0) {
|
|
if (errno == EINTR)
|
|
continue;
|
|
fprintf(stderr,
|
|
"Can't select() on event channel (%s)\n",
|
|
strerror(errno));
|
|
break;
|
|
}
|
|
|
|
while (SDL_PollEvent(&event)) {
|
|
if (!sdl_on_event(xenfb, &event))
|
|
do_quit = 1;
|
|
}
|
|
|
|
if (do_quit)
|
|
break;
|
|
|
|
retval = xenfb_poll(xenfb, &readfds);
|
|
if (retval == -2)
|
|
xenfb_teardown(xenfb);
|
|
if (retval < 0)
|
|
break;
|
|
}
|
|
|
|
xenfb_delete(xenfb);
|
|
|
|
SDL_Quit();
|
|
|
|
return 0;
|
|
}
|