/*********************************************************/
/* ptycon: a pty-console bridge */
/* Copyright (C) 2016--2017 Z. Gilboa */
/* 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"
typedef nt_unicode_conversion_params_utf16_to_utf8 uc_conv_params;
extern const struct ptyc_vkcode ptyc_vkcode[0x100];
static size_t ptyc_repeat(unsigned char * ch, size_t n, uint16_t count)
{
unsigned char * dst;
int i;
if (!--count)
return n;
if (n == 1) {
for (i=count, dst=&ch[n]; i; i--) {
dst[0] = ch[0];
dst = &dst[n];
}
} else if (n == 2) {
for (i=count, dst=&ch[n]; i; i--) {
dst[0] = ch[0];
dst[1] = ch[1];
dst = &dst[n];
}
} else if (n == 3) {
for (i=count, dst=&ch[n]; i; i--) {
dst[0] = ch[0];
dst[1] = ch[1];
dst[2] = ch[2];
dst = &dst[n];
}
} else if (n == 4) {
for (i=count, dst=&ch[n]; i; i--) {
dst[0] = ch[0];
dst[1] = ch[1];
dst[2] = ch[2];
dst[3] = ch[3];
dst = &dst[n];
}
}
return n*count;
}
static size_t ptyc_translate_virtual_keycode(
nt_input_record * rec,
unsigned char * ch)
{
ntapi->tt_generic_memcpy(
ch,
ptyc_vkcode[rec->key_event.virtual_key_code].mbstr,
ptyc_vkcode[rec->key_event.virtual_key_code].mblen);
return ptyc_repeat(
ch,
ptyc_vkcode[rec->key_event.virtual_key_code].mblen,
rec->key_event.repeat_count);
}
static size_t ptyc_translate_keyboard_event(
nt_input_record * rec,
unsigned char * ch,
wchar16_t * wch)
{
wchar16_t src[2];
wchar16_t recwch;
uint32_t nbytes;
uc_conv_params params = {0,0,0,0,0,0,0,0,0};
if (!rec->key_event.key_down)
return 0;
if (!(recwch = rec->key_event.unicode_char))
return ptyc_translate_virtual_keycode(
rec,ch);
if (recwch == 0x08)
recwch = 0x7f;
if (*wch) {
if ((recwch < 0xDC00) || (recwch >= 0xE000)) {
*wch = 0;
return 0;
} else {
src[0] = *wch;
src[1] = recwch;
*wch = 0;
nbytes = 2*sizeof(wchar16_t);
}
} else if ((recwch >= 0xD800) && (recwch < 0xDC00)) {
*wch = recwch;
return 0;
} else {
src[0] = recwch;
nbytes = sizeof(wchar16_t);
}
params.src = src;
params.src_size_in_bytes = nbytes;
params.dst = ch;
params.dst_size_in_bytes = 4;
ntapi->uc_convert_unicode_stream_utf16_to_utf8(
¶ms);
return ptyc_repeat(
ch,
params.bytes_written,
rec->key_event.repeat_count);
}
static size_t ptyc_translate_mouse_event(
nt_input_record * rec,
unsigned char * ch)
{
(void)rec;
(void)ch;
return 0;
}
static size_t ptyc_translate_window_event(nt_input_record * rec)
{
(void)rec;
return 0;
}
static size_t ptyc_translate_menu_event(nt_input_record * rec)
{
(void)rec;
return 0;
}
static size_t ptyc_translate_focus_event(nt_input_record * rec)
{
(void)rec;
return 0;
}
static size_t ptyc_translate_event(
nt_input_record * rec,
unsigned char * ch,
wchar16_t * wch)
{
switch (rec->event_type) {
case NT_KEY_EVENT:
return ptyc_translate_keyboard_event(
rec,ch,wch);
case NT_MOUSE_EVENT:
return ptyc_translate_mouse_event(
rec,ch);
case NT_WINDOW_BUFFER_SIZE_EVENT:
return ptyc_translate_window_event(rec);
case NT_MENU_EVENT:
return ptyc_translate_menu_event(rec);
case NT_FOCUS_EVENT:
return ptyc_translate_focus_event(rec);
}
return 0;
}
int __stdcall ptyc_console_reader(struct ptyc_driver_ctx_impl * ictx)
{
int32_t status;
void * hwait;
nt_iosb iosb;
uint32_t nevents;
size_t nbytes;
wchar16_t wch;
unsigned char * ch;
unsigned i;
if ((status = ntapi->tt_create_private_event(
&hwait,
NT_NOTIFICATION_EVENT,
NT_EVENT_NOT_SIGNALED)))
return status;
do {
if (!(ntcon->read_console_input_utf16(
ictx->tctx.hin,
ictx->tctx.input.events,
PTYC_RAW_EVENTS,
&nevents)))
return NT_STATUS_ALREADY_DISCONNECTED;
for (ch=ictx->tctx.input.stream, i=0; i<nevents; i++)
ch += ptyc_translate_event(
&ictx->tctx.input.events[i],
ch,&wch);
nbytes = ch - ictx->tctx.input.stream;
ch = ictx->tctx.input.stream;
for (; nbytes; ) {
status = ntapi->pty_write(
ictx->cctx.hptm,
hwait,0,0,&iosb,
ch,(uint32_t)nbytes,
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;
}
ch += iosb.info;
nbytes -= iosb.info;
}
} while (1);
return NT_STATUS_INTERNAL_ERROR;
}