Flesh out keyboard support in examples
This commit is contained in:
		
							parent
							
								
									e257afeb7e
								
							
						
					
					
						commit
						6bf7e095cf
					
				|  | @ -7,6 +7,7 @@ | |||
| #include <unistd.h> | ||||
| #include <wayland-server.h> | ||||
| #include <wayland-server-protocol.h> | ||||
| #include <xkbcommon/xkbcommon.h> | ||||
| #include <GLES3/gl3.h> | ||||
| #include <wlr/render/matrix.h> | ||||
| #include <wlr/render/gles3.h> | ||||
|  | @ -18,10 +19,19 @@ | |||
| #include "cat.h" | ||||
| 
 | ||||
| struct state { | ||||
| 	struct wl_list config; | ||||
| 	struct xkb_keymap *keymap; | ||||
| 	struct xkb_state *xkb_state; | ||||
| 	bool exit; | ||||
| 
 | ||||
| 	struct wl_list keyboards; | ||||
| 	struct wl_listener input_add; | ||||
| 	struct wl_listener input_remove; | ||||
| 
 | ||||
| 	struct wl_list outputs; | ||||
| 	struct wl_listener output_add; | ||||
| 	struct wl_listener output_remove; | ||||
| 	struct wl_list outputs; | ||||
| 	struct wl_list config; | ||||
| 
 | ||||
| 	struct wlr_renderer *renderer; | ||||
| 	struct wlr_surface *cat_texture; | ||||
| }; | ||||
|  | @ -33,6 +43,7 @@ struct output_state { | |||
| 	struct state *state; | ||||
| 	struct wl_listener frame; | ||||
| 	float x_offs, y_offs; | ||||
| 	float x_vel, y_vel; | ||||
| }; | ||||
| 
 | ||||
