Skip to content

Commit 91e5c11

Browse files
committed
Add input event specific system calls
This commit integrates a new system call, syscall_poll_event, with SDL's event system, three types of input-specific events are supported: keyboard event, mouse motion event and mouse button event, this input system will improve the interactivity of the demos.
1 parent a99d779 commit 91e5c11

File tree

3 files changed

+163
-3
lines changed

3 files changed

+163
-3
lines changed

docs/syscall.md

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
# System Calls
2+
3+
## SDL-Oriented System Calls
4+
5+
### `syscall_draw_frame(screen, width, height)`
6+
Update the framebuffer of the given size, the window is lazy-initialized, if it does not exist when this system call is called, a new window will be created with the given width and height. This system call also poll events from SDL library, and update the internal input specific event queue if neccessary.
7+
8+
### `syscall_draw_frame_pal(screen, pal, width, height)`
9+
Same as `syscall_draw_frame`, but with indexed-coloring, `pal` is a RGB look up table which contains 256 distinct colors, all pixels in the framebuffer will be automatically mapped before drawing on the screen.
10+
11+
### `syscall_poll_event(event)`
12+
Poll a input-specific event from the event system, `event` should contains a 32-bit `type` field, and associated with a suitably sized value buffer, the internal event queue will be updated whenever `syscall_draw_frame` or `syscall_draw_frame_pal` is called.
13+
14+
The following types of event are currently supported:
15+
* `KEY_EVENT`(`0x0`): Triggered when the status of keyboard is changed, either a key is pressed or released, returns a 32-bit keycode and a 8-bit key state, the hexadecimal keycode values are listed here: https://wiki.libsdl.org/SDLKeycodeLookup
16+
* `MOUSE_MOTION_EVENT`(`0x1`): A mouse move event, with relative position information, two 32-bit signed integers which is correspond to the x and y delta value, the mouse is repeatedly wrapped in the window border by default.
17+
* `MOUSE_BUTTON_EVENT`(`0x2`): Whenever the state of a mouse button is changed, either a button is pressed or released, the user code will receive this event, it returns a 8-bit value indicates which button is updated(1 is left, 2 is middle, 3 is right and so on), and the 8-bit state value whether the button is pressed.

syscall.c

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -301,6 +301,7 @@ static void syscall_open(struct riscv_t *rv)
301301
#ifdef ENABLE_SDL
302302
extern void syscall_draw_frame(struct riscv_t *rv);
303303
extern void syscall_draw_frame_pal(struct riscv_t *rv);
304+
extern void syscall_poll_event(struct riscv_t *rv);
304305
#endif
305306

306307
void syscall_handler(struct riscv_t *rv)
@@ -343,6 +344,9 @@ void syscall_handler(struct riscv_t *rv)
343344
case 0xbabe:
344345
syscall_draw_frame_pal(rv);
345346
break;
347+
case 0xc0de:
348+
syscall_poll_event(rv);
349+
break;
346350
#endif
347351
default:
348352
fprintf(stderr, "unknown syscall %d\n", (int) syscall);

syscall_sdl.c

Lines changed: 142 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,71 @@
99

1010
#include "state.h"
1111

12+
#define MAX_EVENT_QUEUE_SIZE 128
13+
14+
enum {
15+
KEY_EVENT = 0,
16+
MOUSE_MOTION_EVENT = 1,
17+
MOUSE_BUTTON_EVENT = 2,
18+
};
19+
20+
typedef struct {
21+
uint32_t keycode;
22+
uint8_t state;
23+
} key_event_t;
24+
25+
typedef struct {
26+
int32_t xrel, yrel;
27+
} mouse_motion_t;
28+
29+
typedef struct {
30+
uint8_t button;
31+
uint8_t state;
32+
} mouse_button_t;
33+
34+
typedef struct {
35+
uint32_t type;
36+
union {
37+
key_event_t key_event;
38+
mouse_motion_t mouse_motion;
39+
mouse_button_t mouse_button;
40+
};
41+
} event_t;
42+
43+
typedef struct {
44+
event_t events[MAX_EVENT_QUEUE_SIZE];
45+
size_t start, end;
46+
bool full;
47+
} event_queue_t;
48+
1249
static SDL_Window *window = NULL;
1350
static SDL_Renderer *renderer;
1451
static SDL_Texture *texture;
52+
static event_queue_t event_queue = {
53+
.events = {},
54+
.start = 0,
55+
.end = 0,
56+
.full = false,
57+
};
58+
59+
static bool event_pop(event_t *event)
60+
{
61+
if (event_queue.start == event_queue.end)
62+
return false;
63+
*event = event_queue.events[event_queue.start++];
64+
event_queue.start &= MAX_EVENT_QUEUE_SIZE - 1;
65+
event_queue.full = false;
66+
return true;
67+
}
68+
69+
static void event_push(event_t event)
70+
{
71+
if (event_queue.full)
72+
return;
73+
event_queue.events[event_queue.end++] = event;
74+
event_queue.end &= MAX_EVENT_QUEUE_SIZE - 1;
75+
event_queue.full = (event_queue.start == event_queue.end);
76+
}
1577

