mirror of
https://codeberg.org/dnkl/foot.git
synced 2026-02-04 04:06:06 -05:00
wip: initial input handling
This commit is contained in:
parent
3bd77bceb1
commit
71dde121e6
9 changed files with 484 additions and 51 deletions
101
csi.c
101
csi.c
|
|
@ -107,51 +107,124 @@ csi_dispatch(struct terminal *term, uint8_t final)
|
|||
if (term->vt.intermediates.idx == 0) {
|
||||
switch (final) {
|
||||
case 'c':
|
||||
write(term->ptmx, "\033[?6c", 5);
|
||||
return true;
|
||||
return write(term->ptmx, "\033[?6c", 5) == 5;
|
||||
|
||||
case 'm':
|
||||
return csi_sgr(term);
|
||||
|
||||
case 'J': {
|
||||
assert(term->vt.params.idx == 0);
|
||||
int start = grid_cursor_linear(&term->grid, term->grid.cursor.row, 0);
|
||||
int end = term->grid.cols * term->grid.rows;
|
||||
/* Erase screen */
|
||||
|
||||
int param = 0;
|
||||
if (term->vt.params.idx >= 1)
|
||||
param = term->vt.params.v[0].value;
|
||||
|
||||
int start = -1;
|
||||
int end = -1;
|
||||
switch (param) {
|
||||
case 0:
|
||||
/* From cursor to end of screen */
|
||||
start = term->grid.linear_cursor;
|
||||
end = term->grid.cols * term->grid.rows;
|
||||
break;
|
||||
|
||||
case 1:
|
||||
/* From start of screen to cursor */
|
||||
start = 0;
|
||||
end = term->grid.linear_cursor;
|
||||
break;
|
||||
|
||||
case 2:
|
||||
/* Erase entire screen */
|
||||
start = 0;
|
||||
end = term->grid.cols * term->grid.rows;
|
||||
break;
|
||||
|
||||
default:
|
||||
LOG_ERR("CSI: J: invalid argument: %d", param);
|
||||
return false;
|
||||
}
|
||||
|
||||
grid_erase(&term->grid, start, end);
|
||||
return true;
|
||||
break;
|
||||
}
|
||||
|
||||
case 'K': {
|
||||
assert(term->vt.params.idx == 0);
|
||||
int start = term->grid.linear_cursor;
|
||||
int end = grid_cursor_linear(
|
||||
&term->grid, term->grid.cursor.row, term->grid.cols - 1);
|
||||
LOG_DBG("K: %d -> %d", start, end);
|
||||
/* Erase line */
|
||||
|
||||
int param = 0;
|
||||
if (term->vt.params.idx >= 0)
|
||||
param = term->vt.params.v[0].value;
|
||||
|
||||
int start = -1;
|
||||
int end = -1;
|
||||
switch (param) {
|
||||
case 0:
|
||||
/* From cursor to end of line */
|
||||
start = term->grid.linear_cursor;
|
||||
end = grid_cursor_linear(
|
||||
&term->grid, term->grid.cursor.row, term->grid.cols - 1);
|
||||
break;
|
||||
|
||||
case 1:
|
||||
/* From start of line to cursor */
|
||||
start = grid_cursor_linear(
|
||||
&term->grid, term->grid.cursor.row, 0);
|
||||
end = term->grid.linear_cursor;
|
||||
break;
|
||||
|
||||
case 2:
|
||||
/* Entire line */
|
||||
start = grid_cursor_linear(
|
||||
&term->grid, term->grid.cursor.row, 0);
|
||||
end = grid_cursor_linear(
|
||||
&term->grid, term->grid.cursor.row, term->grid.cols - 1);
|
||||
break;
|
||||
|
||||
default:
|
||||
LOG_ERR("CSI: K: invalid argument: %d", param);
|
||||
return false;
|
||||
}
|
||||
|
||||
grid_erase(&term->grid, start, end);
|
||||
return true;
|
||||
break;
|
||||
}
|
||||
|
||||
case 'A': {
|
||||
int count = term->vt.params.idx > 0 ? term->vt.params.v[0].value : 1;
|
||||
grid_cursor_up(&term->grid, count);
|
||||
break;
|
||||
}
|
||||
|
||||
case 'B': {
|
||||
int count = term->vt.params.idx > 0 ? term->vt.params.v[0].value : 1;
|
||||
grid_cursor_up(&term->grid, count);
|
||||
break;
|
||||
}
|
||||
|
||||
case 'C': {
|
||||
int count = term->vt.params.idx > 0 ? term->vt.params.v[0].value : 1;
|
||||
grid_cursor_right(&term->grid, count);
|
||||
return true;
|
||||
break;
|
||||
}
|
||||
|
||||
case 'D': {
|
||||
int count = term->vt.params.idx > 0 ? term->vt.params.v[0].value : 1;
|
||||
grid_cursor_left(&term->grid, count);
|
||||
return true;
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
LOG_ERR("CSI: unimplemented final: %c", final);
|
||||
abort();
|
||||
}
|
||||
|
||||
return true;
|
||||
} else {
|
||||
LOG_ERR("CSI: unimplemented: intermediates: %.*s",
|
||||
(int)term->vt.intermediates.idx,
|
||||
term->vt.intermediates.data);
|
||||
|
||||
//abort();
|
||||
return true;
|
||||
}
|
||||
|
|
|
|||
48
grid.c
48
grid.c
|
|
@ -53,42 +53,26 @@ void
|
|||
grid_cursor_left(struct grid *grid, int count)
|
||||
{
|
||||
int move_amount = min(grid->cursor.col, count);
|
||||
int new_linear = grid->linear_cursor - move_amount;
|
||||
int new_col = grid->cursor.col - move_amount;
|
||||
|
||||
assert(new_linear >= 0);
|
||||
assert(new_linear < grid->rows * grid->cols);
|
||||
assert(new_col >= 0);
|
||||
assert(new_col < grid->cols);
|
||||
|
||||
grid->cells[grid->linear_cursor].dirty = true;
|
||||
grid->cells[new_linear].dirty = true;
|
||||
|
||||
grid->linear_cursor = new_linear;
|
||||
grid->cursor.col = new_col;
|
||||
|
||||
grid->dirty = true;
|
||||
grid->print_needs_wrap = false;
|
||||
grid_cursor_to(grid, grid->cursor.row, grid->cursor.col - move_amount);
|
||||
}
|
||||
|
||||
void
|
||||
grid_cursor_right(struct grid *grid, int count)
|
||||
{
|
||||
int move_amount = min(grid->cols - grid->cursor.col - 1, count);
|
||||
int new_linear = grid->linear_cursor + move_amount;
|
||||
int new_col = grid->cursor.col + move_amount;
|
||||
|
||||
assert(new_linear >= 0);
|
||||
assert(new_linear < grid->rows * grid->cols);
|
||||
assert(new_col >= 0);
|
||||
assert(new_col < grid->cols);
|
||||
|
||||
grid->cells[grid->linear_cursor].dirty = true;
|
||||
grid->cells[new_linear].dirty = true;
|
||||
|
||||
grid->linear_cursor = new_linear;
|
||||
grid->cursor.col = new_col;
|
||||
|
||||
grid->dirty = true;
|
||||
grid->print_needs_wrap = false;
|
||||
grid_cursor_to(grid, grid->cursor.row, grid->cursor.col + move_amount);
|
||||
}
|
||||
|
||||
void
|
||||
grid_cursor_up(struct grid *grid, int count)
|
||||
{
|
||||
int move_amount = min(grid->cursor.row, count);
|
||||
grid_cursor_to(grid, grid->cursor.row - move_amount, grid->cursor.col);
|
||||
}
|
||||
|
||||
void
|
||||
grid_cursor_down(struct grid *grid, int count)
|
||||
{
|
||||
int move_amount = min(grid->rows - grid->cursor.row - 1, count);
|
||||
grid_cursor_to(grid, grid->cursor.row + move_amount, grid->cursor.col);
|
||||
}
|
||||
|
|
|
|||
2
grid.h
2
grid.h
|
|
@ -7,6 +7,8 @@ void grid_erase(struct grid *grid, int start, int end);
|
|||
void grid_cursor_to(struct grid *grid, int row, int col);
|
||||
void grid_cursor_left(struct grid *grid, int count);
|
||||
void grid_cursor_right(struct grid *grid, int count);
|
||||
void grid_cursor_up(struct grid *grid, int count);
|
||||
void grid_cursor_down(struct grid *grid, int count);
|
||||
|
||||
int grid_cursor_linear(const struct grid *grid, int row, int col);
|
||||
|
||||
|
|
|
|||
173
input.c
Normal file
173
input.c
Normal file
|
|
@ -0,0 +1,173 @@
|
|||
#include "input.h"
|
||||
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <signal.h>
|
||||
#include <threads.h>
|
||||
#include <sys/mman.h>
|
||||
|
||||
#include <xkbcommon/xkbcommon.h>
|
||||
#include <xkbcommon/xkbcommon-keysyms.h>
|
||||
|
||||
#define LOG_MODULE "input"
|
||||
#define LOG_ENABLE_DBG 1
|
||||
#include "log.h"
|
||||
#include "terminal.h"
|
||||
|
||||
static void
|
||||
keyboard_keymap(void *data, struct wl_keyboard *wl_keyboard,
|
||||
uint32_t format, int32_t fd, uint32_t size)
|
||||
{
|
||||
struct terminal *term = data;
|
||||
|
||||
char *map_str = mmap(NULL, size, PROT_READ, MAP_PRIVATE, fd, 0);
|
||||
|
||||
/* TODO: free old context + keymap */
|
||||
|
||||
term->kbd.xkb = xkb_context_new(XKB_CONTEXT_NO_FLAGS);
|
||||
term->kbd.xkb_keymap = xkb_keymap_new_from_string(
|
||||
term->kbd.xkb, map_str, XKB_KEYMAP_FORMAT_TEXT_V1,
|
||||
XKB_KEYMAP_COMPILE_NO_FLAGS);
|
||||
|
||||
/* TODO: initialize in enter? */
|
||||
term->kbd.xkb_state = xkb_state_new(term->kbd.xkb_keymap);
|
||||
|
||||
munmap(map_str, size);
|
||||
close(fd);
|
||||
}
|
||||
|
||||
static void
|
||||
keyboard_enter(void *data, struct wl_keyboard *wl_keyboard, uint32_t serial,
|
||||
struct wl_surface *surface, struct wl_array *keys)
|
||||
{
|
||||
LOG_DBG("enter");
|
||||
#if 0
|
||||
uint32_t *key;
|
||||
wl_array_for_each(key, keys)
|
||||
xkb_state_update_key(xkb_state, *key, 1);
|
||||
#endif
|
||||
}
|
||||
|
||||
static void
|
||||
keyboard_leave(void *data, struct wl_keyboard *wl_keyboard, uint32_t serial,
|
||||
struct wl_surface *surface)
|
||||
{
|
||||
#if 0
|
||||
struct terminal *term = data;
|
||||
term->status = EXIT;
|
||||
#endif
|
||||
}
|
||||
|
||||
static void
|
||||
keyboard_key(void *data, struct wl_keyboard *wl_keyboard, uint32_t serial,
|
||||
uint32_t time, uint32_t key, uint32_t state)
|
||||
{
|
||||
static bool mod_masks_initialized = false;
|
||||
static xkb_mod_mask_t ctrl = -1;
|
||||
static xkb_mod_mask_t alt = -1;
|
||||
//static xkb_mod_mask_t shift = -1;
|
||||
|
||||
struct terminal *term = data;
|
||||
|
||||
if (!mod_masks_initialized) {
|
||||
mod_masks_initialized = true;
|
||||
ctrl = 1 << xkb_keymap_mod_get_index(term->kbd.xkb_keymap, "Control");
|
||||
alt = 1 << xkb_keymap_mod_get_index(term->kbd.xkb_keymap, "Mod1");
|
||||
//shift = 1 << xkb_keymap_mod_get_index(term->kbd.xkb_keymap, "Shift");
|
||||
}
|
||||
|
||||
if (state == XKB_KEY_UP) {
|
||||
mtx_lock(&term->kbd.repeat.mutex);
|
||||
if (term->kbd.repeat.key == key) {
|
||||
if (term->kbd.repeat.cmd != REPEAT_EXIT) {
|
||||
term->kbd.repeat.cmd = REPEAT_STOP;
|
||||
cnd_signal(&term->kbd.repeat.cond);
|
||||
}
|
||||
}
|
||||
mtx_unlock(&term->kbd.repeat.mutex);
|
||||
return;
|
||||
}
|
||||
|
||||
key += 8;
|
||||
xkb_keysym_t sym = xkb_state_key_get_one_sym(term->kbd.xkb_state, key);
|
||||
|
||||
xkb_mod_mask_t mods = xkb_state_serialize_mods(
|
||||
term->kbd.xkb_state, XKB_STATE_MODS_EFFECTIVE);
|
||||
xkb_mod_mask_t consumed = xkb_state_key_get_consumed_mods(term->kbd.xkb_state, key);
|
||||
xkb_mod_mask_t significant = ctrl | alt /*| shift*/;
|
||||
xkb_mod_mask_t effective_mods = mods & ~consumed & significant;
|
||||
|
||||
#if 0
|
||||
for (size_t i = 0; i < 32; i++) {
|
||||
if (mods & (1 << i)) {
|
||||
LOG_DBG("%s", xkb_keymap_mod_get_name(term->kbd.xkb_keymap, i));
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
LOG_DBG("sym=%u, mod=0x%08x, consumed=0x%08x, significant=0x%08x, "
|
||||
"effective=0x%08x",
|
||||
sym, mods, consumed, significant, effective_mods);
|
||||
|
||||
if (sym == XKB_KEY_c && effective_mods == ctrl) {
|
||||
kill(term->slave, SIGINT);
|
||||
|
||||
} else if (effective_mods == 0) {
|
||||
char buf[128] = {0};
|
||||
int count = xkb_state_key_get_utf8(term->kbd.xkb_state, key, buf, sizeof(buf));
|
||||
|
||||
if (count == 0)
|
||||
return;
|
||||
|
||||
write(term->ptmx, buf, count);
|
||||
}
|
||||
|
||||
mtx_lock(&term->kbd.repeat.mutex);
|
||||
if (!term->kbd.repeat.dont_re_repeat) {
|
||||
if (term->kbd.repeat.cmd != REPEAT_EXIT) {
|
||||
term->kbd.repeat.cmd = REPEAT_START;
|
||||
term->kbd.repeat.key = key - 8;
|
||||
cnd_signal(&term->kbd.repeat.cond);
|
||||
}
|
||||
}
|
||||
mtx_unlock(&term->kbd.repeat.mutex);
|
||||
}
|
||||
|
||||
static void
|
||||
keyboard_modifiers(void *data, struct wl_keyboard *wl_keyboard, uint32_t serial,
|
||||
uint32_t mods_depressed, uint32_t mods_latched,
|
||||
uint32_t mods_locked, uint32_t group)
|
||||
{
|
||||
struct terminal *term = data;
|
||||
|
||||
LOG_DBG("modifiers: depressed=0x%x, latched=0x%x, locked=0x%x, group=%u",
|
||||
mods_depressed, mods_latched, mods_locked, group);
|
||||
|
||||
xkb_state_update_mask(
|
||||
term->kbd.xkb_state, mods_depressed, mods_latched, mods_locked, 0, 0, group);
|
||||
}
|
||||
|
||||
static void
|
||||
keyboard_repeat_info(void *data, struct wl_keyboard *wl_keyboard,
|
||||
int32_t rate, int32_t delay)
|
||||
{
|
||||
struct terminal *term = data;
|
||||
LOG_DBG("keyboard repeat: rate=%d, delay=%d", rate, delay);
|
||||
term->kbd.repeat.rate = rate;
|
||||
term->kbd.repeat.delay = delay;
|
||||
}
|
||||
|
||||
const struct wl_keyboard_listener keyboard_listener = {
|
||||
.keymap = &keyboard_keymap,
|
||||
.enter = &keyboard_enter,
|
||||
.leave = &keyboard_leave,
|
||||
.key = &keyboard_key,
|
||||
.modifiers = &keyboard_modifiers,
|
||||
.repeat_info = &keyboard_repeat_info,
|
||||
};
|
||||
|
||||
void
|
||||
input_repeat(struct terminal *term, uint32_t key)
|
||||
{
|
||||
keyboard_key(term, NULL, 0, 0, key, XKB_KEY_DOWN);
|
||||
}
|
||||
9
input.h
Normal file
9
input.h
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
#pragma once
|
||||
|
||||
#include <wayland-client.h>
|
||||
|
||||
#include "terminal.h"
|
||||
|
||||
extern const struct wl_keyboard_listener keyboard_listener;
|
||||
|
||||
void input_repeat(struct terminal *term, uint32_t key);
|
||||
158
main.c
158
main.c
|
|
@ -23,6 +23,7 @@
|
|||
#include "slave.h"
|
||||
#include "terminal.h"
|
||||
#include "vt.h"
|
||||
#include "input.h"
|
||||
|
||||
static const uint32_t default_foreground = 0xffffffff;
|
||||
static const uint32_t default_background = 0x000000ff;
|
||||
|
|
@ -33,6 +34,8 @@ struct wayland {
|
|||
struct wl_compositor *compositor;
|
||||
struct wl_surface *surface;
|
||||
struct wl_shm *shm;
|
||||
struct wl_seat *seat;
|
||||
struct wl_keyboard *keyboard;
|
||||
struct xdg_wm_base *shell;
|
||||
struct xdg_surface *xdg_surface;
|
||||
struct xdg_toplevel *xdg_toplevel;
|
||||
|
|
@ -248,6 +251,32 @@ static const struct xdg_wm_base_listener xdg_wm_base_listener = {
|
|||
.ping = &xdg_wm_base_ping,
|
||||
};
|
||||
|
||||
static void
|
||||
seat_handle_capabilities(void *data, struct wl_seat *wl_seat,
|
||||
enum wl_seat_capability caps)
|
||||
{
|
||||
struct context *c = data;
|
||||
|
||||
if (!(caps & WL_SEAT_CAPABILITY_KEYBOARD))
|
||||
return;
|
||||
|
||||
if (c->wl.keyboard != NULL)
|
||||
wl_keyboard_release(c->wl.keyboard);
|
||||
|
||||
c->wl.keyboard = wl_seat_get_keyboard(wl_seat);
|
||||
wl_keyboard_add_listener(c->wl.keyboard, &keyboard_listener, &c->term);
|
||||
}
|
||||
|
||||
static void
|
||||
seat_handle_name(void *data, struct wl_seat *wl_seat, const char *name)
|
||||
{
|
||||
}
|
||||
|
||||
static const struct wl_seat_listener seat_listener = {
|
||||
.capabilities = seat_handle_capabilities,
|
||||
.name = seat_handle_name,
|
||||
};
|
||||
|
||||
static void
|
||||
handle_global(void *data, struct wl_registry *registry,
|
||||
uint32_t name, const char *interface, uint32_t version)
|
||||
|
|
@ -272,6 +301,12 @@ handle_global(void *data, struct wl_registry *registry,
|
|||
xdg_wm_base_add_listener(c->wl.shell, &xdg_wm_base_listener, c);
|
||||
}
|
||||
|
||||
else if (strcmp(interface, wl_seat_interface.name) == 0) {
|
||||
c->wl.seat = wl_registry_bind(c->wl.registry, name, &wl_seat_interface, 4);
|
||||
wl_seat_add_listener(c->wl.seat, &seat_listener, c);
|
||||
wl_display_roundtrip(c->wl.display);
|
||||
}
|
||||
|
||||
#if 0
|
||||
else if (strcmp(interface, wl_output_interface.name) == 0) {
|
||||
struct wl_output *output = wl_registry_bind(
|
||||
|
|
@ -370,6 +405,77 @@ static const struct wl_registry_listener registry_listener = {
|
|||
.global_remove = &handle_global_remove,
|
||||
};
|
||||
|
||||
static int
|
||||
keyboard_repeater(void *arg)
|
||||
{
|
||||
struct terminal *term = arg;
|
||||
|
||||
while (true) {
|
||||
LOG_DBG("repeater: waiting for start");
|
||||
|
||||
mtx_lock(&term->kbd.repeat.mutex);
|
||||
while (term->kbd.repeat.cmd == REPEAT_STOP)
|
||||
cnd_wait(&term->kbd.repeat.cond, &term->kbd.repeat.mutex);
|
||||
|
||||
if (term->kbd.repeat.cmd == REPEAT_EXIT) {
|
||||
mtx_unlock(&term->kbd.repeat.mutex);
|
||||
return 0;
|
||||
}
|
||||
|
||||
restart:
|
||||
|
||||
LOG_DBG("repeater: started");
|
||||
assert(term->kbd.repeat.cmd == REPEAT_START);
|
||||
|
||||
const long rate_delay = 1000000000 / term->kbd.repeat.rate;
|
||||
long delay = term->kbd.repeat.delay * 1000000;
|
||||
|
||||
while (true) {
|
||||
assert(term->kbd.repeat.rate > 0);
|
||||
|
||||
struct timespec timeout;
|
||||
clock_gettime(CLOCK_REALTIME, &timeout);
|
||||
|
||||
timeout.tv_nsec += delay;
|
||||
if (timeout.tv_nsec >= 1000000000) {
|
||||
timeout.tv_sec += timeout.tv_nsec / 1000000000;
|
||||
timeout.tv_nsec %= 1000000000;
|
||||
}
|
||||
|
||||
int ret = cnd_timedwait(&term->kbd.repeat.cond, &term->kbd.repeat.mutex, &timeout);
|
||||
if (ret == thrd_success) {
|
||||
if (term->kbd.repeat.cmd == REPEAT_START)
|
||||
goto restart;
|
||||
else if (term->kbd.repeat.cmd == REPEAT_STOP) {
|
||||
mtx_unlock(&term->kbd.repeat.mutex);
|
||||
break;
|
||||
} else if (term->kbd.repeat.cmd == REPEAT_EXIT) {
|
||||
mtx_unlock(&term->kbd.repeat.mutex);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
assert(ret == thrd_timedout);
|
||||
assert(term->kbd.repeat.cmd == REPEAT_START);
|
||||
LOG_DBG("repeater: repeat: %u", term->kbd.repeat.key);
|
||||
|
||||
if (write(term->kbd.repeat.pipe_write_fd, &term->kbd.repeat.key,
|
||||
sizeof(term->kbd.repeat.key)) != sizeof(term->kbd.repeat.key))
|
||||
{
|
||||
LOG_ERRNO("faile to write repeat key to repeat pipe");
|
||||
mtx_unlock(&term->kbd.repeat.mutex);
|
||||
return 0;
|
||||
}
|
||||
|
||||
delay = rate_delay;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
assert(false);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int
|
||||
main(int argc, const char *const *argv)
|
||||
{
|
||||
|
|
@ -377,6 +483,12 @@ main(int argc, const char *const *argv)
|
|||
|
||||
setlocale(LC_ALL, "");
|
||||
|
||||
int repeat_pipe_fds[2] = {-1, -1};
|
||||
if (pipe2(repeat_pipe_fds, O_CLOEXEC) == -1) {
|
||||
LOG_ERRNO("failed to create pipe for repeater thread");
|
||||
return ret;
|
||||
}
|
||||
|
||||
struct context c = {
|
||||
.quit = false,
|
||||
.term = {
|
||||
|
|
@ -386,9 +498,22 @@ main(int argc, const char *const *argv)
|
|||
},
|
||||
.grid = {.foreground = default_foreground,
|
||||
.background = default_background},
|
||||
.kbd = {
|
||||
.repeat = {
|
||||
.pipe_read_fd = repeat_pipe_fds[0],
|
||||
.pipe_write_fd = repeat_pipe_fds[1],
|
||||
.cmd = REPEAT_STOP,
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
mtx_init(&c.term.kbd.repeat.mutex, mtx_plain);
|
||||
cnd_init(&c.term.kbd.repeat.cond);
|
||||
|
||||
thrd_t keyboard_repeater_id;
|
||||
thrd_create(&keyboard_repeater_id, &keyboard_repeater, &c.term);
|
||||
|
||||
const char *font_name = "Dina:pixelsize=12";
|
||||
c.font = font_from_name(font_name);
|
||||
if (c.font == NULL)
|
||||
|
|
@ -459,8 +584,8 @@ main(int argc, const char *const *argv)
|
|||
|
||||
wl_display_dispatch_pending(c.wl.display);
|
||||
|
||||
pid_t pid = fork();
|
||||
switch (pid) {
|
||||
c.term.slave = fork();
|
||||
switch (c.term.slave) {
|
||||
case -1:
|
||||
LOG_ERRNO("failed to fork");
|
||||
goto out;
|
||||
|
|
@ -472,7 +597,7 @@ main(int argc, const char *const *argv)
|
|||
break;
|
||||
|
||||
default:
|
||||
LOG_DBG("slave has PID %d", pid);
|
||||
LOG_DBG("slave has PID %d", c.term.slave);
|
||||
break;
|
||||
}
|
||||
|
||||
|
|
@ -480,6 +605,7 @@ main(int argc, const char *const *argv)
|
|||
struct pollfd fds[] = {
|
||||
{.fd = wl_display_get_fd(c.wl.display), .events = POLLIN},
|
||||
{.fd = c.term.ptmx, .events = POLLIN},
|
||||
{.fd = c.term.kbd.repeat.pipe_read_fd, .events = POLLIN},
|
||||
};
|
||||
|
||||
wl_display_flush(c.wl.display);
|
||||
|
|
@ -517,9 +643,29 @@ main(int argc, const char *const *argv)
|
|||
ret = EXIT_SUCCESS;
|
||||
break;
|
||||
}
|
||||
|
||||
if (fds[2].revents & POLLIN) {
|
||||
uint32_t key;
|
||||
if (read(c.term.kbd.repeat.pipe_read_fd, &key, sizeof(key)) != sizeof(key)) {
|
||||
LOG_ERRNO("failed to read repeat key from repeat pipe");
|
||||
break;
|
||||
}
|
||||
|
||||
c.term.kbd.repeat.dont_re_repeat = true;
|
||||
input_repeat(&c.term, key);
|
||||
c.term.kbd.repeat.dont_re_repeat = false;
|
||||
}
|
||||
|
||||
if (fds[2].revents & POLLHUP)
|
||||
LOG_ERR("keyboard repeat handling thread died");
|
||||
}
|
||||
|
||||
out:
|
||||
mtx_lock(&c.term.kbd.repeat.mutex);
|
||||
c.term.kbd.repeat.cmd = REPEAT_EXIT;
|
||||
cnd_signal(&c.term.kbd.repeat.cond);
|
||||
mtx_unlock(&c.term.kbd.repeat.mutex);
|
||||
|
||||
shm_fini();
|
||||
if (c.wl.xdg_toplevel != NULL)
|
||||
xdg_toplevel_destroy(c.wl.xdg_toplevel);
|
||||
|
|
@ -546,6 +692,12 @@ out:
|
|||
if (c.term.ptmx != -1)
|
||||
close(c.term.ptmx);
|
||||
|
||||
thrd_join(keyboard_repeater_id, NULL);
|
||||
cnd_destroy(&c.term.kbd.repeat.cond);
|
||||
mtx_destroy(&c.term.kbd.repeat.mutex);
|
||||
close(c.term.kbd.repeat.pipe_read_fd);
|
||||
close(c.term.kbd.repeat.pipe_write_fd);
|
||||
|
||||
cairo_debug_reset_static_data();
|
||||
return ret;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -20,6 +20,7 @@ add_project_arguments(
|
|||
cc = meson.get_compiler('c')
|
||||
math = cc.find_library('m')
|
||||
|
||||
threads = dependency('threads')
|
||||
fontconfig = dependency('fontconfig')
|
||||
cairo = dependency('cairo')
|
||||
cairo_ft = dependency('cairo-ft')
|
||||
|
|
@ -60,6 +61,7 @@ executable(
|
|||
'csi.c', 'csi.h',
|
||||
'font.c', 'font.h',
|
||||
'grid.c', 'grid.h',
|
||||
'input.c', 'input.h',
|
||||
'log.c', 'log.h',
|
||||
'main.c',
|
||||
'osc.c', 'osc.h',
|
||||
|
|
@ -69,5 +71,5 @@ executable(
|
|||
'tllist.h',
|
||||
'vt.c', 'vt.h',
|
||||
wl_proto_src + wl_proto_headers,
|
||||
dependencies: [math, cairo, cairo_ft, fontconfig, wayland_client, wayland_cursor, xkb],
|
||||
dependencies: [threads, math, cairo, cairo_ft, fontconfig, wayland_client, wayland_cursor, xkb],
|
||||
install: true)
|
||||
|
|
|
|||
26
terminal.h
26
terminal.h
|
|
@ -4,6 +4,11 @@
|
|||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
|
||||
#include <threads.h>
|
||||
|
||||
#include <xkbcommon/xkbcommon.h>
|
||||
#include <xkbcommon/xkbcommon-keysyms.h>
|
||||
|
||||
struct attributes {
|
||||
bool bold;
|
||||
bool italic;
|
||||
|
|
@ -73,8 +78,29 @@ struct vt {
|
|||
bool dim;
|
||||
};
|
||||
|
||||
struct kbd {
|
||||
struct xkb_context *xkb;
|
||||
struct xkb_keymap *xkb_keymap;
|
||||
struct xkb_state *xkb_state;
|
||||
struct {
|
||||
mtx_t mutex;
|
||||
cnd_t cond;
|
||||
int trigger;
|
||||
int pipe_read_fd;
|
||||
int pipe_write_fd;
|
||||
enum {REPEAT_STOP, REPEAT_START, REPEAT_EXIT} cmd;
|
||||
|
||||
bool dont_re_repeat;
|
||||
int32_t delay;
|
||||
int32_t rate;
|
||||
uint32_t key;
|
||||
} repeat;
|
||||
};
|
||||
|
||||
struct terminal {
|
||||
pid_t slave;
|
||||
int ptmx;
|
||||
struct vt vt;
|
||||
struct grid grid;
|
||||
struct kbd kbd;
|
||||
};
|
||||
|
|
|
|||
14
vt.c
14
vt.c
|
|
@ -157,6 +157,10 @@ action(struct terminal *term, enum action action, uint8_t c)
|
|||
case ACTION_EXECUTE:
|
||||
LOG_DBG("execute: 0x%02x", c);
|
||||
switch (c) {
|
||||
case '\n':
|
||||
grid_cursor_down(&term->grid, 1);
|
||||
break;
|
||||
|
||||
case '\r':
|
||||
grid_cursor_left(&term->grid, term->grid.cursor.col);
|
||||
break;
|
||||
|
|
@ -164,6 +168,14 @@ action(struct terminal *term, enum action action, uint8_t c)
|
|||
case '\b':
|
||||
grid_cursor_left(&term->grid, 1);
|
||||
break;
|
||||
|
||||
case '\x07':
|
||||
LOG_WARN("BELL");
|
||||
break;
|
||||
|
||||
default:
|
||||
LOG_ERR("execute: unimplemented: %c", c);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
|
|
@ -189,7 +201,7 @@ action(struct terminal *term, enum action action, uint8_t c)
|
|||
cell->c[term->vt.utf8.idx] = '\0';
|
||||
memset(&term->vt.utf8, 0, sizeof(term->vt.utf8));
|
||||
} else {
|
||||
//LOG_DBG("print: ASCII: %c", c);
|
||||
LOG_DBG("print: ASCII: %c", c);
|
||||
cell->c[0] = c;
|
||||
cell->c[1] = '\0';
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue