commit c523129
uint
·
2026-05-13 19:39:28 +0000 UTC
parent b2be907
create pty, read/write pty, handle rgfw keys
2 files changed,
+139,
-24
+136,
-23
1@@ -1,6 +1,15 @@
2 #define RGFW_IMPLEMENTATION
3+#include <errno.h>
4+#include <fcntl.h>
5 #include <stdint.h>
6 #include <stdlib.h>
7+#include <sys/ioctl.h>
8+#ifdef __linux__
9+#include <pty.h>
10+#else
11+#include <util.h>
12+#endif
13+#include <unistd.h>
14
15 #include <RGFW.h>
16 #include <grapheme.h>
17@@ -28,13 +37,17 @@ static Term term = {
18 .runes = runes,
19 .cols = COLS,
20 .rows = ROWS,
21- .ptyfd = -1, /* TODO: pty */
22+ .ptyfd = -1,
23+ .ptypid = -1,
24 .fg = 0xffffffff,
25 .bg = 0xff222222,
26 };
27
28 static void cleanup(void);
29+static void handle_key(RGFW_event ev);
30 static void init(void);
31+static void ptyread(void);
32+static void ptywrite(const char* s, size_t n);
33 static void run(void);
34
35 /**
36@@ -52,11 +65,67 @@ static void cleanup(void)
37 RGFW_window_close(win);
38 }
39
40+/**
41+ * @brief dispatch correct key to pty
42+ *
43+ * @param c character check dispatch
44+ */
45+static void handle_key(RGFW_event ev)
46+{
47+ /* regular character-
48+ * dont have to handle e.g. shift cases:
49+ * SHIFT+1 or `!`
50+ */
51+ if (ev.type == RGFW_keyChar) {
52+ uint32_t cp = ev.keyChar.value;
53+ if (cp >= ' ' && cp <= '~') {
54+ char cpch = (char)cp;
55+ ptywrite(&cpch, 1);
56+ }
57+ }
58+
59+ /* special character */
60+ if (ev.type == RGFW_keyPressed) {
61+ char c = ev.key.value;
62+ switch(c) {
63+ case RGFW_keyReturn: ptywrite("\r", 1); break;
64+
65+ case RGFW_keyDelete:
66+ case RGFW_keyBackSpace: ptywrite("\x7F", 1); break;
67+
68+ case RGFW_keyTab: ptywrite("\t", 1); break;
69+ case RGFW_keyEscape: ptywrite("\x1B", 1); break;
70+ default: break;
71+ }
72+ }
73+}
74+
75 /**
76 * @brief initialise: window (TODO)
77 */
78 static void init(void)
79 {
80+ /* pty */
81+ struct winsize ws = {
82+ .ws_col = COLS,
83+ .ws_row = ROWS,
84+ .ws_xpixel = WIDTH,
85+ .ws_ypixel = HEIGHT
86+ };
87+ term.ptypid = forkpty(&term.ptyfd, NULL, NULL, &ws);
88+ if (term.ptypid < 0)
89+ die(EXIT_FAILURE, "failed to fork pty");
90+ if (term.ptypid == 0) {
91+ /* TODO: change later */
92+ setenv("TERM", "dumb", 1);
93+ execlp("/bin/sh", "sh", "-i", NULL);
94+ _exit(127);
95+ }
96+
97+ int flags = fcntl(term.ptyfd, F_GETFL, 0);
98+ if (flags >= 0) /* append to existing flags */
99+ fcntl(term.ptyfd, F_SETFL, flags|O_NONBLOCK);
100+
101 /* window */
102 if (!(win = RGFW_createWindow("cterm", 0, 0, 800, 600, 0)))
103 die(1, "failed to create window");
104@@ -76,14 +145,53 @@ static void init(void)
105 if (font_load(&font, "./Xanh.ttf", 24.0) < 0)
106 die(1, "failed to load font");
107 font.aa = false;
108-
109- /* tmp */
110 term_clear(&term, &car);
111- const char* s =
112- "cterm test\n"
113- "terminal buffer!";
114- for (const char* p = s; *p; p++)
115- term_putc(&term, &car, (unsigned char)*p);
116+}
117+
118+/**
119+ * @brief read data from master pty
120+ */
121+static void ptyread(void)
122+{
123+ char buf[4096];
124+
125+ for (;;) {
126+ ssize_t n = read(term.ptyfd, buf, sizeof(buf));
127+ if (n < 0 && errno == EINTR)
128+ continue;
129+ if (n < 0 && (errno == EAGAIN || errno == EWOULDBLOCK))
130+ break;
131+ if (n > 0) {
132+ for (ssize_t i = 0; i < n; i++)
133+ term_putc(&term, &car, (unsigned char)buf[i]);
134+ continue;
135+ }
136+
137+ /* EOF or other error */
138+ break;
139+ }
140+}
141+
142+/**
143+ * @brief read data to master pty
144+ *
145+ * @param s string buffer to write to pty
146+ * @param n number of characters in buffer
147+ */
148+static void ptywrite(const char* s, size_t n)
149+{
150+ while (n > 0) {
151+ ssize_t ret = write(term.ptyfd, s, n);
152+ if (ret < 0 && (errno == EINTR))
153+ continue;
154+ if (ret > 0) {
155+ s+= ret;
156+ n -= ret;
157+ continue;
158+ }
159+
160+ break;
161+ }
162 }
163
164 /**
165@@ -95,33 +203,38 @@ static void run(void)
166
167 while (!RGFW_window_shouldClose(win)) {
168 while (RGFW_window_checkEvent(win, &ev))
169- ;
170+ handle_key(ev);
171
172- draw_clear(pixels, WIDTH, HEIGHT, rgba(0, 0, 0, 255));
173+ ptyread();
174
175+ /* drawing */
176+ draw_clear(pixels, WIDTH, HEIGHT, rgba(0, 0, 0, 255));
177 for (int y = 0; y < term.rows; y++) {
178 for (int x = 0; x < term.cols; x++) {
179 Rune* rune = &RUNE(&term, x, y);
180
181- draw_rune(pixels, WIDTH, HEIGHT,
182- x, y,
183- font.cellw, font.cellh,
184- rune->bg);
185+ draw_rune(
186+ pixels, WIDTH, HEIGHT, x, y,
187+ font.cellw, font.cellh, rune->bg
188+ );
189
190 if (rune->cp != ' ') {
191- draw_codepoint(&font, pixels, WIDTH, HEIGHT,
192- x * font.cellw,
193- y * font.cellh + (int)font.asc,
194- rune->cp,
195- rune->fg);
196+ draw_codepoint(
197+ &font, pixels, WIDTH, HEIGHT,
198+ x * font.cellw,
199+ y * font.cellh + (int)font.asc,
200+ rune->cp, rune->fg
201+ );
202 }
203 }
204 }
205
206- draw_caret(pixels, WIDTH, HEIGHT,
207- car.x, car.y,
208- font.cellw, font.cellh,
209- rgba(255, 255, 255, 255));
210+ draw_caret(
211+ pixels, WIDTH, HEIGHT,
212+ car.x, car.y,
213+ font.cellw, font.cellh,
214+ rgba(255, 255, 255, 255)
215+ );
216
217 RGFW_window_blitSurface(win, surf);
218 }
+3,
-1
1@@ -3,6 +3,7 @@
2
3 #include <stdbool.h>
4 #include <stdint.h>
5+#include <sys/types.h>
6
7 /* resolve 1D rune from 2D input */
8 #define RUNE(t, x, y) ((t)->runes[(y) * (t)->cols + (x)])
9@@ -26,6 +27,7 @@ typedef struct {
10 int cols;
11 int rows;
12 int ptyfd;
13+ pid_t ptypid;
14 } Term;
15
16 /**
17@@ -47,7 +49,7 @@ void term_clear(Term* t, Caret* c);
18 void term_putc(Term* t, Caret* c, uint32_t cp);
19
20 /**
21- * @brief scroll viewport down by one
22+ * @brief scroll viewport up by one
23 *
24 * @param t terminal instance to scroll
25 */