source: trunk/packages/xen-common/xen-common/tools/xenfb/sdlfb.c @ 95

Last change on this file since 95 was 34, checked in by hartmans, 17 years ago

Add xen and xen-common

File size: 7.2 KB
Line 
1#include <SDL.h>
2#include <errno.h>
3#include <sys/types.h>
4#include <sys/select.h>
5#include <stdlib.h>
6#include <linux/input.h>
7#include <getopt.h>
8#include <string.h>
9#include "xenfb.h"
10
11struct SDLFBData
12{
13        SDL_Surface *dst;
14        SDL_Surface *src;
15};
16
17/*
18 * Map from scancode to Linux input layer keycode.  Scancodes are
19 * hardware-specific.  This map assumes a standard AT or PS/2
20 * keyboard.
21 *
22 * Why use scancodes?  We can't use key symbols, because they don't
23 * identify keys --- they're what keys are mapped to.  The standard
24 * German keymap, for instance, maps both KEY_COMMA and KEY_102ND to
25 * SDLK_LESS.
26 */
27static int keymap[256] = {
28        [9] = KEY_ESC,
29        [10] = KEY_1,
30        [11] = KEY_2,
31        [12] = KEY_3,
32        [13] = KEY_4,
33        [14] = KEY_5,
34        [15] = KEY_6,
35        [16] = KEY_7,
36        [17] = KEY_8,
37        [18] = KEY_9,
38        [19] = KEY_0,
39        [20] = KEY_MINUS,
40        [21] = KEY_EQUAL,
41        [22] = KEY_BACKSPACE,
42        [23] = KEY_TAB,
43        [24] = KEY_Q,
44        [25] = KEY_W,
45        [26] = KEY_E,
46        [27] = KEY_R,
47        [28] = KEY_T,
48        [29] = KEY_Y,
49        [30] = KEY_U,
50        [31] = KEY_I,
51        [32] = KEY_O,
52        [33] = KEY_P,
53        [34] = KEY_LEFTBRACE,
54        [35] = KEY_RIGHTBRACE,
55        [36] = KEY_ENTER,
56        [37] = KEY_LEFTCTRL,
57        [38] = KEY_A,
58        [39] = KEY_S,
59        [40] = KEY_D,
60        [41] = KEY_F,
61        [42] = KEY_G,
62        [43] = KEY_H,
63        [44] = KEY_J,
64        [45] = KEY_K,
65        [46] = KEY_L,
66        [47] = KEY_SEMICOLON,
67        [48] = KEY_APOSTROPHE,
68        [49] = KEY_GRAVE,
69        [50] = KEY_LEFTSHIFT,
70        [51] = KEY_BACKSLASH,
71        [52] = KEY_Z,
72        [53] = KEY_X,
73        [54] = KEY_C,
74        [55] = KEY_V,
75        [56] = KEY_B,
76        [57] = KEY_N,
77        [58] = KEY_M,
78        [59] = KEY_COMMA,
79        [60] = KEY_DOT,
80        [61] = KEY_SLASH,
81        [62] = KEY_RIGHTSHIFT,
82        [63] = KEY_KPASTERISK,
83        [64] = KEY_LEFTALT,
84        [65] = KEY_SPACE,
85        [66] = KEY_CAPSLOCK,
86        [67] = KEY_F1,
87        [68] = KEY_F2,
88        [69] = KEY_F3,
89        [70] = KEY_F4,
90        [71] = KEY_F5,
91        [72] = KEY_F6,
92        [73] = KEY_F7,
93        [74] = KEY_F8,
94        [75] = KEY_F9,
95        [76] = KEY_F10,
96        [77] = KEY_NUMLOCK,
97        [78] = KEY_SCROLLLOCK,
98        [79] = KEY_KP7,
99        [80] = KEY_KP8,
100        [81] = KEY_KP9,
101        [82] = KEY_KPMINUS,
102        [83] = KEY_KP4,
103        [84] = KEY_KP5,
104        [85] = KEY_KP6,
105        [86] = KEY_KPPLUS,
106        [87] = KEY_KP1,
107        [88] = KEY_KP2,
108        [89] = KEY_KP3,
109        [90] = KEY_KP0,
110        [91] = KEY_KPDOT,
111        [94] = KEY_102ND,       /* FIXME is this correct? */
112        [95] = KEY_F11,
113        [96] = KEY_F12,
114        [108] = KEY_KPENTER,
115        [109] = KEY_RIGHTCTRL,
116        [112] = KEY_KPSLASH,
117        [111] = KEY_SYSRQ,
118        [113] = KEY_RIGHTALT,
119        [97] = KEY_HOME,
120        [98] = KEY_UP,
121        [99] = KEY_PAGEUP,
122        [100] = KEY_LEFT,
123        [102] = KEY_RIGHT,
124        [103] = KEY_END,
125        [104] = KEY_DOWN,
126        [105] = KEY_PAGEDOWN,
127        [106] = KEY_INSERT,
128        [107] = KEY_DELETE,
129        [110] = KEY_PAUSE,
130        [115] = KEY_LEFTMETA,
131        [116] = KEY_RIGHTMETA,
132        [117] = KEY_MENU,
133};
134
135static int btnmap[] = {
136        [SDL_BUTTON_LEFT] = BTN_LEFT,
137        [SDL_BUTTON_MIDDLE] = BTN_MIDDLE,
138        [SDL_BUTTON_RIGHT] = BTN_RIGHT,
139        /* FIXME not 100% sure about these: */
140        [SDL_BUTTON_WHEELUP] = BTN_FORWARD,
141        [SDL_BUTTON_WHEELDOWN] BTN_BACK
142};
143
144static void sdl_update(struct xenfb *xenfb, int x, int y, int width, int height)
145{
146        struct SDLFBData *data = xenfb->user_data;
147        SDL_Rect r = { x, y, width, height };
148        SDL_BlitSurface(data->src, &r, data->dst, &r);
149        SDL_UpdateRect(data->dst, x, y, width, height);
150}
151
152static int sdl_on_event(struct xenfb *xenfb, SDL_Event *event)
153{
154        int x, y, ret;
155
156        switch (event->type) {
157        case SDL_KEYDOWN:
158        case SDL_KEYUP:
159                if (keymap[event->key.keysym.scancode] == 0)
160                        break;
161                ret = xenfb_send_key(xenfb,
162                                     event->type == SDL_KEYDOWN,
163                                     keymap[event->key.keysym.scancode]);
164                if (ret < 0)
165                        fprintf(stderr, "Key %d %s lost (%s)\n",
166                                keymap[event->key.keysym.scancode],
167                                event->type == SDL_KEYDOWN ? "down" : "up",
168                                strerror(errno));
169                break;
170        case SDL_MOUSEMOTION:
171                if (xenfb->abs_pointer_wanted) {
172                        SDL_GetMouseState(&x, &y);
173                        ret = xenfb_send_position(xenfb, x, y);
174                } else {
175                        SDL_GetRelativeMouseState(&x, &y);
176                        ret = xenfb_send_motion(xenfb, x, y);
177                }
178                if (ret < 0)
179                        fprintf(stderr, "Pointer to %d,%d lost (%s)\n",
180                                x, y, strerror(errno));
181                break;
182        case SDL_MOUSEBUTTONDOWN:
183        case SDL_MOUSEBUTTONUP:
184                if (event->button.button >= sizeof(btnmap) / sizeof(*btnmap))
185                        break;
186                if (btnmap[event->button.button] == 0)
187                        break;
188                ret = xenfb_send_key(xenfb,
189                                     event->type == SDL_MOUSEBUTTONDOWN,
190                                     btnmap[event->button.button]);
191                if (ret < 0)
192                        fprintf(stderr, "Button %d %s lost (%s)\n",
193                                btnmap[event->button.button] - BTN_MOUSE,
194                                event->type == SDL_MOUSEBUTTONDOWN ? "down" : "up",
195                                strerror(errno));
196                break;
197        case SDL_QUIT:
198                return 0;
199        }
200
201        return 1;
202}
203
204static struct option options[] = {
205        { "domid", 1, NULL, 'd' },
206        { "title", 1, NULL, 't' },
207        { NULL }
208};
209
210int main(int argc, char **argv)
211{
212        struct xenfb *xenfb;
213        int domid = -1;
214        char * title = NULL;
215        fd_set readfds;
216        int nfds;
217        struct SDLFBData data;
218        SDL_Rect r;
219        struct timeval tv;
220        SDL_Event event;
221        int do_quit = 0;
222        int opt;
223        char *endp;
224        int retval;
225
226        while ((opt = getopt_long(argc, argv, "d:t:", options,
227                                  NULL)) != -1) {
228                switch (opt) {
229                case 'd':
230                        domid = strtol(optarg, &endp, 10);
231                        if (endp == optarg || *endp) {
232                                fprintf(stderr, "Invalid domain id specified\n");
233                                exit(1);
234                        }
235                        break;
236                case 't':
237                        title = strdup(optarg);
238                        break;
239                case '?':
240                        exit(1);
241                }
242        }
243        if (optind != argc) {
244                fprintf(stderr, "Invalid options!\n");
245                exit(1);
246        }
247        if (domid <= 0) {
248                fprintf(stderr, "Domain ID must be specified!\n");
249                exit(1);
250        }
251
252        xenfb = xenfb_new();
253        if (xenfb == NULL) {
254                fprintf(stderr, "Could not create framebuffer (%s)\n",
255                        strerror(errno));
256                exit(1);
257        }
258
259        if (xenfb_attach_dom(xenfb, domid) < 0) {
260                fprintf(stderr, "Could not connect to domain (%s)\n",
261                        strerror(errno));
262                exit(1);
263        }
264
265        if (SDL_Init(SDL_INIT_VIDEO) < 0) {
266                fprintf(stderr, "Could not initialize SDL\n");
267                exit(1);
268        }
269
270        data.dst = SDL_SetVideoMode(xenfb->width, xenfb->height, xenfb->depth,
271                                    SDL_SWSURFACE);
272        if (!data.dst) {
273                fprintf(stderr, "SDL_SetVideoMode failed\n");
274                exit(1);
275        }
276
277        data.src = SDL_CreateRGBSurfaceFrom(xenfb->pixels,
278                                            xenfb->width, xenfb->height,
279                                            xenfb->depth, xenfb->row_stride,
280                                            0xFF0000, 0xFF00, 0xFF, 0);
281
282        if (!data.src) {
283                fprintf(stderr, "SDL_CreateRGBSurfaceFrom failed\n");
284                exit(1);
285        }
286
287        if (title == NULL)
288                title = strdup("xen-sdlfb");
289        SDL_WM_SetCaption(title, title);
290
291        r.x = r.y = 0;
292        r.w = xenfb->width;
293        r.h = xenfb->height;
294        SDL_BlitSurface(data.src, &r, data.dst, &r);
295        SDL_UpdateRect(data.dst, 0, 0, xenfb->width, xenfb->height);
296
297        xenfb->update = sdl_update;
298        xenfb->user_data = &data;
299
300        SDL_ShowCursor(0);
301
302        /*
303         * We need to wait for fds becoming ready or SDL events to
304         * arrive.  We time out the select after 10ms to poll for SDL
305         * events.  Clunky, but works.  Could avoid the clunkiness
306         * with a separate thread.
307         */
308        for (;;) {
309                FD_ZERO(&readfds);
310                nfds = xenfb_select_fds(xenfb, &readfds);
311                tv = (struct timeval){0, 10000};
312
313                if (select(nfds, &readfds, NULL, NULL, &tv) < 0) {
314                        if (errno == EINTR)
315                                continue;
316                        fprintf(stderr,
317                                "Can't select() on event channel (%s)\n",
318                                strerror(errno));
319                        break;
320                }
321
322                while (SDL_PollEvent(&event)) {
323                        if (!sdl_on_event(xenfb, &event))
324                                do_quit = 1;
325                }
326
327                if (do_quit)
328                        break;
329
330                retval = xenfb_poll(xenfb, &readfds);
331                if (retval == -2)
332                    xenfb_teardown(xenfb);
333                if (retval < 0)
334                    break;
335        }
336
337        xenfb_delete(xenfb);
338
339        SDL_Quit();
340
341        return 0;
342}
Note: See TracBrowser for help on using the repository browser.