aboutsummaryrefslogtreecommitdiffstats
path: root/include/input.h
blob: adda27a8934f215c1b94c11f2b3d925e2e427b37 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
/* Input decoding: the bytes the *outer* terminal sends us -> semantic events.
 *
 * libghostty-vt encodes events outward to a pane, but nothing decodes inward,
 * so this half is ours (DESIGN.md). Decoding to a semantic event and
 * re-encoding per pane against that pane's own modes is what makes kitty
 * keyboard passthrough correct instead of approximate.
 *
 * The event carries GhosttyKey / GHOSTTY_MODS_* values as plain integers so
 * this header stays free of libghostty-vt.
 */
#ifndef SLOSH_INPUT_H
#define SLOSH_INPUT_H

#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>

typedef enum {
  EV_NONE = 0,
  EV_KEY,
  EV_MOUSE,
  EV_PASTE,
  EV_FOCUS,
} ev_kind_t;

/* mirrors GhosttyKeyAction */
enum { KEY_RELEASE = 0, KEY_PRESS = 1, KEY_REPEAT = 2 };
/* mirrors GhosttyMouseAction */
enum { MOUSE_PRESS = 0, MOUSE_RELEASE = 1, MOUSE_MOTION = 2 };
/* mirrors GhosttyMouseButton */
enum {
  MBTN_UNKNOWN = 0,
  MBTN_LEFT = 1,
  MBTN_RIGHT = 2,
  MBTN_MIDDLE = 3,
  MBTN_FOUR = 4,
  MBTN_FIVE = 5,
  MBTN_SIX = 6,
  MBTN_SEVEN = 7,
};
/* mirrors GHOSTTY_MODS_* */
enum {
  MOD_SHIFT = 1 << 0,
  MOD_CTRL = 1 << 1,
  MOD_ALT = 1 << 2,
  MOD_SUPER = 1 << 3,
  MOD_CAPS = 1 << 4,
  MOD_NUM = 1 << 5,
};

typedef struct {
  ev_kind_t kind;

  /* EV_KEY */
  int key;        /* GhosttyKey */
  uint16_t mods;  /* MOD_* */
  uint8_t action; /* KEY_* */
  char text[16];  /* UTF-8 the key produced, if any */
  uint8_t text_len;
  uint32_t unshifted; /* unshifted codepoint, 0 if unknown */

  /* EV_MOUSE */
  uint8_t button;  /* MBTN_* */
  uint8_t maction; /* MOUSE_* */
  uint16_t mx, my; /* 0-indexed cell coordinates */

  /* EV_PASTE */
  const char *paste;
  size_t paste_len;

  /* EV_FOCUS */
  bool focused;
} input_event_t;

typedef struct input_parser input_parser_t;
typedef void (*input_cb_t)(const input_event_t *ev, void *ud);

input_parser_t *input_new(void);
void input_free(input_parser_t *p);

/* Feed bytes; complete events are dispatched to cb. Partial sequences are
 * retained for the next call, so split reads are safe. */
void input_feed(input_parser_t *p, const uint8_t *data, size_t len,
                input_cb_t cb, void *ud);

/* True when a bare ESC (or an unterminated sequence) is buffered. Call
 * input_timeout() after ~50ms of quiet to resolve it as the Escape key. */
bool input_pending(const input_parser_t *p);
void input_timeout(input_parser_t *p, input_cb_t cb, void *ud);

/* Debug/test rendering of an event, e.g. "key ARROW_UP mods=CTRL press". */
void input_event_describe(const input_event_t *ev, char *buf, size_t cap);

#endif /* SLOSH_INPUT_H */