#pragma once
class AsyncInput
{
public:
static AsyncInput* GetInstance();
static void Finalize();
static char *Gets(char* buffer, size_t bufferSize);
static void ScanKey();
private:
static AsyncInput* _instance;
AsyncInput();
~AsyncInput();
void ScanKeyImpl();
char* AsyncGets(char* buffer, size_t bufferSize);
HANDLE _hStdin;
DWORD _fdwMode;
uint16_t _writeChar;
uint16_t _readChar;
CHAR _charBuffer[256];
};
#include <Windows.h>
#include <stdint.h>
#include <stdio.h>
//#include "_string.h" // 改行コードの除去とかBackSpace対応とか
#include "AsyncInput.h"
AsyncInput* AsyncInput::_instance = NULL;
AsyncInput::AsyncInput() {
_hStdin = GetStdHandle(STD_INPUT_HANDLE);
GetConsoleMode(_hStdin, &_fdwMode);
SetConsoleMode(_hStdin, ENABLE_WINDOW_INPUT);
_writeChar = 0;
_readChar = 0;
_charBuffer[0] = '\0';
}
AsyncInput::~AsyncInput() {
SetConsoleMode(_hStdin, _fdwMode);
}
AsyncInput* AsyncInput::GetInstance() {
if (_instance != NULL) return _instance;
_instance = new AsyncInput();
return _instance;
}
void AsyncInput::Finalize() {
if (_instance == NULL) return;
delete _instance;
_instance = NULL;
}
void AsyncInput::ScanKey() {
auto instance = GetInstance();
instance->ScanKeyImpl();
}
void AsyncInput::ScanKeyImpl() {
INPUT_RECORD irInBuf[32];
DWORD irRead;
if (PeekConsoleInput(_hStdin, irInBuf, _countof(irInBuf), &irRead) && irRead > 0) {
ReadConsoleInput(_hStdin, irInBuf, _countof(irInBuf), &irRead);
for (int i = 0; i < irRead; ++i) {
if (irInBuf[i].EventType != KEY_EVENT) continue;
auto ascii = irInBuf[i].Event.KeyEvent.uChar.AsciiChar;
auto keyDown = irInBuf[i].Event.KeyEvent.bKeyDown;
if (ascii == 0 || !keyDown) continue;
putchar(ascii);
if (ascii == '\r') putchar('\n');
uint16_t nw = (_writeChar + 1) % _countof(_charBuffer);
if (nw == _readChar) _readChar = (_readChar + 1) % _countof(_charBuffer);
_charBuffer[_writeChar] = ascii;
_writeChar = nw;
}
}
}
char* AsyncInput::Gets(char* line, size_t maxSize) {
auto instance = GetInstance();
instance->ScanKeyImpl();
char* result = instance->AsyncGets(line, maxSize);
if (result == NULL) return NULL;
//_chomp(result); // 改行を除去
//_removebackspace(result); // バックスペースを適用
return result;
}
char* AsyncInput::AsyncGets(char* line, size_t maxSize) {
if (maxSize <= 1) {
return NULL;
}
uint16_t wpos = 0, rpos;
uint8_t c;
uint16_t size = maxSize;
--size; // make room for '\0'
rpos = _readChar;
while (wpos < size) {
if (rpos == _writeChar) return NULL;
c = _charBuffer[rpos];
rpos = (rpos + 1) % _countof(_charBuffer);
if (c != '\r' && c != '\n' && c != '\0') {
line[wpos++] = c;
}
else if (wpos > 0) {
break;
}
}
_readChar = rpos;
line[wpos] = '\0';
return line;
}
このままだとカーソルキーはおろか、バックスペースにも対応していないので注意!
#include <stdio.h>
#include "AsyncInput.h"
void main(){
char buffer[256];
for(;;){
char *input = AsyncInput::Gets(buffer,sizeof(buffer));
if (input == NULL) continue;
printf("%s\r\n",input);
}
}