Skip to content

Commit ad1e1d8

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 ad1e1d8

File tree

3 files changed

+169
-3
lines changed

3 files changed

+169
-3
lines changed

docs/syscall.md

+19
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
# System Calls
2+
3+
## Experimental Display and Event System Calls
4+
5+
These system calls are experimental for demonstration of RISC-V graphics applications, they don't exist in the ABI interface of POSIX and Linux, and are only for the convenience of accessing the SDL library.
6+
7+
### `syscall_draw_frame(screen, width, height)`
8+
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.
9+
10+
### `syscall_draw_frame_pal(screen, pal, width, height)`
11+
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.
12+
13+
### `syscall_poll_event(event)`
14+
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.
15+
16+
The following types of event are currently supported:
17+
* `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 in [SDL Keycode Lookup Table](https://wiki.libsdl.org/SDLKeycodeLookup)
18+
* `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.
19+
* `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

+4
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

+146-3
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,75 @@
99

1010
#include "state.h"
1111

12+
/* For optimization, the capcity of event queues must be the power of two to
13+
* avoid the expensive modulo operation, the details are explained here:
14+
* https://stackoverflow.com/questions/10527581/why-must-a-ring-buffer-size-be-a-power-of-2
15+
*/
16+
#define EVENT_QUEUE_CAPACITY 128
17+
18+
enum {
19+
KEY_EVENT = 0,
20+
MOUSE_MOTION_EVENT = 1,
21+
MOUSE_BUTTON_EVENT = 2,
22+
};
23+
24+
typedef struct {
25+
uint32_t keycode;
26+
uint8_t state;
27+
} key_event_t;
28+
29+
typedef struct {
30+
int32_t xrel, yrel;
31+
} mouse_motion_t;
32+
33+
typedef struct {
34+
uint8_t button;
35+
uint8_t state;
36+
} mouse_button_t;
37+
38+
typedef struct {
39+
uint32_t type;
40+
union {
41+
key_event_t key_event;
42+
mouse_motion_t mouse_motion;
43+
mouse_button_t mouse_button;
44+
};
45+
} event_t;
46+
47+
typedef struct {
48+
event_t events[EVENT_QUEUE_CAPACITY];
49+
size_t start, end;
50+
bool full;
51+
} event_queue_t;
52+
1253
static SDL_Window *window = NULL;
1354
static SDL_Renderer *renderer;
1455
static SDL_Texture *texture;
56+
static event_queue_t event_queue = {
57+
.events = {},
58+
.start = 0,
59+
.end = 0,
60+
.full = false,
61+
};
62+
63+
static bool event_pop(event_t *event)
64+
{
65+
if (event_queue.start == event_queue.end)
66+
return false;
67+
*event = event_queue.events[event_queue.start++];
68+
event_queue.start &= EVENT_QUEUE_CAPACITY - 1;
69+
event_queue.full = false;
70+
return true;
71+
}
72+
73+
static void event_push(event_t event)
74+
{
75+
if (event_queue.full)
76+
return;
77+
event_queue.events[event_queue.end++] = event;
78+
event_queue.end &= EVENT_QUEUE_CAPACITY - 1;
79+
event_queue.full = (event_queue.start == event_queue.end);
80+
}
1581

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

0 commit comments

Comments
 (0)