getch_c/getch.c

304 lines
6.3 KiB
C
Raw Permalink Normal View History

2021-02-22 15:20:00 -08:00
/***********************************************************************
* This Source Code Form is subject to the terms of the Mozilla Public *
* License, v. 2.0. If a copy of the MPL was not distributed with this *
* file, You can obtain one at http://mozilla.org/MPL/2.0/. *
***********************************************************************/
2021-02-22 15:17:06 -08:00
#include <stdio.h>
#include <termios.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <linux/input.h>
#include <glob.h>
#include "getch.h"
#define EVENT_DEVICE_GLOB "/dev/input/by-path/*-event-kbd"
2021-02-22 15:20:00 -08:00
#define FKEY(k) ((k) >= KEY_F1 && (k) <= KEY_F10) || (k) == KEY_F12 || (k) == KEY_F11
2021-02-22 15:17:06 -08:00
#define NOTNUMPAD(k) ((k) >= KEY_HOME && (k) <= KEY_DELETE)
#define XOR_SWAP(a,b) do\
{\
(a) ^= (b);\
(b) ^= (a);\
(a) ^= (b);\
} while (0)
2021-02-22 15:17:06 -08:00
static struct termios oldTermAttributes;
inline static void reverseString(char * str)
{
if (str)
{
char * end = str + strlen(str) - 1;
while (str < end)
{
XOR_SWAP(*str, *end);
str++;
end--;
}
}
}
2021-02-24 20:46:16 -08:00
static int discardRead(unsigned int length)
2021-02-22 15:17:06 -08:00
{
char buffer[length];
2021-02-24 20:46:16 -08:00
ssize_t bytesRead;
2021-02-22 15:17:06 -08:00
int flags = fcntl(STDIN_FILENO, F_GETFL);
fcntl(STDIN_FILENO, F_SETFL, flags|O_NONBLOCK);
2021-02-24 20:46:16 -08:00
if( (bytesRead = fread(buffer, sizeof(char), length, stdin)) == -1) {
2021-02-22 15:17:06 -08:00
perror("discardRead");
}
fcntl(STDIN_FILENO, F_SETFL, flags);
2021-02-24 20:46:16 -08:00
return (int)bytesRead;
2021-02-22 15:17:06 -08:00
}
static int getEventDevice(char ** device)
2021-02-22 15:17:06 -08:00
{
glob_t search;
int globResult = glob(
EVENT_DEVICE_GLOB,
GLOB_NOSORT,
NULL,
&search
);
if(0 != globResult) {
globfree(&search);
return -1;
}
if(search.gl_pathc == 0) {
globfree(&search);
return -1;
}
size_t pathLength;
for(int i = 0; i<search.gl_pathc;i++) {
if(access(search.gl_pathv[i], F_OK) == 0) {
pathLength = strlen(search.gl_pathv[i]) + 1;
*device = (char *)malloc(pathLength);
strcpy(*device, search.gl_pathv[i]);
2021-02-22 15:17:06 -08:00
globfree(&search);
return 1;
}
}
globfree(&search);
return -1;
}
2021-02-24 20:46:16 -08:00
static unsigned short getScanCode()
2021-02-22 15:17:06 -08:00
{
struct input_event inputEvent[5];
2021-02-24 20:46:16 -08:00
int eventDevice;
2021-02-22 15:17:06 -08:00
char *device;
if(getEventDevice(&device) == -1) {
2021-02-24 20:46:16 -08:00
perror("getEventDevice");
free(device);
2021-02-22 15:17:06 -08:00
return KEY_RESERVED;
}
2021-02-24 20:46:16 -08:00
if( ( eventDevice = open(device, O_RDONLY)) == -1 ) {
free(device);
2021-02-24 20:46:16 -08:00
perror("open");
2021-02-22 15:17:06 -08:00
return KEY_RESERVED;
};
free(device);
2021-02-24 20:46:16 -08:00
if( read(eventDevice, &inputEvent, sizeof(inputEvent)) == -1) {
close(eventDevice);
perror("read");
2021-02-22 15:17:06 -08:00
return KEY_RESERVED;
}
2021-02-24 20:46:16 -08:00
close(eventDevice);
2021-02-22 15:17:06 -08:00
for(int i = 0;i<5;i++) {
2021-02-24 20:46:16 -08:00
if(inputEvent[i].type == EV_KEY && inputEvent[i].code != KEY_ENTER) {
2021-02-22 15:17:06 -08:00
return inputEvent[i].code;
}
}
return KEY_RESERVED;
}
inline static void pushStdin(int c) {
ungetc(c, stdin);
}
2021-02-24 20:46:16 -08:00
static void setNormalMode(void)
2021-02-22 15:17:06 -08:00
{
tcsetattr(STDIN_FILENO, TCSANOW, &oldTermAttributes);
}
2021-02-24 20:46:16 -08:00
static void setRawMode(void)
2021-02-22 15:17:06 -08:00
{
tcgetattr(STDIN_FILENO, &oldTermAttributes);
struct termios raw = oldTermAttributes;
cfmakeraw(&raw);
tcsetattr(STDIN_FILENO, TCSANOW, &raw);
}
2021-02-24 20:46:16 -08:00
static unsigned short resolveScanCode(unsigned short key)
2021-02-22 15:17:06 -08:00
{
switch(key) {
case KEY_DOWN: return KEY_KP2;
case KEY_LEFT: return KEY_KP4;
case KEY_RIGHT: return KEY_KP6;
case KEY_UP: return KEY_KP8;
case KEY_HOME: return KEY_KP7;
case KEY_END: return KEY_KP1;
case KEY_INSERT: return KEY_KP0;
case KEY_DELETE: return KEY_KPDOT;
case KEY_PAGEUP: return KEY_KP9;
case KEY_PAGEDOWN: return KEY_KP3;
default: return key;
};
}
2021-02-24 20:46:16 -08:00
static int readKey(void) {
2021-02-22 15:17:06 -08:00
int key = getchar();
if (key == 27) {
2021-02-24 20:46:16 -08:00
unsigned short scanCode = getScanCode();
2021-02-22 15:17:06 -08:00
if (scanCode == KEY_ESC ) {
2021-02-22 15:17:06 -08:00
return 27;
}
int returnResult = 0;
if (NOTNUMPAD(scanCode)) {
scanCode = resolveScanCode(scanCode);
returnResult = 224;
}
u_short discardBytes;
switch (scanCode) {
case KEY_F1:
case KEY_F2:
case KEY_F3:
case KEY_F4:
case KEY_KP1: // END
case KEY_KP2: // DOWN
case KEY_KP4: // LEFT
case KEY_KP6: // RIGHT
case KEY_KP7: // HOME
case KEY_KP8: // UP
discardBytes = 2;
break;
case KEY_KP0: // INSERT
case KEY_KPDOT: // DELETE
case KEY_KP9: // PAGEUP
case KEY_KP3: // PAGEDOWN
discardBytes = 3;
break;
case KEY_F5:
case KEY_F6:
case KEY_F7:
case KEY_F8:
case KEY_F9:
case KEY_F10:
case KEY_F11:
case KEY_F12:
discardBytes = 4;
break;
default:
discardBytes = 0;
break;
2021-02-22 15:17:06 -08:00
}
if (discardBytes != 0) {
discardRead(discardBytes);
}
pushStdin(scanCode);
2021-02-24 20:46:16 -08:00
2021-02-22 15:17:06 -08:00
return returnResult;
}
return key;
}
int _getch(void) {
atexit(setNormalMode);
setRawMode();
int key = readKey();
setNormalMode();
return key;
}
int getch(void)
{
return _getch();
}
2021-02-22 15:17:06 -08:00
int _ungetch(int ch)
{
return ungetc(ch, stdin);
}
int ungetch(int ch)
{
return _ungetch(ch);
}
int *cinPeekCount(ushort count)
{
char buffer[count];
int flags = fcntl(STDIN_FILENO, F_GETFL);
fcntl(STDIN_FILENO, F_SETFL, flags|O_NONBLOCK);
size_t byteCount = fread(&buffer, sizeof(char), count, stdin);
fcntl(STDIN_FILENO, F_SETFL, flags);
int *res = (int*)malloc(byteCount);
for(int i=0;i<byteCount;i++)
{
res[i] = (int)buffer[i];
}
reverseString(buffer);
for(int i=0;i<byteCount;i++) {
pushStdin(buffer[i]);
}
return res;
}
int cinPeek()
{
int flags = fcntl(STDIN_FILENO, F_GETFL);
fcntl(STDIN_FILENO, F_SETFL, flags|O_NONBLOCK);
int result = fgetc(stdin);
fcntl(STDIN_FILENO, F_SETFL, flags);
ungetc(result, stdin);
return result;
2021-02-22 15:17:06 -08:00
}