Sposób 1.
<justify> Poniższy przykład zdaje się być idealny. Nie dość, że korzysta wyłącznie z biblioteki standardowej, to jeszcze jest wyjątkowo przenośny (działa na niemal wszystkich nie-windowsowych systemach). Poprawnie zbiera znaki alfanumeryczne i klawisze funkcyjne. Problem pojawia się jedynie, jeśli chodzi o strzałki oraz [backspace] (funkcja ich nie rozróżnia, wciśnięcie dowolnej strzałki da nam na wyjściu tą samą wartość).</justify><justify> Działanie funkcji jest banalne. Polega na zmianie ustawień terminala tak, aby nie wyświetlał, ani nie buforował znaków. Następnie pobiera znak i przywraca poprzednie ustawienia terminala.</justify>#include <stdio.h>
#include <unistd.h>
#ifdef WIN32
#include <conio.h>
#else
#include <termios.h>
int getch (void)
{
int key;
struct termios oldSettings, newSettings; /* stuktury z ustawieniami terminala */
tcgetattr(STDIN_FILENO, &oldSettings); /* pobranie ustawień terminala */
newSettings = oldSettings;
newSettings.c_lflag &= ~(ICANON | ECHO); /* ustawienie odpowiednich flag */
tcsetattr(STDIN_FILENO, TCSANOW, &newSettings); /* zastosowanie ustawień */
key = getchar(); /* pobranie znaku ze standardowego wejścia */
tcsetattr(STDIN_FILENO, TCSANOW, &oldSettings); /* przywrócenie poprzednich ustawień terminala */
return key;
}
#endif
Sposób 2.
<justify> Poniższa interpretacja to rozwinięcie poprzedniej. Nie korzysta ona z funkcji getchar, zamiast tego używając funkcji <font color="gray">kbhit()</span>, która zwraca prawdę, gdy kliknięty zostanie dowolny klawisz. Dzięki temu bez problemu można pobrać wartość numeryczną każdego klawisza. Minusem tego rozwiązania jest to, że trzeba inicjować jej użycie poprzez funkcję <font color="gray">openKeyboard()</span> na początku i <font color="gray">closeKeyboard()</span> na końcu.</justify>#include<stdio.h>
#include<stdlib.h>
#include<termios.h>
#include<unistd.h>
static struct termios oldSettings, newSettings; /* stuktury z ustawieniami terminala */
static int chartest = -1;
void openKeyboard (void);
void closeKeyboard (void);
int kbhit (void);
int getch (void);
int main (int argc, char* argv[])
{
int znak = 0;
openKeyboard();
while ( znak != 'q' )
{
printf("petla\n");
sleep(1);
if ( kbhit() )
{
znak = getch();
printf("wcisnales %c\n", znak);
}
}
closeKeyboard();
return 0;
}
/* ===== otwiera klawiaturę (zmienia ustawienia terminala) ===== */
void openKeyboard (void)
{
/* pobranie ustawień terminala */
tcgetattr(0, &oldSettings);
newSettings = oldSettings;
/* ustawienie odpowiednich flag */
newSettings.c_lflag &= ~ICANON;
newSettings.c_lflag &= ~ECHO;
newSettings.c_lflag &= ~ISIG;
newSettings.c_cc[VMIN] = 1;
newSettings.c_cc[VTIME] = 0;
/* zastosowanie zmian */
tcsetattr(0, TCSANOW, &newSettings);
return;
}
/* ===== zwraca 1 w przypadku kliknięcia dowolnego klawisza ===== */
int kbhit (void)
{
char key;
int nread;
if ( chartest != -1 )
return 1;
newSettings.c_cc[VMIN] = 0;
tcsetattr(0, TCSANOW, &newSettings);
nread = read(0, &key, 1);
newSettings.c_cc[VMIN] = 1;
tcsetattr(0, TCSANOW, &newSettings);
if ( nread == 1 )
{
chartest = key;
return 1;
}
return 0;
}
/* ===== zamyka klawiaturę (przywraca poprzednie ustawienia terminala) ===== */
void closeKeyboard (void)
{
/* przywrócenie poprzednich ustawień terminala */
tcsetattr(0, TCSANOW, &oldSettings);
return;
}
#ifndef __CONIO_H__
int getch (void)
{
char key;
if ( chartest != -1 )
{
key = chartest;
chartest = -1;
return key;
}
read(0, &key, 1);
return key;
}
#endif
<justify>Reasumując, przykładów implementacji tej banalnej, ale jakże przydatnej funkcji jest wiele. To od użytkownika zależy, czy wybierze niestandardową bibliotekę, którą będzie musiał dołączać do projektu, gdy będzie chciał podzielić się źródłem, czy wykorzysta własną implementację, dzięki czemu program zyska na przenośności.</justify>
Zobacz też: