diff options
Diffstat (limited to 'src/console')
-rw-r--r-- | src/console/ptyc_console_writer.c | 145 |
1 files changed, 143 insertions, 2 deletions
diff --git a/src/console/ptyc_console_writer.c b/src/console/ptyc_console_writer.c index a0ea461..046e675 100644 --- a/src/console/ptyc_console_writer.c +++ b/src/console/ptyc_console_writer.c @@ -12,8 +12,149 @@ #include <ptycon/ptycon.h> #include "ptycon_driver_impl.h" +static ptyc_term_handler ptyc_screen_handler; +static ptyc_term_handler ptyc_ctrl_handler; +static ptyc_term_handler ptyc_flush_screen_buffer; + int ptyc_console_writer(struct ptyc_driver_ctx_impl * ictx) { - (void)ictx; - return ntapi->tt_wait_for_dummy_event(); + int32_t status; + nt_iosb iosb; + size_t nsteps; + void * hwait; + unsigned char * inbuf; + struct ptyc_term_ctx * tctx; + nt_unicode_conversion_params_utf8_to_utf16 uc_params; + + if ((status = ntapi->tt_create_private_event( + &hwait, + NT_NOTIFICATION_EVENT, + NT_EVENT_NOT_SIGNALED))) + return status; + + tctx = &ictx->tctx; + inbuf = (unsigned char *)&tctx->data.in[1]; + + uc_params.dst_size_in_bytes = sizeof(tctx->data.out); + uc_params.leftover_count = 0; + uc_params.leftover_bytes = 0; + + tctx->handler = ptyc_screen_handler; + tctx->char_handler = ptyc_screen_handler; + tctx->ctrl_handler = ptyc_ctrl_handler; + tctx->ctrl_handlers[0] = ptyc_esi_handlers; + tctx->wch_con = tctx->data.screen; + + do { + uc_params.code_points = 0; + uc_params.addr_failed = 0; + uc_params.bytes_written = 0; + + status = ntapi->pty_read( + ictx->cctx.hptm, + hwait,0,0, + &iosb, + inbuf, + sizeof(tctx->data.in) - sizeof(uintptr_t), + 0,0); + + if (status == NT_STATUS_PENDING) + status = ntapi->zw_wait_for_single_object( + hwait,NT_SYNC_ALERTABLE,0); + + if (status || iosb.status) { + ntapi->zw_close(hwait); + return status ? status : iosb.status; + } + + /* account for leftover bytes from the previous conversion */ + tctx->data.in[0] = uc_params.leftover_bytes; + uc_params.src = inbuf - uc_params.leftover_bytes; + uc_params.src_size_in_bytes = iosb.info + uc_params.leftover_count; + uc_params.dst = tctx->data.out; + + + /* utf-8 --> utf-16 */ + status = ntapi->uc_convert_unicode_stream_utf8_to_utf16( + &uc_params); + + /* process the converted (utf-16) stream */ + tctx->wch_pty = tctx->data.out; + nsteps = uc_params.bytes_written / sizeof(wchar16_t); + + for (; nsteps; nsteps--) + tctx->handler = (ptyc_term_handler *)tctx->handler(tctx); + + /* output to console */ + ptyc_flush_screen_buffer(tctx); + } while (1); + + return NT_STATUS_INTERNAL_ERROR; +} + + +static void * __fastcall ptyc_screen_handler(struct ptyc_term_ctx * tctx) +{ + if (*tctx->wch_pty == '\x1b') { + /* output all pending characters */ + ptyc_flush_screen_buffer(tctx); + + /* advance stream pointer */ + tctx->wch_pty++; + + /* set initial control state */ + tctx->ctrl_state = PTYC_CTRL_STATE_ESI; + tctx->ctrl_cap = PTYC_ESI_ARRAY_SIZE; + + /* switch mode */ + return tctx->ctrl_handler; + } else { + /* copy character to the screen buffer */ + *tctx->wch_con = *tctx->wch_pty; + + /* advance the screen and stream pointers */ + tctx->wch_con++; + tctx->wch_pty++; + + /* retain mode */ + return ptyc_screen_handler; + } +} + + +static void * __fastcall ptyc_ctrl_handler(struct ptyc_term_ctx * tctx) +{ + ptyc_term_handler * const * handlers; + ptyc_term_handler * handler; + unsigned idx; + + idx = (*tctx->wch_pty < tctx->ctrl_cap) + ? *tctx->wch_pty + : tctx->ctrl_cap - 1; + + handlers = tctx->ctrl_handlers[tctx->ctrl_state]; + handler = handlers[idx]; + + return handler(tctx); +} + + +static void * __fastcall ptyc_flush_screen_buffer(struct ptyc_term_ctx * tctx) +{ + uint32_t ncunits; + uint32_t nwritten; + + if (!(ncunits = (uint32_t)(tctx->wch_con - tctx->data.screen))) + return tctx->wch_con; + + ntcon->write_console_utf16( + tctx->hout, + tctx->data.screen, + ncunits, + &nwritten, + 0); + + tctx->wch_con = tctx->data.screen; + + return tctx->wch_con; } |