1717
1818struct PtywrightGhosttyTerminal {
1919 GhosttyTerminal handle ;
20+ GhosttyKeyEncoder encoder ;
2021 uint8_t * reply_buf ;
2122 size_t reply_len ;
2223 size_t reply_cap ;
@@ -27,6 +28,44 @@ struct PtywrightGhosttyTerminal {
2728 int reply_error ;
2829};
2930
31+ static int ptywright_ghostty_special_key (const char * name , GhosttyKey * out_key ,
32+ GhosttyMods * out_mods ) {
33+ if (name == NULL || out_key == NULL || out_mods == NULL ) {
34+ return GHOSTTY_INVALID_VALUE ;
35+ }
36+
37+ * out_mods = 0 ;
38+ if (strcmp (name , "arrow_up" ) == 0 ) {
39+ * out_key = GHOSTTY_KEY_ARROW_UP ;
40+ } else if (strcmp (name , "arrow_down" ) == 0 ) {
41+ * out_key = GHOSTTY_KEY_ARROW_DOWN ;
42+ } else if (strcmp (name , "arrow_left" ) == 0 ) {
43+ * out_key = GHOSTTY_KEY_ARROW_LEFT ;
44+ } else if (strcmp (name , "arrow_right" ) == 0 ) {
45+ * out_key = GHOSTTY_KEY_ARROW_RIGHT ;
46+ } else if (strcmp (name , "home" ) == 0 ) {
47+ * out_key = GHOSTTY_KEY_HOME ;
48+ } else if (strcmp (name , "end" ) == 0 ) {
49+ * out_key = GHOSTTY_KEY_END ;
50+ } else if (strcmp (name , "page_up" ) == 0 ) {
51+ * out_key = GHOSTTY_KEY_PAGE_UP ;
52+ } else if (strcmp (name , "page_down" ) == 0 ) {
53+ * out_key = GHOSTTY_KEY_PAGE_DOWN ;
54+ } else if (strcmp (name , "insert" ) == 0 ) {
55+ * out_key = GHOSTTY_KEY_INSERT ;
56+ } else if (strcmp (name , "delete" ) == 0 ) {
57+ * out_key = GHOSTTY_KEY_DELETE ;
58+ } else if (strcmp (name , "escape" ) == 0 ) {
59+ * out_key = GHOSTTY_KEY_ESCAPE ;
60+ } else if (strcmp (name , "backtab" ) == 0 ) {
61+ * out_key = GHOSTTY_KEY_TAB ;
62+ * out_mods = GHOSTTY_MODS_SHIFT ;
63+ } else {
64+ return GHOSTTY_INVALID_VALUE ;
65+ }
66+ return GHOSTTY_SUCCESS ;
67+ }
68+
3069static int ptywright_ghostty_reserve_buffer (uint8_t * * buf ,
3170 size_t * cap ,
3271 size_t needed ) {
@@ -218,6 +257,13 @@ int ptywright_ghostty_terminal_create(uint16_t cols, uint16_t rows, size_t scrol
218257 return result ;
219258 }
220259
260+ result = ghostty_key_encoder_new (NULL , & terminal -> encoder );
261+ if (result != GHOSTTY_SUCCESS ) {
262+ ghostty_terminal_free (terminal -> handle );
263+ free (terminal );
264+ return result ;
265+ }
266+
221267 * out_terminal = terminal ;
222268 return GHOSTTY_SUCCESS ;
223269}
@@ -263,6 +309,78 @@ int ptywright_ghostty_terminal_resize(PtywrightGhosttyTerminal *terminal,
263309 return ghostty_terminal_resize (terminal -> handle , cols , rows , kCellWidthPx , kCellHeightPx );
264310}
265311
312+ int ptywright_ghostty_terminal_encode_special_key (PtywrightGhosttyTerminal * terminal ,
313+ const char * name ,
314+ uint8_t * * out_bytes ,
315+ size_t * out_len ) {
316+ if (terminal == NULL || terminal -> handle == NULL || terminal -> encoder == NULL ||
317+ name == NULL || out_bytes == NULL || out_len == NULL ) {
318+ return GHOSTTY_INVALID_VALUE ;
319+ }
320+
321+ * out_bytes = NULL ;
322+ * out_len = 0 ;
323+
324+ GhosttyKey key = GHOSTTY_KEY_UNIDENTIFIED ;
325+ GhosttyMods mods = 0 ;
326+ int mapped = ptywright_ghostty_special_key (name , & key , & mods );
327+ if (mapped != GHOSTTY_SUCCESS ) {
328+ return mapped ;
329+ }
330+
331+ GhosttyKeyEvent event = NULL ;
332+ GhosttyResult result = ghostty_key_event_new (NULL , & event );
333+ if (result != GHOSTTY_SUCCESS ) {
334+ return result ;
335+ }
336+
337+ ghostty_key_event_set_action (event , GHOSTTY_KEY_ACTION_PRESS );
338+ ghostty_key_event_set_key (event , key );
339+ ghostty_key_event_set_mods (event , mods );
340+ ghostty_key_encoder_setopt_from_terminal (terminal -> encoder , terminal -> handle );
341+
342+ char stack [128 ];
343+ size_t written = 0 ;
344+ result = ghostty_key_encoder_encode (terminal -> encoder , event , stack , sizeof (stack ), & written );
345+ if (result == GHOSTTY_OUT_OF_SPACE ) {
346+ char * dynamic = malloc (written > 0 ? written : 1 );
347+ if (dynamic == NULL ) {
348+ ghostty_key_event_free (event );
349+ return GHOSTTY_OUT_OF_MEMORY ;
350+ }
351+ result = ghostty_key_encoder_encode (terminal -> encoder , event , dynamic , written , & written );
352+ if (result != GHOSTTY_SUCCESS ) {
353+ free (dynamic );
354+ ghostty_key_event_free (event );
355+ return result ;
356+ }
357+ * out_bytes = (uint8_t * )dynamic ;
358+ * out_len = written ;
359+ ghostty_key_event_free (event );
360+ return GHOSTTY_SUCCESS ;
361+ }
362+ if (result != GHOSTTY_SUCCESS ) {
363+ ghostty_key_event_free (event );
364+ return result ;
365+ }
366+
367+ if (written == 0 ) {
368+ ghostty_key_event_free (event );
369+ return GHOSTTY_SUCCESS ;
370+ }
371+
372+ uint8_t * copy = malloc (written );
373+ if (copy == NULL ) {
374+ ghostty_key_event_free (event );
375+ return GHOSTTY_OUT_OF_MEMORY ;
376+ }
377+ memcpy (copy , stack , written );
378+ * out_bytes = copy ;
379+ * out_len = written ;
380+ ghostty_key_event_free (event );
381+ return GHOSTTY_SUCCESS ;
382+ }
383+
266384int ptywright_ghostty_terminal_snapshot (PtywrightGhosttyTerminal * terminal ,
267385 int trim , int unwrap ,
268386 PtywrightGhosttySnapshot * out_snapshot ) {
@@ -416,6 +534,10 @@ void ptywright_ghostty_terminal_destroy(PtywrightGhosttyTerminal *terminal) {
416534 return ;
417535 }
418536
537+ if (terminal -> encoder != NULL ) {
538+ ghostty_key_encoder_free (terminal -> encoder );
539+ terminal -> encoder = NULL ;
540+ }
419541 if (terminal -> handle != NULL ) {
420542 ghostty_terminal_free (terminal -> handle );
421543 terminal -> handle = NULL ;
0 commit comments