/*********************************************************/
/* ptycon: a pty-console bridge */
/* Copyright (C) 2016--2017 SysDeer Technologies, LLC */
/* Released under GPLv2 and GPLv3; see COPYING.PTYCON. */
/*********************************************************/
#include <psxtypes/psxtypes.h>
#include <ntcon/ntcon.h>
#include <ntapi/ntapi.h>
#include <gdi/gdi.h>
#include <ptycon/ptycon.h>
#include "ptycon_driver_impl.h"
#include "ptycon_status_impl.h"
int __stdcall ptyc_console_ctrl(uint32_t);
int __stdcall ptyc_console_reader(void *);
int __stdcall ptyc_console_writer(void *);;
int __stdcall ptyc_console_poller(void *);
int __stdcall ptyc_dbg_cat(struct ptyc_driver_ctx *);
int __stdcall ptyc_dbg_event(void *);
int __stdcall ptyc_dbg_oven(void *);
int __stdcall ptyc_dbg_raw(void *);
struct ptyc_loop_thread_ctx {
nt_thread_start_routine * entry;
struct ptyc_driver_ctx_impl * ictx;
};
static int __stdcall ptyc_loop_thread_entry(void * ctx)
{
struct ptyc_loop_thread_ctx * xctx;
xctx = (struct ptyc_loop_thread_ctx *)ctx;
return ntapi->zw_terminate_thread(
NT_CURRENT_THREAD_HANDLE,
xctx->entry(xctx->ictx));
}
static int ptyc_create_loop_thread(
nt_thread_params * params,
struct ptyc_driver_ctx_impl * ictx,
nt_thread_start_routine * entry)
{
struct ptyc_loop_thread_ctx xctx;
xctx.entry = entry;
xctx.ictx = ictx;
/* rapunzel rapunzel */
params->hprocess = NT_CURRENT_PROCESS_HANDLE;
params->start = ptyc_loop_thread_entry;
params->ext_ctx = &xctx;
params->ext_ctx_size = sizeof(xctx);
params->stack_size_commit = 64 * 1024;
params->stack_size_reserve = 64 * 1024;
params->creation_flags = NT_CREATE_LOCAL_THREAD;
return ntapi->tt_create_thread(
params);
}
static int ptyc_free_console_impl(
struct ptyc_driver_ctx_impl * ictx,
int32_t status)
{
struct ptyc_term_ctx * tctx;
struct ptyc_loop_ctx * lctx;
tctx = &ictx->tctx;
lctx = &ictx->lctx;
if (tctx->hin)
ntcon->free_console();
if (lctx->treader.hthread)
ntapi->zw_close(lctx->treader.hthread);
if (lctx->twriter.hthread)
ntapi->zw_close(lctx->twriter.hthread);
if (lctx->tpoller.hthread)
ntapi->zw_close(lctx->tpoller.hthread);
if (lctx->tdbgevent.hthread)
ntapi->zw_close(lctx->tdbgevent.hthread);
if (lctx->tdbgoven.hthread)
ntapi->zw_close(lctx->tdbgoven.hthread);
if (lctx->tdbgraw.hthread)
ntapi->zw_close(lctx->tdbgraw.hthread);
return status;
}
static int ptyc_init_console(struct ptyc_term_ctx * tctx)
{
/* console input buffer) */
if (!(tctx->hin = ntcon->get_std_handle(NT_STD_INPUT_HANDLE)))
return NT_STATUS_UNSUCCESSFUL;
/* console screen buffer */
if (!(tctx->hout = ntcon->create_console_screen_buffer(
NT_GENERIC_READ | NT_GENERIC_WRITE,
0,0,NT_CONSOLE_TEXTMODE_BUFFER,0)))
return NT_STATUS_UNSUCCESSFUL;
if (!(ntcon->set_console_screen_buffer_size(
tctx->hout,
tctx->screen_size)))
return NT_STATUS_UNSUCCESSFUL;
if (!(ntcon->set_console_active_screen_buffer(tctx->hout)))
return NT_STATUS_UNSUCCESSFUL;
/* console text attributes: default colors */
if (!(ntcon->set_console_text_attribute(
tctx->hout,
NT_BACKGROUND_BLACK | NT_FOREGROUND_WHITE)))
return NT_STATUS_UNSUCCESSFUL;
/* console code page: utf-8 */
if (!(ntcon->set_console_code_page(65001)))
return NT_STATUS_NOT_SUPPORTED;
if (!(ntcon->set_console_output_code_page(65001)))
return NT_STATUS_NOT_SUPPORTED;
/* input events */
if (!(ntcon->set_console_mode(
tctx->hin,
NT_ENABLE_MOUSE_INPUT
| NT_ENABLE_WINDOW_INPUT)))
return NT_STATUS_UNSUCCESSFUL;
/* ctrl events */
if (!(ntcon->set_console_ctrl_handler(
ptyc_console_ctrl,
true)))
return NT_STATUS_UNSUCCESSFUL;
/* cursor info */
if (!(ntcon->get_console_cursor_info(
tctx->hout,
&tctx->cursor_info)))
return NT_STATUS_UNSUCCESSFUL;
return NT_STATUS_SUCCESS;
}
int ptyc_alloc_console(struct ptyc_driver_ctx * dctx)
{
int32_t status;
struct ptyc_driver_ctx_impl * ictx;
struct ptyc_term_ctx * tctx;
struct ptyc_loop_ctx * lctx;
if (!(ictx = ptyc_get_driver_ictx(dctx)))
return NT_STATUS_INVALID_HANDLE;
tctx = &ictx->tctx;
lctx = &ictx->lctx;
tctx->screen_size.x = 512;
tctx->screen_size.y = 4096;
tctx->drvflags = ictx->cctx.drvflags;
if (!(ntcon->alloc_console()))
return NT_STATUS_UNSUCCESSFUL;
if ((status = ptyc_init_console(tctx)))
return ptyc_set_status(dctx,status);
if ((status = ptyc_create_loop_thread(
&lctx->treader,
ictx,ptyc_console_reader)))
return ptyc_set_status(dctx,status);
if ((status = ptyc_create_loop_thread(
&lctx->twriter,
ictx,ptyc_console_writer)))
return ptyc_set_status(dctx,status);
if ((status = ptyc_create_loop_thread(
&lctx->tpoller,
ictx,ptyc_console_poller)))
return ptyc_set_status(dctx,status);
if (dctx->cctx->drvflags & PTYC_DRIVER_DBG_EVENT)
if ((status = ptyc_create_loop_thread(
&lctx->tdbgevent,
ictx,ptyc_dbg_event)))
return ptyc_set_status(dctx,status);
if (dctx->cctx->drvflags & PTYC_DRIVER_DBG_OVEN)
if ((status = ptyc_create_loop_thread(
&lctx->tdbgoven,
ictx,ptyc_dbg_oven)))
return ptyc_set_status(dctx,status);
if (dctx->cctx->drvflags & PTYC_DRIVER_DBG_RAW)
if ((status = ptyc_create_loop_thread(
&lctx->tdbgraw,
ictx,ptyc_dbg_raw)))
return ptyc_set_status(dctx,status);
if ((status = ptyc_dbg_cat(dctx)))
return ptyc_set_status(dctx,status);
return ptyc_set_status(dctx,NT_STATUS_SUCCESS);
}
int ptyc_wait_for_console(struct ptyc_driver_ctx * dctx)
{
struct ptyc_driver_ctx_impl * ictx;
if (!(ictx = ptyc_get_driver_ictx(dctx)))
return NT_STATUS_INVALID_HANDLE;
return ntapi->zw_wait_for_single_object(
ictx->lctx.tpoller.hthread,
NT_SYNC_ALERTABLE,0);
}
void ptyc_free_console(struct ptyc_driver_ctx * dctx)
{
struct ptyc_driver_ctx_impl * ictx;
if (!(ictx = ptyc_get_driver_ictx(dctx)))
return;
ptyc_free_console_impl(ictx,NT_STATUS_SUCCESS);
}