C-Menu 0.2.9
A User Interface Toolkit
Loading...
Searching...
No Matches
ui_notcurses_input.c
Go to the documentation of this file.
1/** @file ui_notcurses_input.c
2 @ingroup ui_notcurses
3 @brief NotCurses UI backend — input handling.
4
5 Translates NotCurses @c ncinput events into the portable UiEvent
6 representation defined in ui_backend.h.
7*/
8
9#include "ui_backend.h"
11#include <notcurses/notcurses.h>
12#include <string.h>
13#include <termios.h>
14
15int ui_get_event_multix(UiSurface *s, uint w, UiEvent *ev, int timeout_ms);
16/* -------------------------------------------------------------------------
17 Key translation
18 ------------------------------------------------------------------------- */
19
20static UiKey translate_nckey(uint32_t id, const ncinput *ni) {
21 if (id == NCKEY_INVALID || id == (uint32_t)NCKEY_EOF)
22 return UI_KEY_NONE;
23
24 /* Mouse buttons — handled separately in ui_get_event(). */
25 if (nckey_mouse_p(id))
26 return UI_KEY_MOUSE;
27
28 switch (id) {
29 case NCKEY_RESIZE:
30 return UI_KEY_RESIZE;
31 case NCKEY_ENTER:
32 return UI_KEY_ENTER;
33 case NCKEY_ESC:
34 return UI_KEY_ESCAPE;
35 case NCKEY_BACKSPACE:
36 return UI_KEY_BACKSPACE;
37 case NCKEY_TAB:
38 return UI_KEY_TAB;
39 case NCKEY_UP:
40 return UI_KEY_UP;
41 case NCKEY_DOWN:
42 return UI_KEY_DOWN;
43 case NCKEY_LEFT:
44 return UI_KEY_LEFT;
45 case NCKEY_RIGHT:
46 return UI_KEY_RIGHT;
47 case NCKEY_HOME:
48 return UI_KEY_HOME;
49 case NCKEY_END:
50 return UI_KEY_END;
51 case NCKEY_PGUP:
52 return UI_KEY_PGUP;
53 case NCKEY_PGDOWN:
54 return UI_KEY_PGDN;
55 case NCKEY_INS:
56 return UI_KEY_INSERT;
57 case NCKEY_DEL:
58 return UI_KEY_DELETE;
59 case NCKEY_F01:
60 return UI_KEY_F1;
61 case NCKEY_F02:
62 return UI_KEY_F2;
63 case NCKEY_F03:
64 return UI_KEY_F3;
65 case NCKEY_F04:
66 return UI_KEY_F4;
67 case NCKEY_F05:
68 return UI_KEY_F5;
69 case NCKEY_F06:
70 return UI_KEY_F6;
71 case NCKEY_F07:
72 return UI_KEY_F7;
73 case NCKEY_F08:
74 return UI_KEY_F8;
75 case NCKEY_F09:
76 return UI_KEY_F9;
77 case NCKEY_F10:
78 return UI_KEY_F10;
79 case NCKEY_F11:
80 return UI_KEY_F11;
81 case NCKEY_F12:
82 return UI_KEY_F12;
83 default:
84 if (ni && ni->evtype == NCTYPE_UNKNOWN)
85 return UI_KEY_NONE;
86 /* Printable Unicode codepoint. */
87 if (id >= 0x20 && id < NCKEY_INVALID)
88 return UI_KEY_CHAR;
89 return UI_KEY_NONE;
90 }
91}
92
93/* -------------------------------------------------------------------------
94 Event retrieval
95 ------------------------------------------------------------------------- */
96
97/** @brief Wait for an input event from the NotCurses context.
98 @param ui UI runtime context.
99 @param target Unused for NotCurses (events are global to the context).
100 @param ev Output UiEvent structure.
101 @param timeout_ms Milliseconds to wait; -1 = block indefinitely.
102 @return 0 on success, -1 if @p ui or @p ev is NULL.
103*/
104int ui_get_event(UiSurface *s, uint w, UiEvent *ev, int timeout_ms) {
105 if (!ui || !ev)
106 return -1;
107 memset(ev, 0, sizeof(*ev));
108
109 ncinput ni;
110 // ui_cursor_enable(s, w, true);
111 // tcflush(0, TCIFLUSH);
112 if (timeout_ms < 0) {
113 do {
114 // notcurses_get(ui->nc, NULL, &ni);
115 notcurses_get_blocking(ui->nc, &ni);
116 } while (ni.evtype == NCTYPE_RELEASE ||
117 ni.id == NCKEY_INVALID ||
118 ni.id == NCKEY_MOTION ||
119 ni.id == NCKEY_SIGNAL);
120 } else {
121 struct timespec ts = {
122 .tv_sec = timeout_ms / 1000,
123 .tv_nsec = (long)(timeout_ms % 1000) * 1000000L,
124 };
125 do {
126 notcurses_get(ui->nc, &ts, &ni);
127 } while (ni.evtype == NCTYPE_RELEASE || ni.id == NCKEY_INVALID);
128 }
129 // notcurses_cursor_disable(ui->nc);
130 ev->key = translate_nckey(ni.id, &ni);
131 ev->alt = ncinput_alt_p(&ni);
132 ev->ctrl = ncinput_ctrl_p(&ni);
133 ev->shift = ncinput_shift_p(&ni);
134 if (ev->key == UI_KEY_CHAR) {
135 ev->ch = ni.id; /* Unicode codepoint */
136 } else if (ev->key == UI_KEY_MOUSE) {
137 ev->y = ni.y;
138 ev->x = ni.x;
139 if (ni.id == NCKEY_BUTTON4)
141 else if (ni.id == NCKEY_BUTTON5)
143 else if (ni.evtype == NCTYPE_PRESS)
145 else if (ni.evtype == NCTYPE_RELEASE)
147 }
148 return ni.id;
149}
150
151int ui_getch() {
152 if (!ui)
153 return -1;
154 ncinput ni;
155 do {
156 notcurses_get(ui->nc, NULL, &ni);
157 } while (ni.evtype == NCTYPE_RELEASE ||
158 ni.id == NCKEY_INVALID ||
159 ni.id == NCKEY_MOTION ||
160 ni.id == NCKEY_SIGNAL);
161 return ni.id;
162}
163
164int ui_get_event_multix(UiSurface *s, uint w, UiEvent *ev, int timeout_ms) {
165 (void)timeout_ms;
166 (void)ev;
167 (void)w;
168 (void)s;
169 if (!ui)
170 return -1;
171 ncinput ni;
172 do {
173 // notcurses_get_blocking(ui->nc, &ni);
174 notcurses_get(ui->nc, NULL, &ni);
175 } while (ni.evtype == NCTYPE_RELEASE ||
176 ni.id == NCKEY_INVALID ||
177 ni.id == NCKEY_MOTION ||
178 ni.id == NCKEY_SIGNAL);
179 return ni.id;
180}
181int ui_get_event_multi(UiSurface *s, uint w, UiEvent *ev, int timeout_ms) {
182 if (!ui || !ev)
183 return -1;
184 memset(ev, 0, sizeof(*ev));
185 ncinput ni;
186 if (timeout_ms < 0)
187 do {
188 notcurses_get(ui->nc, NULL, &ni);
189 } while (ni.evtype == NCTYPE_RELEASE ||
190 ni.id == NCKEY_INVALID ||
191 ni.id == NCKEY_MOTION ||
192 ni.id == NCKEY_SIGNAL);
193 else {
194 struct timespec ts = {
195 .tv_sec = timeout_ms / 1000,
196 .tv_nsec = (long)(timeout_ms % 1000) * 1000000L,
197 };
198 do {
199 notcurses_get(ui->nc, &ts, &ni);
200 } while (ni.evtype == NCTYPE_RELEASE || ni.id == NCKEY_INVALID);
201 }
202 // notcurses_cursor_disable(ui->nc);
203 ev->key = translate_nckey(ni.id, &ni);
204 ev->alt = ncinput_alt_p(&ni);
205 ev->ctrl = ncinput_ctrl_p(&ni);
206 ev->shift = ncinput_shift_p(&ni);
207 if (ev->key == UI_KEY_CHAR) {
208 ev->ch = ni.id; /* Unicode codepoint */
209 } else if (ev->key == UI_KEY_MOUSE) {
210 if (ni.id == NCKEY_BUTTON1) {
211 struct ncplane *nn = ncplane_clicked(s, w, &ni);
213 ev->key = 0;
214 }
215 }
216 ev->y = ni.y;
217 ev->x = ni.x;
218 if (ni.id == NCKEY_BUTTON4)
220 else if (ni.id == NCKEY_BUTTON5)
222 else if (ni.evtype == NCTYPE_PRESS)
224 else if (ni.evtype == NCTYPE_RELEASE)
226 return ni.id;
227}
228
229int ui_get_event_no_mouse(UiSurface *target, uint w, UiEvent *ev) {
230 (void)target;
231 (void)w;
232 if (!ui || !ev)
233 return -1;
234 memset(ev, 0, sizeof(*ev));
235 ncinput ni;
236 // notcurses_mice_disable(ui->nc);
237 do {
238 notcurses_get(ui->nc, NULL, &ni);
239 } while (ni.id == NCKEY_INVALID);
240 ev->key = translate_nckey(ni.id, &ni);
241 ev->alt = ncinput_alt_p(&ni);
242 ev->ctrl = ncinput_ctrl_p(&ni);
243 ev->shift = ncinput_shift_p(&ni);
244 if (ev->key == UI_KEY_CHAR)
245 ev->ch = ni.id;
246 return ni.id;
247}
248
249uint get_plane_idx(UiSurface *s, struct ncplane *plane) {
250 if (!s)
251 return -1;
252 for (uint w = 0; w < SUB_SFC_MAX; ++w) {
253 if (s->mplane[w] == plane)
254 return w;
255 }
256 return -1;
257}
258
259NcPlane *ncplane_clicked(UiSurface *s, uint w, ncinput *ni) {
260 NcPlane *pile_member = s->mplane[w];
261 struct ncplane *cur = ncpile_top(pile_member);
262 while (cur != NULL) {
263 int y = ni->y, x = ni->x;
264 if (ncplane_translate_abs(cur, &y, &x)) {
265 ni->y = y;
266 ni->x = x;
267 return cur;
268 }
269 cur = ncplane_below(cur);
270 }
271 return NULL;
272}
int ui_get_event_no_mouse(UiSurface *surface, uint w, UiEvent *ev)
@ UI_KEY_F8
Definition ui_backend.h:69
@ UI_KEY_BACKSPACE
Definition ui_backend.h:47
@ UI_KEY_F9
Definition ui_backend.h:70
@ UI_KEY_TAB
Definition ui_backend.h:48
@ UI_KEY_F2
Definition ui_backend.h:63
@ UI_KEY_F7
Definition ui_backend.h:68
@ UI_KEY_DELETE
Definition ui_backend.h:59
@ UI_KEY_CHAR
Definition ui_backend.h:44
@ UI_KEY_MOUSE
Definition ui_backend.h:61
@ UI_KEY_F11
Definition ui_backend.h:72
@ UI_KEY_DOWN
Definition ui_backend.h:51
@ UI_KEY_F4
Definition ui_backend.h:65
@ UI_KEY_F3
Definition ui_backend.h:64
@ UI_KEY_HOME
Definition ui_backend.h:54
@ UI_KEY_F6
Definition ui_backend.h:67
@ UI_KEY_PGDN
Definition ui_backend.h:57
@ UI_KEY_PGUP
Definition ui_backend.h:56
@ UI_KEY_NONE
Definition ui_backend.h:43
@ UI_KEY_END
Definition ui_backend.h:55
@ UI_KEY_F5
Definition ui_backend.h:66
@ UI_KEY_ESCAPE
Definition ui_backend.h:46
@ UI_KEY_LEFT
Definition ui_backend.h:52
@ UI_KEY_F1
Definition ui_backend.h:62
@ UI_KEY_ENTER
Definition ui_backend.h:45
@ UI_KEY_UP
Definition ui_backend.h:50
@ UI_KEY_F12
Definition ui_backend.h:73
@ UI_KEY_RESIZE
Definition ui_backend.h:60
@ UI_KEY_INSERT
Definition ui_backend.h:58
@ UI_KEY_RIGHT
Definition ui_backend.h:53
@ UI_KEY_F10
Definition ui_backend.h:71
int ui_get_event(UiSurface *s, uint w, UiEvent *ev, int timeout_ms)
Wait for an input event on target (or stdscr if NULL).
int ui_getch()
Definition nckeys.c:255
UiRuntime * ui
int ui_get_event_multi(UiSurface *s, uint w, UiEvent *ev, int timeout_ms)
struct ncplane NcPlane
Definition ui_backend.h:251
@ UI_MOUSE_SCROLL_DOWN
Definition ui_backend.h:82
@ UI_MOUSE_PRESS
Definition ui_backend.h:78
@ UI_MOUSE_SCROLL_UP
Definition ui_backend.h:81
@ UI_MOUSE_RELEASE
Definition ui_backend.h:79
NcPlane * ncplane_clicked(NcPlane *pile_member, ncinput *ni)
Definition nckeys.c:295
uint get_plane_idx(UiSurface *s, struct ncplane *plane)
int ui_get_event_multix(UiSurface *s, uint w, UiEvent *ev, int timeout_ms)
uint32_t ch
Definition ui_backend.h:102
UiMouseAction mouse_action
Definition ui_backend.h:112
bool shift
Definition ui_backend.h:105
uint in_win
Definition ui_backend.h:110
bool ctrl
Definition ui_backend.h:104
UiKey key
Definition ui_backend.h:101
bool alt
Definition ui_backend.h:103
struct notcurses * nc