Um kbhit() para Windows

Num artigo anterior (este aqui) mostrei como codificar um kbhit() para Linux. Ficou faltando a mesma função para Windows.

Algumas pessoas insistem em usar o header conio.h, que existe para o MinGW e o Visual Studio… Se esses são seus alvos para compilação e seu projeto não precisa ser portável, vá em frente, use o header. Mas, saiba que você pode codificar essas funções de forma mais “portável”, juntando as definições dos outros artigos (para Linux) com essas aqui.

No caso do Windows, podemos usar as funções da Console API, que é mais ou menos equivalente à termios, do Linux. Eis as rotinas _kbhit() e _getch():

#include <windows.h>

// Ok... essa função só tem um problema.
// Por causa do loop, a thread consumirá
// muito tempo de CPU...
int _kbhit(void)
{
  HANDLE hConsole;
  INPUT_RECORD ir;
  DWORD n;

  hConsole = GetStdHandle(STD_INPUT_HANDLE);
  while (PeekConsoleInput(hConsole, &ir, 1, &n))
    if (ir.EventType == KEY_EVENT)
      return 1;

  return 0;
}

int _getch(void)
{
  HANDLE hConsole;
  DWORD cm, n;
  char buffer[4];   // Para ter certeza que um caracter
                    // UNICODE cabe aqui, alocamos 4 bytes.

  hConsole = GetStdHandle(STD_INPUT_HANDLE);
  GetConsoleMode(hConsole, &cm);
  SetConsoleMode(hConsole, cm &
             ~(ENABLE_LINE_INPUT | ENABLE_ECHO_INPUT));
  ReadConsole(hConsole, buffer, 1, &n, NULL);
  SetConsoleMode(hConsole, cm);

  // Só preciso de 1 char...
  return buffer[0];
}

Repare como, em _getch() desabilito “LINE INPUT” (mais ou menos como o método “canônico” do termios) e o “ECHO INPUT”. Fiz algo semelhante no getch() e kbhit() lá do Linux…

A função _kbhit() fica um pouco mais simples por causa de PeekConsoleInput, que nos permite obter os eventos de entrada sem retirá-los da fila. Essencialmente, percorremos a fila de eventos à procura de um KEY_INPUT. Se algum for achado, retornamos 1 (true)…

Anúncios