1678
/* check if we need to setup SDL and run event loop */
1779
static bool check_sdl(struct riscv_t *rv, uint32_t width, uint32_t height)
@@ -43,10 +105,55 @@ static bool check_sdl(struct riscv_t *rv, uint32_t width, uint32_t height)
43105
rv_halt(rv);
44106
return false;
45107
case SDL_KEYDOWN:
46-
if (event.key.keysym.sym == SDLK_ESCAPE) {
47-
rv_halt(rv);
48-
return false;
108+
if (event.key.keysym.sym == SDLK_ESCAPE &&
109+
SDL_GetRelativeMouseMode() == SDL_TRUE) {
110+
SDL_SetRelativeMouseMode(SDL_FALSE);
111+
break;
49112
}
113+
/* fall through */
114+
case SDL_KEYUP: {
115+
if (event.key.repeat)
116+
break;
117+
event_t new_event = {
118+
.type = KEY_EVENT,
119+
.key_event =
120+
{
121+
.keycode = event.key.keysym.sym,
122+
.state = (bool) (event.key.state == SDL_PRESSED),
123+
},
124+
};
125+
event_push(new_event);
126+
break;
127+
}
128+
case SDL_MOUSEMOTION: {
129+
event_t new_event = {
130+
.type = MOUSE_MOTION_EVENT,
131+
.mouse_motion =
132+
{
133+
.xrel = event.motion.xrel,
134+
.yrel = event.motion.yrel,
135+
},
136+
};
137+
event_push(new_event);
138+
break;
139+
}
140+
case SDL_MOUSEBUTTONDOWN:
141+
if (event.button.button == SDL_BUTTON_LEFT &&
142+
SDL_GetRelativeMouseMode() == SDL_FALSE) {
143+
SDL_SetRelativeMouseMode(SDL_TRUE);
144+
break;
145+
}
146+
/* fall through */
147+
case SDL_MOUSEBUTTONUP: {
148+
event_t new_event = {
149+
.type = MOUSE_BUTTON_EVENT,
150+
.mouse_button = {
151+
.button = event.button.button,
152+
.state = (bool) (event.button.state == SDL_PRESSED),
153+
}};
154+
event_push(new_event);
155+
break;
156+
}
50157
}
51158
}
52159
return true;
@@ -118,3 +225,35 @@ void syscall_draw_frame_pal(struct riscv_t *rv)
118225
free(i);
119226
free(j);
120227
}
228+
229+
void syscall_poll_event(struct riscv_t *rv)
230+
{
231+
state_t *s = rv_userdata(rv); /* access userdata */
232+
233+
/* poll_event(base) */
234+
const uint32_t base = rv_get_reg(rv, rv_reg_a0);
235+
236+
event_t event;
237+
if (!event_pop(&event)) {
238+
rv_set_reg(rv, rv_reg_a0, 0);
239+
return;
240+
}
241+
242+
memory_write(s->mem, base + 0, (const uint8_t *) &event.type, 4);
243+
switch (event.type) {
244+
case KEY_EVENT:
245+
memory_write(s->mem, base + 4, (const uint8_t *) &event.key_event,
246+
sizeof(key_event_t));
247+
break;
248+
case MOUSE_MOTION_EVENT:
249+
memory_write(s->mem, base + 4, (const uint8_t *) &event.mouse_motion,
250+
sizeof(mouse_motion_t));
251+
break;
252+
case MOUSE_BUTTON_EVENT:
253+
memory_write(s->mem, base + 4, (const uint8_t *) &event.mouse_button,
254+
sizeof(mouse_button_t));
255+
break;
256+
}
257+
258+
rv_set_reg(rv, rv_reg_a0, 1);
259+
}

0 commit comments

Comments
 (0)