/*********************************************************/ /* ptycon: a pty-console bridge */ /* Copyright (C) 2016--2017 SysDeer Technologies, LLC */ /* Released under GPLv2 and GPLv3; see COPYING.PTYCON. */ /*********************************************************/ #include #include #include #include #include #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; itctx.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; }