Blame src/console/ptyc_console_writer.c

1bab02
/*********************************************************/
1bab02
/*  ptycon: a pty-console bridge                         */
f25e99
/*  Copyright (C) 2016--2017  SysDeer Technologies, LLC  */
1bab02
/*  Released under GPLv2 and GPLv3; see COPYING.PTYCON.  */
1bab02
/*********************************************************/
1bab02
1bab02
#include <psxtypes/psxtypes.h>
1bab02
#include <ntcon/ntcon.h>
1bab02
#include <ntapi/ntapi.h>
1bab02
#include <gdi/gdi.h>
1bab02
1bab02
#include <ptycon/ptycon.h>
1bab02
#include "ptycon_driver_impl.h"
6db2d7
#include "ptycon_status_impl.h"
1bab02
640ed3
static ptyc_term_handler	ptyc_screen_handler;
640ed3
static ptyc_term_handler	ptyc_ctrl_handler;
640ed3
static ptyc_term_handler	ptyc_flush_screen_buffer;
640ed3
5399d4
int __stdcall ptyc_console_writer(struct ptyc_driver_ctx_impl * ictx)
1bab02
{
640ed3
	int32_t						status;
640ed3
	nt_iosb						iosb;
640ed3
	size_t						nsteps;
640ed3
	void *						hwait;
640ed3
	unsigned char *					inbuf;
640ed3
	struct ptyc_term_ctx *				tctx;
640ed3
	nt_unicode_conversion_params_utf8_to_utf16	uc_params;
640ed3
640ed3
	if ((status = ntapi->tt_create_private_event(
640ed3
			&hwait,
640ed3
			NT_NOTIFICATION_EVENT,
640ed3
			NT_EVENT_NOT_SIGNALED)))
640ed3
		return status;
640ed3
640ed3
	tctx				= &ictx->tctx;
640ed3
	inbuf				= (unsigned char *)&tctx->data.in[1];
640ed3
640ed3
	uc_params.dst_size_in_bytes	= sizeof(tctx->data.out);
640ed3
	uc_params.leftover_count	= 0;
640ed3
	uc_params.leftover_bytes	= 0;
640ed3
640ed3
	tctx->handler			= ptyc_screen_handler;
640ed3
	tctx->char_handler		= ptyc_screen_handler;
640ed3
	tctx->ctrl_handler		= ptyc_ctrl_handler;
640ed3
	tctx->ctrl_handlers[0]		= ptyc_esi_handlers;
640ed3
	tctx->wch_con			= tctx->data.screen;
640ed3
640ed3
	do {
640ed3
		uc_params.code_points	= 0;
640ed3
		uc_params.addr_failed	= 0;
640ed3
		uc_params.bytes_written	= 0;
640ed3
640ed3
		status = ntapi->pty_read(
640ed3
			ictx->cctx.hptm,
640ed3
			hwait,0,0,
640ed3
			&iosb,
640ed3
			inbuf,
640ed3
			sizeof(tctx->data.in) - sizeof(uintptr_t),
640ed3
			0,0);
640ed3
640ed3
		if (status == NT_STATUS_PENDING)
6db2d7
			if (!(status = ntapi->zw_wait_for_single_object(
6db2d7
					hwait,NT_SYNC_ALERTABLE,0)))
6db2d7
				status = iosb.status;
640ed3
6db2d7
		if (status)
6db2d7
			return ptyc_set_status(&ictx->ctx,status);
640ed3
640ed3
		/* account for leftover bytes from the previous conversion */
640ed3
		tctx->data.in[0]		= uc_params.leftover_bytes;
da425a
		uc_params.src			= inbuf - uc_params.leftover_count;
640ed3
		uc_params.src_size_in_bytes	= iosb.info + uc_params.leftover_count;
640ed3
		uc_params.dst			= tctx->data.out;
640ed3
640ed3
640ed3
		/* utf-8 --> utf-16 */
640ed3
		status = ntapi->uc_convert_unicode_stream_utf8_to_utf16(
640ed3
			&uc_params);
640ed3
640ed3
		/* process the converted (utf-16) stream */
640ed3
		tctx->wch_pty = tctx->data.out;
640ed3
		nsteps        = uc_params.bytes_written / sizeof(wchar16_t);
640ed3
640ed3
		for (; nsteps; nsteps--)
640ed3
			tctx->handler = (ptyc_term_handler *)tctx->handler(tctx);
640ed3
640ed3
		/* output to console */
640ed3
		ptyc_flush_screen_buffer(tctx);
640ed3
	} while (1);
640ed3
640ed3
	return NT_STATUS_INTERNAL_ERROR;
640ed3
}
640ed3
640ed3
640ed3
static void * __fastcall ptyc_screen_handler(struct ptyc_term_ctx * tctx)
640ed3
{
640ed3
	if (*tctx->wch_pty == '\x1b') {
640ed3
		/* output all pending characters */
640ed3
		ptyc_flush_screen_buffer(tctx);
640ed3
640ed3
		/* advance stream pointer */
640ed3
		tctx->wch_pty++;
640ed3
640ed3
		/* set initial control state */
640ed3
		tctx->ctrl_state = PTYC_CTRL_STATE_ESI;
640ed3
		tctx->ctrl_cap   = PTYC_ESI_ARRAY_SIZE;
640ed3
640ed3
		/* switch mode */
640ed3
		return tctx->ctrl_handler;
640ed3
	} else {
79c2fe
		/* filter out bell key? */
79c2fe
		if (*tctx->wch_pty == 0x7)
79c2fe
			if (!(tctx->drvflags & PTYC_DRIVER_BELL))
79c2fe
				return ptyc_screen_handler;
79c2fe
640ed3
		/* copy character to the screen buffer */
640ed3
		*tctx->wch_con = *tctx->wch_pty;
640ed3
640ed3
		/* advance the screen and stream pointers */
640ed3
		tctx->wch_con++;
640ed3
		tctx->wch_pty++;
640ed3
640ed3
		/* retain mode */
640ed3
		return ptyc_screen_handler;
640ed3
	}
640ed3
}
640ed3
640ed3
640ed3
static void * __fastcall ptyc_ctrl_handler(struct ptyc_term_ctx * tctx)
640ed3
{
640ed3
	ptyc_term_handler * const *	handlers;
640ed3
	ptyc_term_handler *		handler;
640ed3
	unsigned			idx;
640ed3
640ed3
	idx = (*tctx->wch_pty < tctx->ctrl_cap)
640ed3
			? *tctx->wch_pty
640ed3
			: tctx->ctrl_cap - 1;
640ed3
640ed3
	handlers = tctx->ctrl_handlers[tctx->ctrl_state];
640ed3
	handler  = handlers[idx];
640ed3
640ed3
	return handler(tctx);
640ed3
}
640ed3
640ed3
640ed3
static void * __fastcall ptyc_flush_screen_buffer(struct ptyc_term_ctx * tctx)
640ed3
{
640ed3
	uint32_t ncunits;
640ed3
	uint32_t nwritten;
640ed3
640ed3
	if (!(ncunits = (uint32_t)(tctx->wch_con - tctx->data.screen)))
640ed3
		return tctx->wch_con;
640ed3
640ed3
	ntcon->write_console_utf16(
640ed3
		tctx->hout,
640ed3
		tctx->data.screen,
640ed3
		ncunits,
640ed3
		&nwritten,
640ed3
		0);
640ed3
eb4b7f
	/* heuristics: interactive input? */
eb4b7f
	if (ncunits <= 4) {
eb4b7f
		ntcon->get_console_screen_buffer_info(
eb4b7f
			tctx->hout,
eb4b7f
			&tctx->screen_info);
eb4b7f
eb4b7f
		ntcon->set_console_cursor_position(
eb4b7f
			tctx->hout,
eb4b7f
			tctx->screen_info.cursor_position);
eb4b7f
	}
2ded43
640ed3
	tctx->wch_con = tctx->data.screen;
640ed3
640ed3
	return tctx->wch_con;
1bab02
}