Updated libgetch, now includes cinPeek function

This commit is contained in:
R. Eric Wheeler 2021-02-27 19:10:44 -08:00
parent e06f9e0cc7
commit ba09e1d356
4 changed files with 118 additions and 12 deletions

View File

@ -67,19 +67,32 @@ final class Getch
if (null === self::$ffi) { if (null === self::$ffi) {
$osFamily = PHP_OS_FAMILY; $osFamily = PHP_OS_FAMILY;
if ('Windows' === $osFamily) { if ('Windows' === $osFamily) {
self::$ffi = FFI::cdef(self::DECLARATIONS, self::WINDOWS_LIBRARY); $declarations = self::DECLARATIONS . ' int _kbhit();';
self::$ffi = FFI::cdef($declarations, self::WINDOWS_LIBRARY);
} elseif ('Linux' === $osFamily) { } elseif ('Linux' === $osFamily) {
if (!file_exists($linuxLibrary)) { if (!file_exists($linuxLibrary)) {
throw new RuntimeException(sprintf('Could not find library file %s.', $linuxLibrary)); throw new RuntimeException(sprintf('Could not find library file %s.', $linuxLibrary));
} }
$declarations = self::DECLARATIONS . ' int cinPeek();';
self::$ffi = FFI::cdef(self::DECLARATIONS, $linuxLibrary); self::$ffi = FFI::cdef($declarations, $linuxLibrary);
} else { } else {
throw new RuntimeException(sprintf('Sorry, %s is not supported yet.', $osFamily)); throw new RuntimeException(sprintf('Sorry, %s is not supported yet.', $osFamily));
} }
} }
} }
public function peek(): int
{
if(PHP_OS_FAMILY === 'Windows') {
if($ffi->_kbhit()) {
$result = $ffi->_getch();
$ffi->_ungetch($result);
return $result;
}
return -1;
}
return $ffi->cinPeek();
}
/* public function keyCode(string $device): array /* public function keyCode(string $device): array
{ {

View File

@ -20,6 +20,33 @@
static struct termios oldTermAttributes; static struct termios oldTermAttributes;
inline static void reverseString(char * str)
{
if (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
}
}
static int discardRead(unsigned int length) static int discardRead(unsigned int length)
{ {
char buffer[length]; char buffer[length];
@ -37,7 +64,7 @@ static int discardRead(unsigned int length)
return (int)bytesRead; return (int)bytesRead;
} }
static int getEventDevice(const char * device) static int getEventDevice(char ** device)
{ {
glob_t search; glob_t search;
@ -63,7 +90,8 @@ static int getEventDevice(const char * device)
for(int i = 0; i<search.gl_pathc;i++) { for(int i = 0; i<search.gl_pathc;i++) {
if(access(search.gl_pathv[i], F_OK) == 0) { if(access(search.gl_pathv[i], F_OK) == 0) {
pathLength = strlen(search.gl_pathv[i]) + 1; pathLength = strlen(search.gl_pathv[i]) + 1;
strncpy((char *)device, search.gl_pathv[i], pathLength); *device = (char *)malloc(pathLength);
strcpy(*device, search.gl_pathv[i]);
globfree(&search); globfree(&search);
return 1; return 1;
} }
@ -75,30 +103,38 @@ static int getEventDevice(const char * device)
static unsigned short getScanCode() static unsigned short getScanCode()
{ {
struct input_event inputEvent[3]; struct input_event inputEvent[40];
int eventDevice; int eventDevice;
const char device[FILENAME_MAX]; char *device;
if(getEventDevice(device) == -1) { if(getEventDevice(&device) == -1) {
perror("getEventDevice"); perror("getEventDevice");
free(device);
return KEY_RESERVED; return KEY_RESERVED;
} }
if( ( eventDevice = open(device, O_RDONLY)) == -1 ) { if( ( eventDevice = open(device, O_RDONLY)) == -1 ) {
free(device);
perror("open"); perror("open");
return KEY_RESERVED; return KEY_RESERVED;
}; };
free(device);
if( read(eventDevice, &inputEvent, sizeof(inputEvent)) == -1) { if( read(eventDevice, &inputEvent, sizeof(inputEvent)) == -1) {
close(eventDevice); close(eventDevice);
perror("read");
return KEY_RESERVED; return KEY_RESERVED;
} }
close(eventDevice); close(eventDevice);
for(int i = 0;i<3;i++) { // for(int i = 0;i<39;i++) {
// printf("Type %d, Code %d, Value %d\r\n", inputEvent[i].type, inputEvent[i].code, inputEvent[i].value);
// }
for(int i = 0;i<40;i++) {
//printf("Type %d, Code %d\n", inputEvent[i].type, inputEvent[i].code);
if(inputEvent[i].type == EV_KEY && inputEvent[i].code != KEY_ENTER) { if(inputEvent[i].type == EV_KEY && inputEvent[i].code != KEY_ENTER) {
return inputEvent[i].code; return inputEvent[i].code;
} }
@ -152,7 +188,7 @@ static int readKey(void) {
unsigned short scanCode = getScanCode(); unsigned short scanCode = getScanCode();
if (scanCode == KEY_ESC || scanCode == KEY_RESERVED) { if (scanCode == KEY_ESC ) {
return 27; return 27;
} }
@ -170,19 +206,23 @@ static int readKey(void) {
case KEY_F2: case KEY_F2:
case KEY_F3: case KEY_F3:
case KEY_F4: case KEY_F4:
case KEY_KP1: // END case KEY_KP1: // END
case KEY_KP2: // DOWN case KEY_KP2: // DOWN
case KEY_KP4: // LEFT case KEY_KP4: // LEFT
case KEY_KP6: // RIGHT case KEY_KP6: // RIGHT
case KEY_KP7: // HOME case KEY_KP7: // HOME
case KEY_KP8: // UP case KEY_KP8: // UP
//getchar();
//getchar();
discardBytes = 2; discardBytes = 2;
break; break;
case KEY_KP0: // INSERT case KEY_KP0: // INSERT
case KEY_KPDOT: // DELETE case KEY_KPDOT: // DELETE
case KEY_KP9: // PAGEUP case KEY_KP9: // PAGEUP
case KEY_KP3: // PAGEDOWN case KEY_KP3: // PAGEDOWN
/*getchar();
getchar();
getchar(); */
discardBytes = 3; discardBytes = 3;
break; break;
case KEY_F5: case KEY_F5:
@ -193,11 +233,16 @@ static int readKey(void) {
case KEY_F10: case KEY_F10:
case KEY_F11: case KEY_F11:
case KEY_F12: case KEY_F12:
/* getchar();
getchar();
getchar();
getchar(); */
discardBytes = 4; discardBytes = 4;
break; break;
default: default:
discardBytes = 0; discardBytes = 0;
break;
} }
if (discardBytes != 0) { if (discardBytes != 0) {
@ -228,3 +273,41 @@ int _ungetch(int ch)
{ {
return ungetc(ch, stdin); return ungetc(ch, stdin);
} }
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;
}

Binary file not shown.

View File

@ -70,4 +70,14 @@ class GetchTest extends TestCase
self::assertEquals(0, $g->getch()); self::assertEquals(0, $g->getch());
self::assertEquals(71, $g->getch()); self::assertEquals(71, $g->getch());
} }
public function setPeek()
{
$g = new Getch();
$g->ungetch('q');
$peek = $g->peek();
$getch = $g->getch();
self::assertEquals($peek, $getch);
self::assertEquals(113, $peek);
}
} }