Update master
This commit is contained in:
commit
24e53cd2cc
|
@ -18,7 +18,6 @@ before_script:
|
||||||
- php composer.phar install
|
- php composer.phar install
|
||||||
|
|
||||||
# Run our tests
|
# Run our tests
|
||||||
# If Xdebug was installed you can generate a coverage report and see code coverage metrics.
|
|
||||||
test:7.4:
|
test:7.4:
|
||||||
only:
|
only:
|
||||||
- 1.x
|
- 1.x
|
||||||
|
@ -35,3 +34,11 @@ test:8.0:
|
||||||
image: php:8.0
|
image: php:8.0
|
||||||
script:
|
script:
|
||||||
- vendor/bin/phpunit --configuration phpunit.xml --coverage-text --colors=never
|
- vendor/bin/phpunit --configuration phpunit.xml --coverage-text --colors=never
|
||||||
|
test:8.1:
|
||||||
|
only:
|
||||||
|
- 1.x
|
||||||
|
tags:
|
||||||
|
- default
|
||||||
|
image: php:8.1
|
||||||
|
script:
|
||||||
|
- vendor/bin/phpunit --configuration phpunit.xml --coverage-text --colors=never
|
||||||
|
|
|
@ -2,15 +2,12 @@
|
||||||
|
|
||||||
This simply uses the FFI extension to enable _getch and _ungetch in Windows and linux.
|
This simply uses the FFI extension to enable _getch and _ungetch in Windows and linux.
|
||||||
|
|
||||||
[![pipeline status](https://repos.bgemi.net/sikofitt/getch/badges/1.x/pipeline.svg)](https://repos.bgemi.net/sikofitt/getch/-/commits/1.x)
|
|
||||||
[![coverage report](https://repos.bgemi.net/sikofitt/getch/badges/1.x/coverage.svg)](https://repos.bgemi.net/sikofitt/getch/-/commits/1.x)
|
|
||||||
|
|
||||||
```shell script
|
```shell script
|
||||||
$ composer require sikofitt/getch:dev-master
|
$ composer require olivebbs/getch
|
||||||
```
|
```
|
||||||
|
|
||||||
```php
|
```php
|
||||||
use Sikofitt\Console\Getch;
|
use Olive\Console\Getch;
|
||||||
$g = new Getch($linuxLibrary = null); // can also be a library that implements a function called _getch;
|
$g = new Getch($linuxLibrary = null); // can also be a library that implements a function called _getch;
|
||||||
// by default uses the bundled Resources/libgetch.so
|
// by default uses the bundled Resources/libgetch.so
|
||||||
// on windows uses the built in _getch function.
|
// on windows uses the built in _getch function.
|
||||||
|
@ -45,7 +42,7 @@ Note that if you want to put a word into the STDIN stack, you need to do it in r
|
||||||
There are also helper functions called getch() and ungetch();
|
There are also helper functions called getch() and ungetch();
|
||||||
|
|
||||||
```php
|
```php
|
||||||
use function Sikofitt\Console\getch;
|
use function Olive\Console\getch;
|
||||||
$ord = getch($linuxLibrary = null);
|
$ord = getch($linuxLibrary = null);
|
||||||
print \chr($ord);
|
print \chr($ord);
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,8 @@
|
||||||
{
|
{
|
||||||
"name": "sikofitt/getch",
|
"name": "olivebbs/getch",
|
||||||
"description": "Implements _getch and _ungetch for windows and linux using ffi",
|
"description": "Implements _getch and _ungetch for windows and linux using ffi",
|
||||||
"type": "library",
|
"type": "library",
|
||||||
|
"keywords": ["getch", "windows", "conio", "linux", "console", "conio.h", "hotkey", "termios"],
|
||||||
"require": {
|
"require": {
|
||||||
"php": "^8.2",
|
"php": "^8.2",
|
||||||
"ext-ffi": "*"
|
"ext-ffi": "*"
|
||||||
|
@ -11,7 +12,7 @@
|
||||||
},
|
},
|
||||||
"autoload": {
|
"autoload": {
|
||||||
"psr-4": {
|
"psr-4": {
|
||||||
"Sikofitt\\Console\\": "src/Console/"
|
"Olive\\Console\\": "src/Console/"
|
||||||
},
|
},
|
||||||
"files": [
|
"files": [
|
||||||
"functions.php"
|
"functions.php"
|
||||||
|
@ -19,7 +20,7 @@
|
||||||
},
|
},
|
||||||
"autoload-dev": {
|
"autoload-dev": {
|
||||||
"psr-4": {
|
"psr-4": {
|
||||||
"Sikofitt\\Tests\\Console\\": "tests/"
|
"Olive\\Tests\\Console\\": "tests/"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"license": "MPL-2.0",
|
"license": "MPL-2.0",
|
||||||
|
@ -28,5 +29,8 @@
|
||||||
"name": "R. Eric Wheeler",
|
"name": "R. Eric Wheeler",
|
||||||
"email": "sikofitt@gmail.com"
|
"email": "sikofitt@gmail.com"
|
||||||
}
|
}
|
||||||
]
|
],
|
||||||
|
"conflict": {
|
||||||
|
"sikofitt/getch": "*"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -12,7 +12,7 @@ declare(strict_types=1);
|
||||||
* You can obtain one at https://mozilla.org/MPL/2.0/.
|
* You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
use Sikofitt\Console\Getch;
|
use Olive\Console\Getch;
|
||||||
|
|
||||||
if (!function_exists('getch')) {
|
if (!function_exists('getch')) {
|
||||||
function getch(?string $linuxLibrary = null): int
|
function getch(?string $linuxLibrary = null): int
|
||||||
|
|
|
@ -1,115 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
declare(strict_types=1);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Copyright (c) 2020-2024 https://sikofitt.com sikofitt@gmail.com
|
|
||||||
*
|
|
||||||
* 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 https://mozilla.org/MPL/2.0/.
|
|
||||||
*/
|
|
||||||
|
|
||||||
namespace Sikofitt\Console;
|
|
||||||
|
|
||||||
final class Getch
|
|
||||||
{
|
|
||||||
// Special key codes
|
|
||||||
// Extended scan code used to indicate special keyboard functions
|
|
||||||
public const KEY_RESERVED = 0;
|
|
||||||
public const KEY_E0 = 0;
|
|
||||||
public const KEY_E1 = 224;
|
|
||||||
|
|
||||||
// Supported scan codes.
|
|
||||||
public const KEY_F1 = 59;
|
|
||||||
public const KEY_F2 = 60;
|
|
||||||
public const KEY_F3 = 61;
|
|
||||||
public const KEY_F4 = 62;
|
|
||||||
public const KEY_F5 = 63;
|
|
||||||
public const KEY_F6 = 64;
|
|
||||||
public const KEY_F7 = 65;
|
|
||||||
public const KEY_F8 = 66;
|
|
||||||
public const KEY_F9 = 67;
|
|
||||||
public const KEY_F10 = 68;
|
|
||||||
public const KEY_F11 = 87;
|
|
||||||
public const KEY_F12 = 88;
|
|
||||||
public const KEY_UP = 72;
|
|
||||||
public const KEY_LEFT = 75;
|
|
||||||
public const KEY_RIGHT = 77;
|
|
||||||
public const KEY_DOWN = 80;
|
|
||||||
public const KEY_DELETE = 83;
|
|
||||||
public const KEY_HOME = 71;
|
|
||||||
public const KEY_PAGEUP = 73;
|
|
||||||
public const KEY_END = 79;
|
|
||||||
public const KEY_PAGEDOWN = 81;
|
|
||||||
public const KEY_INSERT = 82;
|
|
||||||
|
|
||||||
private const LINUX_LIBRARY = __DIR__.'/Resources/libgetch.so';
|
|
||||||
private const WINDOWS_LIBRARY = 'ucrtbase.dll';
|
|
||||||
private const DECLARATIONS = <<<DECLARATIONS
|
|
||||||
int _getch();
|
|
||||||
int _ungetch(int c);
|
|
||||||
DECLARATIONS;
|
|
||||||
|
|
||||||
private static ?\FFI $ffi = null;
|
|
||||||
|
|
||||||
public static function resetFFI(): void
|
|
||||||
{
|
|
||||||
self::$ffi = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function __construct(?string $linuxLibrary = null)
|
|
||||||
{
|
|
||||||
if (null === $linuxLibrary) {
|
|
||||||
$linuxLibrary = self::LINUX_LIBRARY;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (null === self::$ffi) {
|
|
||||||
$osFamily = PHP_OS_FAMILY;
|
|
||||||
if ('Windows' === $osFamily) {
|
|
||||||
$declarations = self::DECLARATIONS.' int _kbhit();';
|
|
||||||
self::$ffi = \FFI::cdef($declarations, self::WINDOWS_LIBRARY);
|
|
||||||
} elseif ('Linux' === $osFamily) {
|
|
||||||
if (!file_exists($linuxLibrary)) {
|
|
||||||
throw new \RuntimeException(sprintf('Could not find library file %s.', $linuxLibrary));
|
|
||||||
}
|
|
||||||
$declarations = self::DECLARATIONS.' int cinPeek();';
|
|
||||||
self::$ffi = \FFI::cdef($declarations, $linuxLibrary);
|
|
||||||
} else {
|
|
||||||
throw new \RuntimeException(sprintf('Sorry, %s is not supported yet.', $osFamily));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public function peek(): int
|
|
||||||
{
|
|
||||||
if (PHP_OS_FAMILY === 'Windows') {
|
|
||||||
if (self::$ffi->_kbhit()) {
|
|
||||||
$result = self::$ffi->_getch();
|
|
||||||
self::$ffi->_ungetch($result);
|
|
||||||
|
|
||||||
return $result;
|
|
||||||
}
|
|
||||||
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
return self::$ffi->cinPeek();
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getch(): int
|
|
||||||
{
|
|
||||||
return self::$ffi->_getch();
|
|
||||||
}
|
|
||||||
|
|
||||||
public function ungetch(string|int $char): int
|
|
||||||
{
|
|
||||||
if (is_string($char)) {
|
|
||||||
$char = ord($char[0]);
|
|
||||||
}
|
|
||||||
|
|
||||||
return self::$ffi->_ungetch($char);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,95 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Copyright (c) 2020-2024 https://sikofitt.com sikofitt@gmail.com
|
|
||||||
*
|
|
||||||
* 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 https://mozilla.org/MPL/2.0/.
|
|
||||||
*/
|
|
||||||
|
|
||||||
namespace Sikofitt\Tests\Console\Getch;
|
|
||||||
|
|
||||||
use PHPUnit\Framework\TestCase;
|
|
||||||
use Sikofitt\Console\Getch;
|
|
||||||
|
|
||||||
class GetchTest extends TestCase
|
|
||||||
{
|
|
||||||
private \FFI $ffi;
|
|
||||||
private const HOME_KEY = "\x1b[H";
|
|
||||||
|
|
||||||
public function setUp(): void
|
|
||||||
{
|
|
||||||
$this->ffi = \FFI::load(__DIR__.'/../test.h');
|
|
||||||
$file = $this->ffi->stdin;
|
|
||||||
$stdin = $this->ffi->fopen('/dev/stdin', 'a+');
|
|
||||||
|
|
||||||
foreach (range('D', 'A') as $character) {
|
|
||||||
$this->ffi->ungetc(ord($character), $file);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @preserveGlobalState disabled
|
|
||||||
*
|
|
||||||
* @backupStaticAttributes false
|
|
||||||
*
|
|
||||||
* @backupGlobals false
|
|
||||||
*/
|
|
||||||
public function testFailureOnInvalidLibrary()
|
|
||||||
{
|
|
||||||
Getch::resetFFI();
|
|
||||||
$this->expectException(\RuntimeException::class);
|
|
||||||
\getch(__DIR__.'/library.so');
|
|
||||||
}
|
|
||||||
|
|
||||||
public function testGetchClass()
|
|
||||||
{
|
|
||||||
$getch = new Getch();
|
|
||||||
foreach (range('A', 'D') as $character) {
|
|
||||||
self::assertSame(\ord($character), $getch->getch());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public function testGetchFunction()
|
|
||||||
{
|
|
||||||
foreach (range('A', 'D') as $character) {
|
|
||||||
self::assertSame(\ord($character), getch());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public function testUnsupportedOS()
|
|
||||||
{
|
|
||||||
if (PHP_OS_FAMILY !== 'Linux' || PHP_OS_FAMILY !== 'Windows') {
|
|
||||||
self::markTestSkipped('This test only applies to non Linux or Windows systems.');
|
|
||||||
}
|
|
||||||
$this->expectException(\RuntimeException::class);
|
|
||||||
\getch();
|
|
||||||
}
|
|
||||||
|
|
||||||
public function testHomeKey()
|
|
||||||
{
|
|
||||||
self::markTestSkipped('This seems impossible to test, since it relies on someone actually pressing keys on the keyboard.');
|
|
||||||
|
|
||||||
$stdin = $this->ffi->stdin;
|
|
||||||
|
|
||||||
foreach (str_split(strrev(self::HOME_KEY)) as $character) {
|
|
||||||
$this->ffi->ungetc(ord($character), $stdin);
|
|
||||||
}
|
|
||||||
$g = new Getch();
|
|
||||||
self::assertEquals(0, $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);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,57 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Copyright (c) 2020-2024 https://sikofitt.com sikofitt@gmail.com
|
|
||||||
*
|
|
||||||
* 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 https://mozilla.org/MPL/2.0/.
|
|
||||||
*/
|
|
||||||
|
|
||||||
namespace Sikofitt\Tests\Console\Ungetch;
|
|
||||||
|
|
||||||
use PHPUnit\Framework\TestCase;
|
|
||||||
use Sikofitt\Console\Getch;
|
|
||||||
|
|
||||||
class UngetchTest extends TestCase
|
|
||||||
{
|
|
||||||
public function setUp(): void
|
|
||||||
{
|
|
||||||
parent::setUp(); // TODO: Change the autogenerated stub
|
|
||||||
}
|
|
||||||
|
|
||||||
public function testUngetch()
|
|
||||||
{
|
|
||||||
$g = new Getch();
|
|
||||||
$res = $g->ungetch('A');
|
|
||||||
self::assertSame(65, $res);
|
|
||||||
$res = $g->getch();
|
|
||||||
self::assertSame(65, $res);
|
|
||||||
$res = ungetch(65);
|
|
||||||
self::assertSame(65, $res);
|
|
||||||
$res = $g->getch();
|
|
||||||
self::assertSame(65, $res);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function testTypeError()
|
|
||||||
{
|
|
||||||
$g = new Getch();
|
|
||||||
$this->expectException(\TypeError::class);
|
|
||||||
$g->ungetch(new \stdClass());
|
|
||||||
}
|
|
||||||
|
|
||||||
public function testForFun()
|
|
||||||
{
|
|
||||||
foreach (\str_split(\strrev('Hello World!')) as $char) {
|
|
||||||
ungetch($char);
|
|
||||||
}
|
|
||||||
$result = '';
|
|
||||||
do {
|
|
||||||
$ord = getch();
|
|
||||||
$result .= \chr($ord);
|
|
||||||
} while ($ord !== ord('!'));
|
|
||||||
self::assertSame('Hello World!', $result);
|
|
||||||
}
|
|
||||||
}
|
|
Loading…
Reference in New Issue