| struct output_config { | ||||
|  | @ -41,6 +52,13 @@ struct output_config { | |||
| 	struct wl_list link; | ||||
| }; | ||||
| 
 | ||||
| struct keyboard_state { | ||||
| 	struct state *state; | ||||
| 	struct wlr_input_device *device; | ||||
| 	struct wl_listener key; | ||||
| 	struct wl_list link; | ||||
| }; | ||||
| 
 | ||||
| static void output_frame(struct wl_listener *listener, void *data) { | ||||
| 	struct output_state *ostate = wl_container_of(listener, ostate, frame); | ||||
| 	struct wlr_output *output = ostate->output; | ||||
|  | @ -68,8 +86,8 @@ static void output_frame(struct wl_listener *listener, void *data) { | |||
| 		(now.tv_nsec - ostate->last_frame.tv_nsec) / 1000000; | ||||
| 	float seconds = ms / 1000.0f; | ||||
| 
 | ||||
| 	ostate->x_offs += 128 * seconds; | ||||
| 	ostate->y_offs += 128 * seconds; | ||||
| 	ostate->x_offs += ostate->x_vel * seconds; | ||||
| 	ostate->y_offs += ostate->y_vel * seconds; | ||||
| 	if (ostate->x_offs > 128) ostate->x_offs = 0; | ||||
| 	if (ostate->y_offs > 128) ostate->y_offs = 0; | ||||
| 	ostate->last_frame = now; | ||||
|  | @ -89,6 +107,7 @@ static void output_add(struct wl_listener *listener, void *data) { | |||
| 	ostate->state = state; | ||||
| 	ostate->frame.notify = output_frame; | ||||
| 	ostate->x_offs = ostate->y_offs = 0; | ||||
| 	ostate->x_vel = ostate->y_vel = 128; | ||||
| 
 | ||||
| 	struct output_config *conf; | ||||
| 	wl_list_for_each(conf, &state->config, link) { | ||||
|  | @ -118,9 +137,91 @@ static void output_remove(struct wl_listener *listener, void *data) { | |||
| 	} | ||||
| } | ||||
| 
 | ||||
| static int timer_done(void *data) { | ||||
| 	*(bool *)data = true; | ||||
| 	return 1; | ||||
| static void update_velocities(struct state *state, float x_diff, float y_diff) { | ||||
| 	struct output_state *ostate; | ||||
| 	wl_list_for_each(ostate, &state->outputs, link) { | ||||
| 		ostate->x_vel += x_diff; | ||||
| 		ostate->y_vel += y_diff; | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| static void handle_keysym(struct state *state, xkb_keysym_t sym, | ||||
| 		enum wlr_key_state key_state) { | ||||
| 	char name[64]; | ||||
| 	int l = xkb_keysym_get_name(sym, name, sizeof(name)); | ||||
| 	if (l != -1 && l != sizeof(name)) { | ||||
| 		fprintf(stderr, "Key event: %s %s\n", name, | ||||
| 				key_state == WLR_KEY_PRESSED ? "pressed" : "released"); | ||||
| 	} | ||||
| 	// NOTE: It may be better to simply refer to our key state during each frame
 | ||||
| 	// and make this change in pixels/sec^2
 | ||||
| 	if (key_state == WLR_KEY_PRESSED) { | ||||
| 		switch (sym) { | ||||
| 		case XKB_KEY_Escape: | ||||
| 			state->exit = true; | ||||
| 			break; | ||||
| 		case XKB_KEY_Left: | ||||
| 			update_velocities(state, -16, 0); | ||||
| 			break; | ||||
| 		case XKB_KEY_Right: | ||||
| 			update_velocities(state, 16, 0); | ||||
| 			break; | ||||
| 		case XKB_KEY_Up: | ||||
| 			update_velocities(state, 0, -16); | ||||
| 			break; | ||||
| 		case XKB_KEY_Down: | ||||
| 			update_velocities(state, 0, 16); | ||||
| 			break; | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| static void keyboard_key(struct wl_listener *listener, void *data) { | ||||
| 	struct wlr_keyboard_key *event = data; | ||||
| 	struct keyboard_state *kbstate = wl_container_of(listener, kbstate, key); | ||||
| 	uint32_t keycode = event->keycode + 8; | ||||
| 	const xkb_keysym_t *syms; | ||||
| 	int nsyms = xkb_state_key_get_syms(kbstate->state->xkb_state, keycode, &syms); | ||||
| 	for (int i = 0; i < nsyms; ++i) { | ||||
| 		handle_keysym(kbstate->state, syms[i], event->state); | ||||
| 	} | ||||
| 	xkb_state_update_key(kbstate->state->xkb_state, keycode, | ||||
| 		event->state == WLR_KEY_PRESSED ?  XKB_KEY_DOWN : XKB_KEY_UP); | ||||
| } | ||||
| 
 | ||||
| void input_add(struct wl_listener *listener, void *data) { | ||||
| 	struct wlr_input_device *device = data; | ||||
| 	struct state *state = wl_container_of(listener, state, input_add); | ||||
| 	if (device->type != WLR_INPUT_DEVICE_KEYBOARD) { | ||||
| 		return; | ||||
| 	} | ||||
| 	struct keyboard_state *kbstate = calloc(sizeof(struct keyboard_state), 1); | ||||
| 	kbstate->device = device; | ||||
| 	kbstate->state = state; | ||||
| 	wl_list_init(&kbstate->key.link); | ||||
| 	kbstate->key.notify = keyboard_key; | ||||
| 	wl_signal_add(&device->keyboard->events.key, &kbstate->key); | ||||
| 	wl_list_insert(&state->keyboards, &kbstate->link); | ||||
| } | ||||
| 
 | ||||
| void input_remove(struct wl_listener *listener, void *data) { | ||||
| 	struct wlr_input_device *device = data; | ||||
| 	struct state *state = wl_container_of(listener, state, input_add); | ||||
| 	if (device->type != WLR_INPUT_DEVICE_KEYBOARD) { | ||||
| 		return; | ||||
| 	} | ||||
| 	struct keyboard_state *kbstate = NULL, *_kbstate; | ||||
| 	wl_list_for_each(_kbstate, &state->keyboards, link) { | ||||
| 		if (_kbstate->device == device) { | ||||
| 			kbstate = kbstate; | ||||
| 			break; | ||||
| 		} | ||||
| 	} | ||||
| 	if (!kbstate) { | ||||
| 		return; // We are unfamiliar with this keyboard
 | ||||
| 	} | ||||
| 	wl_list_remove(&kbstate->link); | ||||
| 	wl_list_remove(&kbstate->key.link); | ||||
| } | ||||
| 
 | ||||
| static void usage(const char *name, int ret) { | ||||
|  | @ -191,10 +292,38 @@ static void parse_args(int argc, char *argv[], struct wl_list *config) { | |||
| 
 | ||||
| int main(int argc, char *argv[]) { | ||||
| 	struct state state = { | ||||
| 		.exit = false, | ||||
| 		.input_add = { .notify = input_add }, | ||||
| 		.input_remove = { .notify = input_remove }, | ||||
| 		.output_add = { .notify = output_add }, | ||||
| 		.output_remove = { .notify = output_remove } | ||||
| 	}; | ||||
| 
 | ||||
| 	struct xkb_rule_names rules; | ||||
| 	memset(&rules, 0, sizeof(rules)); | ||||
| 	rules.rules = getenv("XKB_DEFAULT_RULES"); | ||||
| 	rules.model = getenv("XKB_DEFAULT_MODEL"); | ||||
| 	rules.layout = getenv("XKB_DEFAULT_LAYOUT"); | ||||
| 	rules.variant = getenv("XKB_DEFAULT_VARIANT"); | ||||
| 	rules.options = getenv("XKB_DEFAULT_OPTIONS"); | ||||
| 	struct xkb_context *context = xkb_context_new(XKB_CONTEXT_NO_FLAGS); | ||||
| 	if (!context) { | ||||
| 		fprintf(stderr, "Failed to create XKB context\n"); | ||||
| 		return 1; | ||||
| 	} | ||||
| 	state.keymap = | ||||
| 		xkb_map_new_from_names(context, &rules, XKB_KEYMAP_COMPILE_NO_FLAGS); | ||||
| 	if (!state.keymap) { | ||||
| 		fprintf(stderr, "Failed to create XKB keymap\n"); | ||||
| 		return 1; | ||||
| 	} | ||||
| 	xkb_context_unref(context); | ||||
| 	state.xkb_state = xkb_state_new(state.keymap); | ||||
| 
 | ||||
| 	wl_list_init(&state.keyboards); | ||||
| 	wl_list_init(&state.input_add.link); | ||||
| 	wl_list_init(&state.input_remove.link); | ||||
| 
 | ||||
| 	wl_list_init(&state.outputs); | ||||
| 	wl_list_init(&state.config); | ||||
| 	wl_list_init(&state.output_add.link); | ||||
|  | @ -215,10 +344,11 @@ int main(int argc, char *argv[]) { | |||
| 		return 1; | ||||
| 	} | ||||
| 
 | ||||
| 	wl_signal_add(&wlr->events.input_add, &state.input_add); | ||||
| 	wl_signal_add(&wlr->events.input_remove, &state.input_remove); | ||||
| 	wl_signal_add(&wlr->events.output_add, &state.output_add); | ||||
| 	wl_signal_add(&wlr->events.output_remove, &state.output_remove); | ||||
| 
 | ||||
| 	if (!wlr_backend_init(wlr)) { | ||||
| 	if (!wlr || !wlr_backend_init(wlr)) { | ||||
| 		printf("Failed to initialize backend, bailing out\n"); | ||||
| 		return 1; | ||||
| 	} | ||||
|  | @ -228,17 +358,10 @@ int main(int argc, char *argv[]) { | |||
| 	wlr_surface_attach_pixels(state.cat_texture, GL_RGB, | ||||
| 		cat_tex.width, cat_tex.height, cat_tex.pixel_data); | ||||
| 
 | ||||
| 	bool done = false; | ||||
| 	struct wl_event_source *timer = wl_event_loop_add_timer(event_loop, | ||||
| 		timer_done, &done); | ||||
| 
 | ||||
| 	wl_event_source_timer_update(timer, 30000); | ||||
| 
 | ||||
| 	while (!done) { | ||||
| 	while (!state.exit) { | ||||
| 		wl_event_loop_dispatch(event_loop, 0); | ||||
| 	} | ||||
| 
 | ||||
| 	wl_event_source_remove(timer); | ||||
| 	wlr_backend_destroy(wlr); | ||||
| 	wlr_session_finish(session); | ||||
| 	wlr_surface_destroy(state.cat_texture); | ||||
|  |  | |||
|  | @ -162,12 +162,6 @@ void input_remove(struct wl_listener *listener, void *data) { | |||
| 	wl_list_remove(&kbstate->key.link); | ||||
| } | ||||
| 
 | ||||
| static int timer_done(void *data) { | ||||
| 	struct state *state = data; | ||||
| 	state->exit = true; | ||||
| 	return 1; | ||||
| } | ||||
| 
 | ||||
| int main() { | ||||
| 	struct state state = { | ||||
| 		.color = { 1.0, 0.0, 0.0 }, | ||||
|  | @ -225,10 +219,6 @@ int main() { | |||
| 	if (!wlr || !wlr_backend_init(wlr)) { | ||||
| 		return 1; | ||||
| 	} | ||||
| 	struct wl_event_source *timer = wl_event_loop_add_timer(event_loop, | ||||
| 		timer_done, &state); | ||||
| 
 | ||||
| 	wl_event_source_timer_update(timer, 30000); | ||||
| 
 | ||||
| 	while (!state.exit) { | ||||
| 		wl_event_loop_dispatch(event_loop, 0); | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue