Skip to content

Instantly share code, notes, and snippets.

@Hamayama
Last active August 8, 2024 21:04
Show Gist options
  • Save Hamayama/6add968870269f2426716fad79724b31 to your computer and use it in GitHub Desktop.
Save Hamayama/6add968870269f2426716fad79724b31 to your computer and use it in GitHub Desktop.
Windows Console Mouse Input Test
/*
Windows Console Mouse Input Test
2021-3-13 v1.28
OS : Windows 10 (version 20H2) (64bit)
DevTools : MSYS2/MinGW-w64 (64bit) (gcc version 10.2.0 (Rev6, Built by MSYS2 project)))
Terminal : Windows Terminal 1.6.10571.0
Compile : gcc -g -O2 -Wall -Wextra -o wincon_mouse.exe wincon_mouse.c
*/
#include <windows.h>
#include <stdio.h>
#include <stdlib.h>
#ifndef DISABLE_VT_MOUSE_INPUT
#define USE_VT_MOUSE_INPUT
#endif
#ifndef DISABLE_DBG_PRINT
#define USE_DBG_PRINT
#endif
#ifdef USE_DBG_PRINT
#define DBG_PRINT(...) fprintf(stderr, __VA_ARGS__);
#else
#define DBG_PRINT(...) do { } while (0)
#endif
#define MAX_INPUT_REC_LEN 20
#define MAX_VT_INPUT_SEQ_LEN 6
/* vt escape sequence input structure */
struct vt_input
{
char seq[MAX_VT_INPUT_SEQ_LEN + 1];
int seq_len;
WORD vk;
WORD vs;
WCHAR uchar;
DWORD ctrl;
int modifier_index;
};
/* vt escape sequence input table
( https://docs.microsoft.com/en-us/windows/console/console-virtual-terminal-sequences#input-sequences )
*/
static const struct vt_input vt_input_table[] = {
{ "[A", 2, 0x26, 0x48, 0, 0x0100, 0 }, /* Up Arrow */
{ "[B", 2, 0x28, 0x50, 0, 0x0100, 0 }, /* Down Arrow */
{ "[C", 2, 0x27, 0x4d, 0, 0x0100, 0 }, /* Right Arrow */
{ "[D", 2, 0x25, 0x4b, 0, 0x0100, 0 }, /* Left Arrow */
{ "[H", 2, 0x24, 0x47, 0, 0x0100, 0 }, /* Home */
{ "[F", 2, 0x23, 0x4f, 0, 0x0100, 0 }, /* End */
{ "[1;@A", 5, 0x26, 0x48, 0, 0x0100, 3 }, /* ModifierKeys + Up Arrow */
{ "[1;@B", 5, 0x28, 0x50, 0, 0x0100, 3 }, /* ModifierKeys + Down Arrow */
{ "[1;@C", 5, 0x27, 0x4d, 0, 0x0100, 3 }, /* ModifierKeys + Right Arrow */
{ "[1;@D", 5, 0x25, 0x4b, 0, 0x0100, 3 }, /* ModifierKeys + Left Arrow */
{ "[1;@H", 5, 0x24, 0x47, 0, 0x0100, 3 }, /* ModifierKeys + Home */
{ "[1;@F", 5, 0x23, 0x4f, 0, 0x0100, 3 }, /* ModifierKeys + End */
{ "[2~", 3, 0x2d, 0x52, 0, 0x0100, 0 }, /* Insert */
{ "[3~", 3, 0x2e, 0x53, 0, 0x0100, 0 }, /* Delete */
{ "[5~", 3, 0x21, 0x49, 0, 0x0100, 0 }, /* Page Up */
{ "[6~", 3, 0x22, 0x51, 0, 0x0100, 0 }, /* Page Down */
{ "[2;@~", 5, 0x2d, 0x52, 0, 0x0100, 3 }, /* ModifierKeys + Insert */
{ "[3;@~", 5, 0x2e, 0x53, 0, 0x0100, 3 }, /* ModifierKeys + Delete */
{ "[5;@~", 5, 0x21, 0x49, 0, 0x0100, 3 }, /* ModifierKeys + Page Up */
{ "[6;@~", 5, 0x22, 0x51, 0, 0x0100, 3 }, /* ModifierKeys + Page Down */
{ "OP", 2, 0x70, 0x3b, 0, 0x0000, 0 }, /* F1 */
{ "OQ", 2, 0x71, 0x3c, 0, 0x0000, 0 }, /* F2 */
{ "OR", 2, 0x72, 0x3d, 0, 0x0000, 0 }, /* F3 */
{ "OS", 2, 0x73, 0x3e, 0, 0x0000, 0 }, /* F4 */
{ "[15~", 4, 0x74, 0x3f, 0, 0x0000, 0 }, /* F5 */
{ "[17~", 4, 0x75, 0x40, 0, 0x0000, 0 }, /* F6 */
{ "[18~", 4, 0x76, 0x41, 0, 0x0000, 0 }, /* F7 */
{ "[19~", 4, 0x77, 0x42, 0, 0x0000, 0 }, /* F8 */
{ "[20~", 4, 0x78, 0x43, 0, 0x0000, 0 }, /* F9 */
{ "[21~", 4, 0x79, 0x44, 0, 0x0000, 0 }, /* F10 */
{ "[23~", 4, 0x7a, 0x57, 0, 0x0000, 0 }, /* F11 */
{ "[24~", 4, 0x7b, 0x58, 0, 0x0000, 0 }, /* F12 */
{ "[1;@P", 5, 0x70, 0x3b, 0, 0x0000, 3 }, /* ModifierKeys + F1 */
{ "[1;@Q", 5, 0x71, 0x3c, 0, 0x0000, 3 }, /* ModifierKeys + F2 */
{ "[1;@R", 5, 0x72, 0x3d, 0, 0x0000, 3 }, /* ModifierKeys + F3 */
{ "[1;@S", 5, 0x73, 0x3e, 0, 0x0000, 3 }, /* ModifierKeys + F4 */
{ "[15;@~", 6, 0x74, 0x3f, 0, 0x0000, 4 }, /* ModifierKeys + F5 */
{ "[17;@~", 6, 0x75, 0x40, 0, 0x0000, 4 }, /* ModifierKeys + F6 */
{ "[18;@~", 6, 0x76, 0x41, 0, 0x0000, 4 }, /* ModifierKeys + F7 */
{ "[19;@~", 6, 0x77, 0x42, 0, 0x0000, 4 }, /* ModifierKeys + F8 */
{ "[20;@~", 6, 0x78, 0x43, 0, 0x0000, 4 }, /* ModifierKeys + F9 */
{ "[21;@~", 6, 0x79, 0x44, 0, 0x0000, 4 }, /* ModifierKeys + F10 */
{ "[23;@~", 6, 0x7a, 0x57, 0, 0x0000, 4 }, /* ModifierKeys + F11 */
{ "[24;@~", 6, 0x7b, 0x58, 0, 0x0000, 4 }, /* ModifierKeys + F12 */
{ "[Z", 2, 0x9, 0xf, 0x9, 0x0000, 0 } /* Shift + Tab */
};
/* inner functions */
static int is_vt_input(const INPUT_RECORD *input_rec_ptr);
static void set_key_event(PINPUT_RECORD input_rec_ptr, WORD vk, WORD vs, WCHAR uchar, DWORD ctrl);
static BOOL consume_vt_input(HANDLE hin, int input_seq_len);
static BOOL read_console_input_w_sub(HANDLE hin, PINPUT_RECORD input_rec_ptr, DWORD input_rec_len, LPDWORD read_event_num_ptr, int peek_flag);
/* api functions */
BOOL PDC_peek_console_input_w(HANDLE hin, PINPUT_RECORD input_rec_ptr, DWORD input_rec_len, LPDWORD read_event_num_ptr);
BOOL PDC_read_console_input_w(HANDLE hin, PINPUT_RECORD input_rec_ptr, DWORD input_rec_len, LPDWORD read_event_num_ptr);
/* check vt escape sequence */
static int is_vt_input(const INPUT_RECORD *input_rec_ptr)
{
return (input_rec_ptr->EventType == KEY_EVENT &&
input_rec_ptr->Event.KeyEvent.bKeyDown &&
input_rec_ptr->Event.KeyEvent.wVirtualKeyCode == 0 &&
input_rec_ptr->Event.KeyEvent.wVirtualScanCode == 0);
}
/* set key event */
static void set_key_event(PINPUT_RECORD input_rec_ptr, WORD vk, WORD vs, WCHAR uchar, DWORD ctrl)
{
input_rec_ptr->EventType = KEY_EVENT;
input_rec_ptr->Event.KeyEvent.bKeyDown = 1;
input_rec_ptr->Event.KeyEvent.wRepeatCount = 1;
input_rec_ptr->Event.KeyEvent.wVirtualKeyCode = vk;
input_rec_ptr->Event.KeyEvent.wVirtualScanCode = vs;
input_rec_ptr->Event.KeyEvent.uChar.UnicodeChar = uchar;
input_rec_ptr->Event.KeyEvent.dwControlKeyState = ctrl;
}
/* consume vt escape sequence */
static BOOL consume_vt_input(HANDLE hin, int input_seq_len) {
INPUT_RECORD input_rec[MAX_INPUT_REC_LEN];
DWORD read_event_num;
/* check arguments */
if (input_seq_len > MAX_INPUT_REC_LEN) {
DBG_PRINT("internal error. (consume)\n");
SetLastError(ERROR_INTERNAL_ERROR);
return FALSE;
}
/* consume vt escape sequence */
if (!ReadConsoleInputW(hin, input_rec, input_seq_len, &read_event_num)) {
DBG_PRINT("ReadConsoleInputW failed. (consume)\n");
return FALSE;
}
if ((int)read_event_num < input_seq_len) {
DBG_PRINT("ReadConsoleInputW returned before read. (consume)\n");
SetLastError(ERROR_INTERNAL_ERROR);
return FALSE;
}
return TRUE;
}
/* peek/read console input
limitations:
- only one input record is returned.
- separated receive of vt escape sequence is not supported.
- double click event is not supported.
- horizontal mouse wheel is not supported.
- virtual key code and virtual scan code casually become zero.
- Alt + X key combination input is split into Esc and X key events.
- mouse coordinates origin is top left of screen (not top left of buffer).
*/
BOOL PDC_peek_console_input_w(HANDLE hin, PINPUT_RECORD input_rec_ptr, DWORD input_rec_len, LPDWORD read_event_num_ptr)
{
return read_console_input_w_sub(hin, input_rec_ptr, input_rec_len, read_event_num_ptr, 1);
}
BOOL PDC_read_console_input_w(HANDLE hin, PINPUT_RECORD input_rec_ptr, DWORD input_rec_len, LPDWORD read_event_num_ptr)
{
return read_console_input_w_sub(hin, input_rec_ptr, input_rec_len, read_event_num_ptr, 0);
}
static BOOL read_console_input_w_sub(HANDLE hin, PINPUT_RECORD input_rec_ptr, DWORD input_rec_len, LPDWORD read_event_num_ptr, int peek_flag)
{
static DWORD mouse_button_state = 0;
static DWORD ctrl_state = 0;
INPUT_RECORD input_rec2[MAX_INPUT_REC_LEN];
DWORD read_event_num2;
char input_seq[MAX_INPUT_REC_LEN + 1];
int input_seq_len;
int input_seq_len2;
int vt_input_table_len;
int mouse_cmd_read_state;
int mouse_button_param;
int mouse_x;
int mouse_y;
int mouse_button_press;
DWORD mouse_event_flags;
int ret_val;
int i;
/* initialize return data */
*read_event_num_ptr = 0;
/* check arguments */
if (input_rec_len == 0) {
/* DBG_PRINT("specified input record length is zero.\n"); */
return TRUE;
}
/* check peek flag */
if (peek_flag) {
/* peek all console input */
if (!PeekConsoleInputW(hin, input_rec2, MAX_INPUT_REC_LEN, &read_event_num2)) {
DBG_PRINT("PeekConsoleInputW failed. (input_rec2)\n");
return FALSE;
}
if (read_event_num2 == 0) {
/* DBG_PRINT("PeekConsoleInputW returned before read. (input_rec2)\n"); */
return TRUE;
}
} else {
/* read one console input */
if (!ReadConsoleInputW(hin, input_rec2, 1, &read_event_num2)) {
DBG_PRINT("ReadConsoleInputW failed. (input_rec2)\n");
return FALSE;
}
if (read_event_num2 == 0) {
DBG_PRINT("ReadConsoleInputW returned before read. (input_rec2)\n");
SetLastError(ERROR_INTERNAL_ERROR);
return FALSE;
}
/* peek all console input */
if (!PeekConsoleInputW(hin, &input_rec2[1], MAX_INPUT_REC_LEN - 1, &read_event_num2)) {
DBG_PRINT("PeekConsoleInputW failed. (input_rec2) (after read)\n");
return FALSE;
}
read_event_num2++;
}
/* check read event number */
if (read_event_num2 > MAX_INPUT_REC_LEN) {
DBG_PRINT("internal error. (input_rec2)\n");
SetLastError(ERROR_INTERNAL_ERROR);
return FALSE;
}
/* set return data (only one input record is returned) */
*read_event_num_ptr = 1;
memcpy(input_rec_ptr, &input_rec2[0], sizeof(INPUT_RECORD));
/* get/set modifier key state */
if (input_rec2[0].EventType == KEY_EVENT) {
if (!is_vt_input(&input_rec2[0])) {
/* get modifier key state */
ctrl_state = input_rec2[0].Event.KeyEvent.dwControlKeyState;
} else {
/* vt escape sequence doesn't have modifier key state.
so, we set the current state here. */
/* (drop left alt key state to avoid unwanted character code
conversion on PDCurses) */
input_rec_ptr->Event.KeyEvent.dwControlKeyState = ctrl_state & ~LEFT_ALT_PRESSED;
}
}
/* convert some keys */
if (is_vt_input(&input_rec2[0]) &&
input_rec2[0].Event.KeyEvent.uChar.UnicodeChar == 0x7f) { /* Backspace */
set_key_event(input_rec_ptr, 0x8, 0xe, 0x8, ctrl_state);
return TRUE;
}
if (is_vt_input(&input_rec2[0]) &&
input_rec2[0].Event.KeyEvent.uChar.UnicodeChar == 0x8) { /* Ctrl + Backspace */
set_key_event(input_rec_ptr, 0x8, 0xe, 0x7f, ctrl_state);
return TRUE;
}
#if 0
/* this breaks Ctrl + Z key input */
if (is_vt_input(&input_rec2[0]) &&
input_rec2[0].Event.KeyEvent.uChar.UnicodeChar == 0x1a) { /* Pause */
set_key_event(input_rec_ptr, 0x13, 0x45, 0, ctrl_state);
return TRUE;
}
#endif
if (input_rec2[0].EventType == KEY_EVENT &&
input_rec2[0].Event.KeyEvent.bKeyDown &&
input_rec2[0].Event.KeyEvent.wVirtualKeyCode == 0x32 &&
input_rec2[0].Event.KeyEvent.wVirtualScanCode == 0 &&
input_rec2[0].Event.KeyEvent.uChar.UnicodeChar == 0) { /* Ctrl + Space */
set_key_event(input_rec_ptr, 0x20, 0x39, 0x20, ctrl_state);
return TRUE;
}
if (is_vt_input(&input_rec2[0]) &&
input_rec2[0].Event.KeyEvent.uChar.UnicodeChar == 0x9) { /* Ctrl + Tab */
set_key_event(input_rec_ptr, 0x9, 0xf, 0x0, ctrl_state);
return TRUE;
}
/* process vt escape sequence */
if (is_vt_input(&input_rec2[0]) &&
input_rec2[0].Event.KeyEvent.uChar.UnicodeChar == 0x1b) {
/* read vt escape sequence */
input_seq_len = 0;
for (i = 1; i < (int)read_event_num2; i++) {
if (is_vt_input(&input_rec2[i]) &&
input_rec2[i].Event.KeyEvent.uChar.UnicodeChar <= 0x7f) {
input_seq[input_seq_len] = input_rec2[i].Event.KeyEvent.uChar.UnicodeChar;
input_seq_len++;
continue;
}
break;
}
input_seq[input_seq_len] = 0;
#if 0
/* for debug */
DBG_PRINT(" vt input seq : ");
for (i = 0; i < MAX_INPUT_REC_LEN; i++) {
DBG_PRINT("%02x ", (unsigned char)input_seq[i]);
}
DBG_PRINT("\n");
#endif
/* process vt escape sequence of mouse input (sgr-1006) '[<' */
if (input_seq_len >= 2 &&
input_seq[0] == 0x5b &&
input_seq[1] == 0x3c) {
input_seq_len2 = 2;
/* read parameters 'Db ; Dx ; Dy M/m' */
mouse_cmd_read_state = 0;
mouse_button_param = 0;
mouse_x = 0;
mouse_y = 0;
mouse_button_press = 0;
mouse_event_flags = 0;
ret_val = FALSE;
for (i = 2; i < input_seq_len; i++) {
switch (mouse_cmd_read_state) {
case 0:
/* read mouse button parameter 'Db' */
if (input_seq[i] >= 0x30 && input_seq[i] <= 0x39) {
input_seq_len2++;
mouse_button_param *= 10;
mouse_button_param += input_seq[i] - 0x30;
if (mouse_button_param < 10000) {
continue;
}
}
/* read delimiter ';' */
if (input_seq[i] == 0x3b) {
input_seq_len2++;
mouse_cmd_read_state++;
continue;
}
break;
case 1:
/* read mouse position x 'Dx' */
if (input_seq[i] >= 0x30 && input_seq[i] <= 0x39) {
input_seq_len2++;
mouse_x *= 10;
mouse_x += input_seq[i] - 0x30;
if (mouse_x < 10000) {
continue;
}
}
/* read delimiter ';' */
if (input_seq[i] == 0x3b) {
input_seq_len2++;
mouse_cmd_read_state++;
continue;
}
break;
case 2:
/* read mouse position y 'Dy' */
if (input_seq[i] >= 0x30 && input_seq[i] <= 0x39) {
input_seq_len2++;
mouse_y *= 10;
mouse_y += input_seq[i] - 0x30;
if (mouse_y < 10000) {
continue;
}
}
/* read button on/off 'M/m' */
if ((input_seq[i] == 0x4d || input_seq[i] == 0x6d)) {
input_seq_len2++;
mouse_button_press = (input_seq[i] == 0x4d) ? 1 : 0;
/* make mouse event */
input_rec_ptr->EventType = MOUSE_EVENT;
input_rec_ptr->Event.MouseEvent.dwMousePosition.X = mouse_x - 1;
input_rec_ptr->Event.MouseEvent.dwMousePosition.Y = mouse_y - 1;
input_rec_ptr->Event.MouseEvent.dwButtonState = 0;
input_rec_ptr->Event.MouseEvent.dwControlKeyState = ctrl_state;
input_rec_ptr->Event.MouseEvent.dwEventFlags = 0;
/* set mouse button state */
mouse_button_state &= ~0xffff0000; /* clear wheel movement amount */
switch (mouse_button_param & 0xc3) { /* extract button no */
case 0: /* left button */
if (mouse_button_press) {
mouse_button_state |= FROM_LEFT_1ST_BUTTON_PRESSED;
} else {
mouse_button_state &= ~FROM_LEFT_1ST_BUTTON_PRESSED;
}
break;
case 1: /* middle button */
if (mouse_button_press) {
mouse_button_state |= FROM_LEFT_2ND_BUTTON_PRESSED;
} else {
mouse_button_state &= ~FROM_LEFT_2ND_BUTTON_PRESSED;
}
break;
case 2: /* right button */
if (mouse_button_press) {
mouse_button_state |= RIGHTMOST_BUTTON_PRESSED;
} else {
mouse_button_state &= ~RIGHTMOST_BUTTON_PRESSED;
}
break;
case 64: /* vertical wheel up */
mouse_event_flags |= MOUSE_WHEELED;
mouse_button_state |= 0x00780000;
break;
case 65: /* vertical wheel down */
mouse_event_flags |= MOUSE_WHEELED;
mouse_button_state |= 0xff880000;
break;
}
input_rec_ptr->Event.MouseEvent.dwButtonState = mouse_button_state;
/* set mouse event flags */
if (mouse_button_param & 0x20) { /* mouse moved */
/* PDCurses uses MOUSE_MOVED with a different definition from Win32 API */
/* mouse_event_flags |= MOUSE_MOVED; */
mouse_event_flags |= 0x1;
}
input_rec_ptr->Event.MouseEvent.dwEventFlags = mouse_event_flags;
/* succeeded */
ret_val = TRUE;
}
break;
}
break;
}
/* check failure */
if (ret_val == FALSE) {
DBG_PRINT("mouse input failed.\n");
}
/* consume vt escape sequence */
if (!peek_flag && !consume_vt_input(hin, input_seq_len2)) {
return FALSE;
}
return ret_val;
}
/* process other vt escape sequence */
if (input_seq_len > 0) {
/* search vt escape sequence input table */
vt_input_table_len = sizeof(vt_input_table) / sizeof(struct vt_input);
for (i = 0; i < vt_input_table_len; i++) {
if (input_seq_len >= vt_input_table[i].seq_len &&
((vt_input_table[i].modifier_index <= 0 &&
!strncmp(vt_input_table[i].seq, input_seq, vt_input_table[i].seq_len)) ||
(!strncmp(vt_input_table[i].seq, input_seq, vt_input_table[i].modifier_index) &&
!strncmp(vt_input_table[i].seq + vt_input_table[i].modifier_index + 1,
input_seq + vt_input_table[i].modifier_index + 1,
vt_input_table[i].seq_len - vt_input_table[i].modifier_index - 1)))) {
/* set key event */
set_key_event(input_rec_ptr,
vt_input_table[i].vk,
vt_input_table[i].vs,
vt_input_table[i].uchar,
ctrl_state | vt_input_table[i].ctrl);
/* consume vt escape sequence */
if (!peek_flag && !consume_vt_input(hin, vt_input_table[i].seq_len)) {
return FALSE;
}
return TRUE;
}
}
}
}
return TRUE;
}
/* display last error message */
void disp_last_err_msg(void)
{
int err_code;
char *err_msg = NULL;
err_code = GetLastError();
if (FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER |
FORMAT_MESSAGE_FROM_SYSTEM |
FORMAT_MESSAGE_IGNORE_INSERTS,
NULL,
err_code,
MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT),
(LPSTR)&err_msg,
0,
NULL)) {
DBG_PRINT("error code=%d : %s\n", err_code, err_msg);
} else {
DBG_PRINT("error code=%d : (no message)\n", err_code);
}
LocalFree(err_msg);
}
/* main function for test */
int main(void)
{
HANDLE hin = GetStdHandle(STD_INPUT_HANDLE);
HANDLE hout = GetStdHandle(STD_OUTPUT_HANDLE);
DWORD con_input_mode_orig;
DWORD con_output_mode_orig;
INPUT_RECORD input_rec;
DWORD read_event_num;
INPUT_RECORD input_rec_peek;
DWORD read_event_num_peek;
#ifdef USE_VT_MOUSE_INPUT
const char *vt_mouse_input_enable_cmd = "\x1b[?1003;1006h";
const char *vt_mouse_input_disable_cmd = "\x1b[?1003;1006l";
DWORD written;
#endif
int input_loop;
int ret_val;
int i;
/* get console mode */
GetConsoleMode(hin, &con_input_mode_orig);
GetConsoleMode(hout, &con_output_mode_orig);
/* set console mode */
#ifdef USE_VT_MOUSE_INPUT
if (!SetConsoleMode(hin, ENABLE_VIRTUAL_TERMINAL_INPUT | ENABLE_WINDOW_INPUT)) {
DBG_PRINT("SetConsoleMode for input failed. (VT escape sequence might not be supported)\n");
return 1;
}
if (!SetConsoleMode(hout, ENABLE_PROCESSED_OUTPUT | ENABLE_VIRTUAL_TERMINAL_PROCESSING)) {
DBG_PRINT("SetConsoleMode for output failed. (VT escape sequence might not be supported)\n");
SetConsoleMode(hin, con_input_mode_orig);
return 1;
}
#else
/* (To set ENABLE_MOUSE_INPUT to on, we must set ENABLE_QUICK_EDIT_MODE to off) */
SetConsoleMode(hin, ENABLE_MOUSE_INPUT | ENABLE_EXTENDED_FLAGS | ENABLE_WINDOW_INPUT);
SetConsoleMode(hout, ENABLE_PROCESSED_OUTPUT);
#endif
#ifdef USE_VT_MOUSE_INPUT
/* enable vt escape sequence of mouse input (sgr-1006) */
WriteConsoleA(hout, vt_mouse_input_enable_cmd, strlen(vt_mouse_input_enable_cmd), &written, NULL);
#endif
/* start-up message */
DBG_PRINT("Please try key and mouse input.\n");
DBG_PRINT("( [q] key to quit )\n");
/* input loop */
input_loop = 1;
ret_val = 0;
while (input_loop) {
/* peek console input */
memset(&input_rec_peek, 0, sizeof(INPUT_RECORD));
if (!PDC_peek_console_input_w(hin, &input_rec_peek, 1, &read_event_num_peek)) {
DBG_PRINT("PDC_peek_console_input_w failed.\n");
disp_last_err_msg();
ret_val = 1;
break;
}
if (read_event_num_peek == 0) {
Sleep(10);
continue;
}
/* read console input */
memset(&input_rec, 0, sizeof(INPUT_RECORD));
if (!PDC_read_console_input_w(hin, &input_rec, 1, &read_event_num)) {
DBG_PRINT("PDC_read_console_input_w failed.\n");
disp_last_err_msg();
ret_val = 1;
break;
}
if (read_event_num == 0) {
DBG_PRINT("PDC_read_console_input_w returned before read.\n");
ret_val = 1;
break;
}
/* check input data */
if (memcmp(&input_rec_peek, &input_rec, sizeof(INPUT_RECORD))) {
DBG_PRINT("read data corruption occurred.\n");
DBG_PRINT(" size=%d\n", (int)sizeof(INPUT_RECORD));
DBG_PRINT(" peek : ");
for (i = 0; i < (int)sizeof(INPUT_RECORD); i++) {
DBG_PRINT("%02x ", *((unsigned char*)&input_rec_peek + i));
}
DBG_PRINT("\n");
DBG_PRINT(" read : ");
for (i = 0; i < (int)sizeof(INPUT_RECORD); i++) {
DBG_PRINT("%02x ", *((unsigned char*)&input_rec + i));
}
DBG_PRINT("\n");
continue;
}
/* process event */
switch (input_rec.EventType) {
case KEY_EVENT:
DBG_PRINT("key event : kdown=%d repeat=%d vkey=0x%x vscan=0x%x uchar=0x%x ctrl=0x%lx\n",
input_rec.Event.KeyEvent.bKeyDown,
input_rec.Event.KeyEvent.wRepeatCount,
input_rec.Event.KeyEvent.wVirtualKeyCode,
input_rec.Event.KeyEvent.wVirtualScanCode,
input_rec.Event.KeyEvent.uChar.UnicodeChar,
input_rec.Event.KeyEvent.dwControlKeyState);
/* process key event */
if (!input_rec.Event.KeyEvent.bKeyDown) {
switch (input_rec.Event.KeyEvent.wVirtualKeyCode) {
/* [q] key to quit */
case 0x51:
input_loop = 0;
break;
/* [l] key to clear screen */
case 0x4c:
system("cls");
break;
}
}
break;
case MOUSE_EVENT:
DBG_PRINT("mouse event : (%d,%d) btn=0x%lx ctrl=0x%lx evt=0x%lx\n",
input_rec.Event.MouseEvent.dwMousePosition.X,
input_rec.Event.MouseEvent.dwMousePosition.Y,
input_rec.Event.MouseEvent.dwButtonState,
input_rec.Event.MouseEvent.dwControlKeyState,
input_rec.Event.MouseEvent.dwEventFlags);
break;
case WINDOW_BUFFER_SIZE_EVENT:
DBG_PRINT("window buffer size event : width=%d height=%d\n",
input_rec.Event.WindowBufferSizeEvent.dwSize.X,
input_rec.Event.WindowBufferSizeEvent.dwSize.Y);
break;
}
}
#ifdef USE_VT_MOUSE_INPUT
/* disable vt escape sequence of mouse input (sgr-1006) */
WriteConsoleA(hout, vt_mouse_input_disable_cmd, strlen(vt_mouse_input_disable_cmd), &written, NULL);
#endif
/* restore console mode */
SetConsoleMode(hin, con_input_mode_orig);
SetConsoleMode(hout, con_output_mode_orig);
return ret_val;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment