From 876c303e5eccce2e1594c246f9433ca65c0e7778 Mon Sep 17 00:00:00 2001 From: "R. Eric Wheeler" Date: Mon, 1 Mar 2021 09:37:48 -0800 Subject: [PATCH] new function cinPeek(); named from c++ cin.peek() --- CMakeLists.txt | 36 ++++++++++++++--- README.md | 2 + example.c | 13 +++++++ getch.c | 97 ++++++++++++++++++++++++++++++++++++++++------ getch.h | 5 ++- tests/getchTests.c | 84 ++++++++++++++++++++------------------- 6 files changed, 179 insertions(+), 58 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index d545791..58ebcf8 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -4,15 +4,39 @@ project(getch C) set(CMAKE_C_STANDARD 11) set(CMAKE_COLOR_MAKEFILE ON) -add_library(getch SHARED getch.c getch.h) +add_library(libgetch SHARED getch.c getch.h) +add_library(libgetch_static STATIC getch.c getch.h) + add_executable(example example.c ) add_executable(getchTest tests/test.c tests/getchTests.c) -add_test(NAME getchTests - COMMAND getchTest - WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}) -target_link_libraries(getchTest -L./build getch) -target_link_libraries(example -L./build getch) + +add_test(NAME defaultTests + COMMAND "getchTest" + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} + ) + +target_link_libraries(getchTest -L./build libgetch) +target_link_libraries(example -L./build libgetch) + if (ENABLE_TESTS EQUAL 1) enable_testing() endif () +add_custom_target(escapeTest getchTest escapeReturnsTest + COMMAND getchTest specialKeyTest + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} + USES_TERMINAL + ) +set_target_properties(libgetch PROPERTIES PUBLIC_HEADER getch.h) +set_target_properties(libgetch PROPERTIES OUTPUT_NAME getch) +set_target_properties(libgetch_static PROPERTIES OUTPUT_NAME getch_static) + +include(GNUInstallDirs) + +install(TARGETS libgetch libgetch_static + LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} + ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} + PUBLIC_HEADER + DESTINATION ${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_INCLUDEDIR} + ) + diff --git a/README.md b/README.md index 0ae2dca..62e8fd6 100644 --- a/README.md +++ b/README.md @@ -10,6 +10,8 @@ See https://docs.microsoft.com/en-us/cpp/c-runtime-library/reference/getch-getwc Difference is that _getch will read CTRL+C, or any control characters. +There is also an extra function `int cinPeek()` that returns the next character in stdin without removing it. + ### Note Make sure that the user calling the function is in the group "input" diff --git a/example.c b/example.c index b10bd02..fc8667f 100644 --- a/example.c +++ b/example.c @@ -11,4 +11,17 @@ int main() { key = _getch(); printf("Special Key : %d\n", key); } + + do { + key = _getch(); + printf("Key : %d\n", key); + } while(key != 113); + + _ungetch('A'); + + int res = cinPeek(); + int getch = _getch(); + + printf("%c : %c\n\r", res, getch); + } \ No newline at end of file diff --git a/getch.c b/getch.c index a8379fe..78a5e7f 100644 --- a/getch.c +++ b/getch.c @@ -14,13 +14,34 @@ #include #include "getch.h" -#define FKEY(k) ((k) >= KEY_F1 && (k) <= KEY_F10) || (k) == KEY_F12 || (k) == KEY_F11 -#define NOTNUMPAD(k) ((k) >= KEY_HOME && (k) <= KEY_DELETE) - #define EVENT_DEVICE_GLOB "/dev/input/by-path/*-event-kbd" +#define FKEY(k) ((k) >= KEY_F1 && (k) <= KEY_F10) || (k) == KEY_F12 || (k) == KEY_F11 +#define NOTNUMPAD(k) ((k) >= KEY_HOME && (k) <= KEY_DELETE) +#define XOR_SWAP(a,b) do\ + {\ + (a) ^= (b);\ + (b) ^= (a);\ + (a) ^= (b);\ + } while (0) + 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--; + } + } +} + static int discardRead(unsigned int length) { char buffer[length]; @@ -38,7 +59,7 @@ static int discardRead(unsigned int length) return (int)bytesRead; } -static int getEventDevice(const char * device) +static int getEventDevice(char ** device) { glob_t search; @@ -64,7 +85,8 @@ static int getEventDevice(const char * device) for(int i = 0; i #include #include +#include #include #include "../getch.h" +#define XOR_SWAP(a,b) do\ + {\ + (a) ^= (b);\ + (b) ^= (a);\ + (a) ^= (b);\ + } while (0) #define EV_PRESSED 1 #define EV_RELEASED 0 inline static void writeToEventDevice(__u16 code) { + struct libevdev *dev = NULL; glob_t globResult; glob("/dev/input/by-path/*-event-kbd", GLOB_NOSORT, NULL, &globResult); @@ -23,34 +31,45 @@ inline static void writeToEventDevice(__u16 code) exit(EXIT_FAILURE); } - char device[strlen(globResult.gl_pathv[0])]; - strncpy(device, globResult.gl_pathv[0], strlen(globResult.gl_pathv[0]) + 1); + char device[strlen(globResult.gl_pathv[0])+1]; + strcpy(device, globResult.gl_pathv[0]); globfree(&globResult); - struct input_event inputEvent[2]; - int eventDevice = open(device, O_WRONLY); + struct input_event inputEvent[3]; + int eventDevice = open(device, O_WRONLY|O_NONBLOCK); if(eventDevice == -1) { perror("open"); exit(EXIT_FAILURE); } - for(int i=0; i<2;i++) { - gettimeofday(&inputEvent[i].time, NULL); - inputEvent[i].type = EV_KEY; - inputEvent[i].code = code; - inputEvent[i].value = i ? EV_RELEASED : EV_PRESSED; + inputEvent[0].time.tv_usec = 0; + inputEvent[0].time.tv_sec = 0; + inputEvent[0].type = 4; + inputEvent[0].code = 4; + inputEvent[0].value = code; + + inputEvent[1].time.tv_usec = 0; + inputEvent[1].time.tv_sec = 0; + inputEvent[1].type = EV_KEY; + inputEvent[1].code = code; + inputEvent[1].value = EV_PRESSED; + + inputEvent[2].time.tv_usec = 0; + inputEvent[2].time.tv_sec = 0; + inputEvent[2].type = EV_KEY; + inputEvent[2].code = code; + inputEvent[2].value = EV_RELEASED; + + + int res; + + res = write(eventDevice, &inputEvent, sizeof(inputEvent)); + if(res == -1) { + perror("Write"); } - write(eventDevice, &inputEvent, sizeof(inputEvent)); - - - close(eventDevice); - - sync(); - - fflush(NULL); - + close(eventDevice); } inline static void reverseString(char * str) @@ -59,24 +78,12 @@ inline static void reverseString(char * str) { char * end = str + strlen(str) - 1; - // swap the values in the two given variables - // XXX: fails when a and b refer to same memory location -# define XOR_SWAP(a,b) do\ - {\ - (a) ^= (b);\ - (b) ^= (a);\ - (a) ^= (b);\ - } while (0) - - // walk inwards from both ends of the string, - // swapping until we get to the middle while (str < end) { XOR_SWAP(*str, *end); str++; end--; } -# undef XOR_SWAP } } @@ -94,12 +101,12 @@ inline static void writeStringToStdin(char * string) } static char *asciiCodes[3] = { - "\x1bOPP", + "\x1bOP", "\x1b[H", - "\x1bOJ" + "\x1bOQ" }; -static int scanCodes[3] = { KEY_F1, KEY_HOME, KEY_F5 }; +static int scanCodes[3] = { KEY_F1, KEY_HOME, KEY_F2 }; CTEST(getchTests, simpleGetchSetReturn_q) { @@ -113,9 +120,8 @@ CTEST(getchTests, simpleGetchSetReturn_q) CTEST(getchTests, SpecialKey) { - - writeStringToStdin(asciiCodes[0]); writeToEventDevice(scanCodes[0]); + writeStringToStdin(asciiCodes[0]); int key = _getch(); int code = _getch(); @@ -126,10 +132,8 @@ CTEST(getchTests, SpecialKey) CTEST(specialKeyTests, Home) { - + writeToEventDevice(scanCodes[1]); writeStringToStdin(asciiCodes[1]); - writeToEventDevice(KEY_HOME); - int key = _getch(); int code = _getch(); @@ -139,8 +143,10 @@ CTEST(specialKeyTests, Home) CTEST(escapeReturnsTest, Esc) { - ungetc(27, stdin); writeToEventDevice(KEY_ESC); + ungetc(27, stdin); + + int key = _getch(); ASSERT_EQUAL(27, key);