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  */