diff options
| author | Mitchell Riedstra <mitch@riedstra.dev> | 2025-12-24 19:49:57 -0500 |
|---|---|---|
| committer | Mitchell Riedstra <mitch@riedstra.dev> | 2025-12-24 19:49:57 -0500 |
| commit | 939ac4319cb047a37ba46f84eff81948063f6954 (patch) | |
| tree | 5112cf8aad73125a13f5b52c0290a7f26f948b52 /jslinux-2019-12-21/tinyemu-2019-12-21/sdl.c | |
| parent | 3a1b5ba15b89c907f9bf66a0761ffdd73b32208b (diff) | |
| download | unixv4-939ac4319cb047a37ba46f84eff81948063f6954.tar.gz unixv4-939ac4319cb047a37ba46f84eff81948063f6954.tar.xz | |
Add working webpage for unix v4
Diffstat (limited to 'jslinux-2019-12-21/tinyemu-2019-12-21/sdl.c')
| -rw-r--r-- | jslinux-2019-12-21/tinyemu-2019-12-21/sdl.c | 275 |
1 files changed, 275 insertions, 0 deletions
diff --git a/jslinux-2019-12-21/tinyemu-2019-12-21/sdl.c b/jslinux-2019-12-21/tinyemu-2019-12-21/sdl.c new file mode 100644 index 0000000..c2afeba --- /dev/null +++ b/jslinux-2019-12-21/tinyemu-2019-12-21/sdl.c @@ -0,0 +1,275 @@ +/* + * SDL display driver + * + * Copyright (c) 2017 Fabrice Bellard + * + * 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 <stdlib.h> +#include <stdio.h> +#include <stdarg.h> +#include <string.h> +#include <inttypes.h> +#include <assert.h> +#include <fcntl.h> +#include <errno.h> + +#include <SDL/SDL.h> + +#include "cutils.h" +#include "virtio.h" +#include "machine.h" + +#define KEYCODE_MAX 127 + +static SDL_Surface *screen; +static SDL_Surface *fb_surface; +static int screen_width, screen_height, fb_width, fb_height, fb_stride; +static SDL_Cursor *sdl_cursor_hidden; +static uint8_t key_pressed[KEYCODE_MAX + 1]; + +static void sdl_update_fb_surface(FBDevice *fb_dev) +{ + if (!fb_surface) + goto force_alloc; + if (fb_width != fb_dev->width || + fb_height != fb_dev->height || + fb_stride != fb_dev->stride) { + force_alloc: + if (fb_surface != NULL) + SDL_FreeSurface(fb_surface); + fb_width = fb_dev->width; + fb_height = fb_dev->height; + fb_stride = fb_dev->stride; + fb_surface = SDL_CreateRGBSurfaceFrom(fb_dev->fb_data, + fb_dev->width, fb_dev->height, + 32, fb_dev->stride, + 0x00ff0000, + 0x0000ff00, + 0x000000ff, + 0x00000000); + if (!fb_surface) { + fprintf(stderr, "Could not create SDL framebuffer surface\n"); + exit(1); + } + } +} + +static void sdl_update(FBDevice *fb_dev, void *opaque, + int x, int y, int w, int h) +{ + SDL_Rect r; + // printf("sdl_update: %d %d %d %d\n", x, y, w, h); + r.x = x; + r.y = y; + r.w = w; + r.h = h; + SDL_BlitSurface(fb_surface, &r, screen, &r); + SDL_UpdateRect(screen, r.x, r.y, r.w, r.h); +} + +#if defined(_WIN32) + +static int sdl_get_keycode(const SDL_KeyboardEvent *ev) +{ + return ev->keysym.scancode; +} + +#else + +/* we assume Xorg is used with a PC keyboard. Return 0 if no keycode found. */ +static int sdl_get_keycode(const SDL_KeyboardEvent *ev) +{ + int keycode; + keycode = ev->keysym.scancode; + if (keycode < 9) { + keycode = 0; + } else if (keycode < 127 + 8) { + keycode -= 8; + } else { + keycode = 0; + } + return keycode; +} + +#endif + +/* release all pressed keys */ +static void sdl_reset_keys(VirtMachine *m) +{ + int i; + + for(i = 1; i <= KEYCODE_MAX; i++) { + if (key_pressed[i]) { + vm_send_key_event(m, FALSE, i); + key_pressed[i] = FALSE; + } + } +} + +static void sdl_handle_key_event(const SDL_KeyboardEvent *ev, VirtMachine *m) +{ + int keycode, keypress; + + keycode = sdl_get_keycode(ev); + if (keycode) { + if (keycode == 0x3a || keycode ==0x45) { + /* SDL does not generate key up for numlock & caps lock */ + vm_send_key_event(m, TRUE, keycode); + vm_send_key_event(m, FALSE, keycode); + } else { + keypress = (ev->type == SDL_KEYDOWN); + if (keycode <= KEYCODE_MAX) + key_pressed[keycode] = keypress; + vm_send_key_event(m, keypress, keycode); + } + } else if (ev->type == SDL_KEYUP) { + /* workaround to reset the keyboard state (used when changing + desktop with ctrl-alt-x on Linux) */ + sdl_reset_keys(m); + } +} + +static void sdl_send_mouse_event(VirtMachine *m, int x1, int y1, + int dz, int state, BOOL is_absolute) +{ + int buttons, x, y; + + buttons = 0; + if (state & SDL_BUTTON(SDL_BUTTON_LEFT)) + buttons |= (1 << 0); + if (state & SDL_BUTTON(SDL_BUTTON_RIGHT)) + buttons |= (1 << 1); + if (state & SDL_BUTTON(SDL_BUTTON_MIDDLE)) + buttons |= (1 << 2); + if (is_absolute) { + x = (x1 * 32768) / screen_width; + y = (y1 * 32768) / screen_height; + } else { + x = x1; + y = y1; + } + vm_send_mouse_event(m, x, y, dz, buttons); +} + +static void sdl_handle_mouse_motion_event(const SDL_Event *ev, VirtMachine *m) +{ + BOOL is_absolute = vm_mouse_is_absolute(m); + int x, y; + if (is_absolute) { + x = ev->motion.x; + y = ev->motion.y; + } else { + x = ev->motion.xrel; + y = ev->motion.yrel; + } + sdl_send_mouse_event(m, x, y, 0, ev->motion.state, is_absolute); +} + +static void sdl_handle_mouse_button_event(const SDL_Event *ev, VirtMachine *m) +{ + BOOL is_absolute = vm_mouse_is_absolute(m); + int state, dz; + + dz = 0; + if (ev->type == SDL_MOUSEBUTTONDOWN) { + if (ev->button.button == SDL_BUTTON_WHEELUP) { + dz = 1; + } else if (ev->button.button == SDL_BUTTON_WHEELDOWN) { + dz = -1; + } + } + + state = SDL_GetMouseState(NULL, NULL); + /* just in case */ + if (ev->type == SDL_MOUSEBUTTONDOWN) + state |= SDL_BUTTON(ev->button.button); + else + state &= ~SDL_BUTTON(ev->button.button); + + if (is_absolute) { + sdl_send_mouse_event(m, ev->button.x, ev->button.y, + dz, state, is_absolute); + } else { + sdl_send_mouse_event(m, 0, 0, dz, state, is_absolute); + } +} + +void sdl_refresh(VirtMachine *m) +{ + SDL_Event ev_s, *ev = &ev_s; + + if (!m->fb_dev) + return; + + sdl_update_fb_surface(m->fb_dev); + + m->fb_dev->refresh(m->fb_dev, sdl_update, NULL); + + while (SDL_PollEvent(ev)) { + switch (ev->type) { + case SDL_KEYDOWN: + case SDL_KEYUP: + sdl_handle_key_event(&ev->key, m); + break; + case SDL_MOUSEMOTION: + sdl_handle_mouse_motion_event(ev, m); + break; + case SDL_MOUSEBUTTONDOWN: + case SDL_MOUSEBUTTONUP: + sdl_handle_mouse_button_event(ev, m); + break; + case SDL_QUIT: + exit(0); + } + } +} + +static void sdl_hide_cursor(void) +{ + uint8_t data = 0; + sdl_cursor_hidden = SDL_CreateCursor(&data, &data, 8, 1, 0, 0); + SDL_ShowCursor(1); + SDL_SetCursor(sdl_cursor_hidden); +} + +void sdl_init(int width, int height) +{ + int flags; + + screen_width = width; + screen_height = height; + + if (SDL_Init (SDL_INIT_VIDEO | SDL_INIT_NOPARACHUTE)) { + fprintf(stderr, "Could not initialize SDL - exiting\n"); + exit(1); + } + + flags = SDL_HWSURFACE | SDL_ASYNCBLIT | SDL_HWACCEL; + screen = SDL_SetVideoMode(width, height, 0, flags); + if (!screen || !screen->pixels) { + fprintf(stderr, "Could not open SDL display\n"); + exit(1); + } + + SDL_WM_SetCaption("TinyEMU", "TinyEMU"); + + sdl_hide_cursor(); +} + |
