Merge 1.x into master #1
|
@ -377,16 +377,16 @@
|
|||
},
|
||||
{
|
||||
"name": "friendsofphp/php-cs-fixer",
|
||||
"version": "v2.18.1",
|
||||
"version": "v2.18.2",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/FriendsOfPHP/PHP-CS-Fixer.git",
|
||||
"reference": "c68ff6231adb276857761e43b7ed082f164dce0b"
|
||||
"reference": "18f8c9d184ba777380794a389fabc179896ba913"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/FriendsOfPHP/PHP-CS-Fixer/zipball/c68ff6231adb276857761e43b7ed082f164dce0b",
|
||||
"reference": "c68ff6231adb276857761e43b7ed082f164dce0b",
|
||||
"url": "https://api.github.com/repos/FriendsOfPHP/PHP-CS-Fixer/zipball/18f8c9d184ba777380794a389fabc179896ba913",
|
||||
"reference": "18f8c9d184ba777380794a389fabc179896ba913",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
|
@ -468,7 +468,7 @@
|
|||
"description": "A tool to automatically fix PHP code style",
|
||||
"support": {
|
||||
"issues": "https://github.com/FriendsOfPHP/PHP-CS-Fixer/issues",
|
||||
"source": "https://github.com/FriendsOfPHP/PHP-CS-Fixer/tree/v2.18.1"
|
||||
"source": "https://github.com/FriendsOfPHP/PHP-CS-Fixer/tree/v2.18.2"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
|
@ -476,7 +476,7 @@
|
|||
"type": "github"
|
||||
}
|
||||
],
|
||||
"time": "2021-01-21T18:50:42+00:00"
|
||||
"time": "2021-01-26T00:22:21+00:00"
|
||||
},
|
||||
{
|
||||
"name": "jetbrains/phpstorm-stubs",
|
||||
|
@ -484,12 +484,12 @@
|
|||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/JetBrains/phpstorm-stubs.git",
|
||||
"reference": "44640f75da5865d1c3b0e433cc72ee4cdc677926"
|
||||
"reference": "b8cf707c050f775cdb7693afa6099bd227b383f4"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/JetBrains/phpstorm-stubs/zipball/44640f75da5865d1c3b0e433cc72ee4cdc677926",
|
||||
"reference": "44640f75da5865d1c3b0e433cc72ee4cdc677926",
|
||||
"url": "https://api.github.com/repos/JetBrains/phpstorm-stubs/zipball/b8cf707c050f775cdb7693afa6099bd227b383f4",
|
||||
"reference": "b8cf707c050f775cdb7693afa6099bd227b383f4",
|
||||
"shasum": ""
|
||||
},
|
||||
"require-dev": {
|
||||
|
@ -524,7 +524,7 @@
|
|||
"support": {
|
||||
"source": "https://github.com/JetBrains/phpstorm-stubs/tree/master"
|
||||
},
|
||||
"time": "2021-01-25T16:29:22+00:00"
|
||||
"time": "2021-02-15T11:11:55+00:00"
|
||||
},
|
||||
{
|
||||
"name": "myclabs/deep-copy",
|
||||
|
@ -1351,16 +1351,16 @@
|
|||
},
|
||||
{
|
||||
"name": "phpunit/phpunit",
|
||||
"version": "9.5.1",
|
||||
"version": "9.5.2",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/sebastianbergmann/phpunit.git",
|
||||
"reference": "e7bdf4085de85a825f4424eae52c99a1cec2f360"
|
||||
"reference": "f661659747f2f87f9e72095bb207bceb0f151cb4"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/e7bdf4085de85a825f4424eae52c99a1cec2f360",
|
||||
"reference": "e7bdf4085de85a825f4424eae52c99a1cec2f360",
|
||||
"url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/f661659747f2f87f9e72095bb207bceb0f151cb4",
|
||||
"reference": "f661659747f2f87f9e72095bb207bceb0f151cb4",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
|
@ -1438,7 +1438,7 @@
|
|||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/sebastianbergmann/phpunit/issues",
|
||||
"source": "https://github.com/sebastianbergmann/phpunit/tree/9.5.1"
|
||||
"source": "https://github.com/sebastianbergmann/phpunit/tree/9.5.2"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
|
@ -1450,7 +1450,7 @@
|
|||
"type": "github"
|
||||
}
|
||||
],
|
||||
"time": "2021-01-17T07:42:25+00:00"
|
||||
"time": "2021-02-02T14:45:58+00:00"
|
||||
},
|
||||
{
|
||||
"name": "psr/container",
|
||||
|
@ -2571,16 +2571,16 @@
|
|||
},
|
||||
{
|
||||
"name": "symfony/console",
|
||||
"version": "v5.2.1",
|
||||
"version": "v5.2.3",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/console.git",
|
||||
"reference": "47c02526c532fb381374dab26df05e7313978976"
|
||||
"reference": "89d4b176d12a2946a1ae4e34906a025b7b6b135a"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/console/zipball/47c02526c532fb381374dab26df05e7313978976",
|
||||
"reference": "47c02526c532fb381374dab26df05e7313978976",
|
||||
"url": "https://api.github.com/repos/symfony/console/zipball/89d4b176d12a2946a1ae4e34906a025b7b6b135a",
|
||||
"reference": "89d4b176d12a2946a1ae4e34906a025b7b6b135a",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
|
@ -2639,7 +2639,7 @@
|
|||
"homepage": "https://symfony.com/contributors"
|
||||
}
|
||||
],
|
||||
"description": "Symfony Console Component",
|
||||
"description": "Eases the creation of beautiful and testable command line interfaces",
|
||||
"homepage": "https://symfony.com",
|
||||
"keywords": [
|
||||
"cli",
|
||||
|
@ -2648,7 +2648,7 @@
|
|||
"terminal"
|
||||
],
|
||||
"support": {
|
||||
"source": "https://github.com/symfony/console/tree/v5.2.1"
|
||||
"source": "https://github.com/symfony/console/tree/v5.2.3"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
|
@ -2664,7 +2664,7 @@
|
|||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2020-12-18T08:03:05+00:00"
|
||||
"time": "2021-01-28T22:06:19+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/deprecation-contracts",
|
||||
|
@ -2735,16 +2735,16 @@
|
|||
},
|
||||
{
|
||||
"name": "symfony/event-dispatcher",
|
||||
"version": "v5.2.1",
|
||||
"version": "v5.2.3",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/event-dispatcher.git",
|
||||
"reference": "1c93f7a1dff592c252574c79a8635a8a80856042"
|
||||
"reference": "4f9760f8074978ad82e2ce854dff79a71fe45367"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/1c93f7a1dff592c252574c79a8635a8a80856042",
|
||||
"reference": "1c93f7a1dff592c252574c79a8635a8a80856042",
|
||||
"url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/4f9760f8074978ad82e2ce854dff79a71fe45367",
|
||||
"reference": "4f9760f8074978ad82e2ce854dff79a71fe45367",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
|
@ -2797,10 +2797,10 @@
|
|||
"homepage": "https://symfony.com/contributors"
|
||||
}
|
||||
],
|
||||
"description": "Symfony EventDispatcher Component",
|
||||
"description": "Provides tools that allow your application components to communicate with each other by dispatching events and listening to them",
|
||||
"homepage": "https://symfony.com",
|
||||
"support": {
|
||||
"source": "https://github.com/symfony/event-dispatcher/tree/v5.2.1"
|
||||
"source": "https://github.com/symfony/event-dispatcher/tree/v5.2.3"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
|
@ -2816,7 +2816,7 @@
|
|||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2020-12-18T08:03:05+00:00"
|
||||
"time": "2021-01-27T10:36:42+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/event-dispatcher-contracts",
|
||||
|
@ -2899,16 +2899,16 @@
|
|||
},
|
||||
{
|
||||
"name": "symfony/filesystem",
|
||||
"version": "v5.2.1",
|
||||
"version": "v5.2.3",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/filesystem.git",
|
||||
"reference": "fa8f8cab6b65e2d99a118e082935344c5ba8c60d"
|
||||
"reference": "262d033b57c73e8b59cd6e68a45c528318b15038"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/filesystem/zipball/fa8f8cab6b65e2d99a118e082935344c5ba8c60d",
|
||||
"reference": "fa8f8cab6b65e2d99a118e082935344c5ba8c60d",
|
||||
"url": "https://api.github.com/repos/symfony/filesystem/zipball/262d033b57c73e8b59cd6e68a45c528318b15038",
|
||||
"reference": "262d033b57c73e8b59cd6e68a45c528318b15038",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
|
@ -2938,10 +2938,10 @@
|
|||
"homepage": "https://symfony.com/contributors"
|
||||
}
|
||||
],
|
||||
"description": "Symfony Filesystem Component",
|
||||
"description": "Provides basic utilities for the filesystem",
|
||||
"homepage": "https://symfony.com",
|
||||
"support": {
|
||||
"source": "https://github.com/symfony/filesystem/tree/v5.2.1"
|
||||
"source": "https://github.com/symfony/filesystem/tree/v5.2.3"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
|
@ -2957,20 +2957,20 @@
|
|||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2020-11-30T17:05:38+00:00"
|
||||
"time": "2021-01-27T10:01:46+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/finder",
|
||||
"version": "v5.2.1",
|
||||
"version": "v5.2.3",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/finder.git",
|
||||
"reference": "0b9231a5922fd7287ba5b411893c0ecd2733e5ba"
|
||||
"reference": "4adc8d172d602008c204c2e16956f99257248e03"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/finder/zipball/0b9231a5922fd7287ba5b411893c0ecd2733e5ba",
|
||||
"reference": "0b9231a5922fd7287ba5b411893c0ecd2733e5ba",
|
||||
"url": "https://api.github.com/repos/symfony/finder/zipball/4adc8d172d602008c204c2e16956f99257248e03",
|
||||
"reference": "4adc8d172d602008c204c2e16956f99257248e03",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
|
@ -2999,10 +2999,10 @@
|
|||
"homepage": "https://symfony.com/contributors"
|
||||
}
|
||||
],
|
||||
"description": "Symfony Finder Component",
|
||||
"description": "Finds files and directories via an intuitive fluent interface",
|
||||
"homepage": "https://symfony.com",
|
||||
"support": {
|
||||
"source": "https://github.com/symfony/finder/tree/v5.2.1"
|
||||
"source": "https://github.com/symfony/finder/tree/v5.2.3"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
|
@ -3018,20 +3018,20 @@
|
|||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2020-12-08T17:02:38+00:00"
|
||||
"time": "2021-01-28T22:06:19+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/options-resolver",
|
||||
"version": "v5.2.1",
|
||||
"version": "v5.2.3",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/options-resolver.git",
|
||||
"reference": "87a2a4a766244e796dd9cb9d6f58c123358cd986"
|
||||
"reference": "5d0f633f9bbfcf7ec642a2b5037268e61b0a62ce"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/options-resolver/zipball/87a2a4a766244e796dd9cb9d6f58c123358cd986",
|
||||
"reference": "87a2a4a766244e796dd9cb9d6f58c123358cd986",
|
||||
"url": "https://api.github.com/repos/symfony/options-resolver/zipball/5d0f633f9bbfcf7ec642a2b5037268e61b0a62ce",
|
||||
"reference": "5d0f633f9bbfcf7ec642a2b5037268e61b0a62ce",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
|
@ -3063,7 +3063,7 @@
|
|||
"homepage": "https://symfony.com/contributors"
|
||||
}
|
||||
],
|
||||
"description": "Symfony OptionsResolver Component",
|
||||
"description": "Provides an improved replacement for the array_replace PHP function",
|
||||
"homepage": "https://symfony.com",
|
||||
"keywords": [
|
||||
"config",
|
||||
|
@ -3071,7 +3071,7 @@
|
|||
"options"
|
||||
],
|
||||
"support": {
|
||||
"source": "https://github.com/symfony/options-resolver/tree/v5.2.1"
|
||||
"source": "https://github.com/symfony/options-resolver/tree/v5.2.3"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
|
@ -3087,7 +3087,7 @@
|
|||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2020-10-24T12:08:07+00:00"
|
||||
"time": "2021-01-27T12:56:27+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/polyfill-ctype",
|
||||
|
@ -3721,16 +3721,16 @@
|
|||
},
|
||||
{
|
||||
"name": "symfony/process",
|
||||
"version": "v5.2.1",
|
||||
"version": "v5.2.3",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/process.git",
|
||||
"reference": "bd8815b8b6705298beaa384f04fabd459c10bedd"
|
||||
"reference": "313a38f09c77fbcdc1d223e57d368cea76a2fd2f"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/process/zipball/bd8815b8b6705298beaa384f04fabd459c10bedd",
|
||||
"reference": "bd8815b8b6705298beaa384f04fabd459c10bedd",
|
||||
"url": "https://api.github.com/repos/symfony/process/zipball/313a38f09c77fbcdc1d223e57d368cea76a2fd2f",
|
||||
"reference": "313a38f09c77fbcdc1d223e57d368cea76a2fd2f",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
|
@ -3760,10 +3760,10 @@
|
|||
"homepage": "https://symfony.com/contributors"
|
||||
}
|
||||
],
|
||||
"description": "Symfony Process Component",
|
||||
"description": "Executes commands in sub-processes",
|
||||
"homepage": "https://symfony.com",
|
||||
"support": {
|
||||
"source": "https://github.com/symfony/process/tree/v5.2.1"
|
||||
"source": "https://github.com/symfony/process/tree/v5.2.3"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
|
@ -3779,7 +3779,7 @@
|
|||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2020-12-08T17:03:37+00:00"
|
||||
"time": "2021-01-27T10:15:41+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/service-contracts",
|
||||
|
@ -3862,16 +3862,16 @@
|
|||
},
|
||||
{
|
||||
"name": "symfony/stopwatch",
|
||||
"version": "v5.2.1",
|
||||
"version": "v5.2.3",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/stopwatch.git",
|
||||
"reference": "2b105c0354f39a63038a1d8bf776ee92852813af"
|
||||
"reference": "b12274acfab9d9850c52583d136a24398cdf1a0c"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/stopwatch/zipball/2b105c0354f39a63038a1d8bf776ee92852813af",
|
||||
"reference": "2b105c0354f39a63038a1d8bf776ee92852813af",
|
||||
"url": "https://api.github.com/repos/symfony/stopwatch/zipball/b12274acfab9d9850c52583d136a24398cdf1a0c",
|
||||
"reference": "b12274acfab9d9850c52583d136a24398cdf1a0c",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
|
@ -3901,10 +3901,10 @@
|
|||
"homepage": "https://symfony.com/contributors"
|
||||
}
|
||||
],
|
||||
"description": "Symfony Stopwatch Component",
|
||||
"description": "Provides a way to profile code",
|
||||
"homepage": "https://symfony.com",
|
||||
"support": {
|
||||
"source": "https://github.com/symfony/stopwatch/tree/v5.2.1"
|
||||
"source": "https://github.com/symfony/stopwatch/tree/v5.2.3"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
|
@ -3920,20 +3920,20 @@
|
|||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2020-11-01T16:14:45+00:00"
|
||||
"time": "2021-01-27T10:15:41+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/string",
|
||||
"version": "v5.2.1",
|
||||
"version": "v5.2.3",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/string.git",
|
||||
"reference": "5bd67751d2e3f7d6f770c9154b8fbcb2aa05f7ed"
|
||||
"reference": "c95468897f408dd0aca2ff582074423dd0455122"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/string/zipball/5bd67751d2e3f7d6f770c9154b8fbcb2aa05f7ed",
|
||||
"reference": "5bd67751d2e3f7d6f770c9154b8fbcb2aa05f7ed",
|
||||
"url": "https://api.github.com/repos/symfony/string/zipball/c95468897f408dd0aca2ff582074423dd0455122",
|
||||
"reference": "c95468897f408dd0aca2ff582074423dd0455122",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
|
@ -3976,7 +3976,7 @@
|
|||
"homepage": "https://symfony.com/contributors"
|
||||
}
|
||||
],
|
||||
"description": "Symfony String component",
|
||||
"description": "Provides an object-oriented API to strings and deals with bytes, UTF-8 code points and grapheme clusters in a unified way",
|
||||
"homepage": "https://symfony.com",
|
||||
"keywords": [
|
||||
"grapheme",
|
||||
|
@ -3987,7 +3987,7 @@
|
|||
"utf8"
|
||||
],
|
||||
"support": {
|
||||
"source": "https://github.com/symfony/string/tree/v5.2.1"
|
||||
"source": "https://github.com/symfony/string/tree/v5.2.3"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
|
@ -4003,7 +4003,7 @@
|
|||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2020-12-05T07:33:16+00:00"
|
||||
"time": "2021-01-25T15:14:59+00:00"
|
||||
},
|
||||
{
|
||||
"name": "theseer/tokenizer",
|
||||
|
|
|
@ -19,6 +19,31 @@ use RuntimeException;
|
|||
|
||||
final class Getch
|
||||
{
|
||||
// Special key codes
|
||||
public const GETCH_SPECIAL = 0;
|
||||
public const GETCH_F1 = 59;
|
||||
public const GETCH_F2 = 60;
|
||||
public const GETCH_F3 = 61;
|
||||
public const GETCH_F4 = 62;
|
||||
public const GETCH_F5 = 63;
|
||||
public const GETCH_F6 = 64;
|
||||
public const GETCH_F7 = 65;
|
||||
public const GETCH_F8 = 66;
|
||||
public const GETCH_F9 = 67;
|
||||
public const GETCH_F10 = 68;
|
||||
public const GETCH_F11 = 87;
|
||||
public const GETCH_F12 = 88;
|
||||
public const GETCH_UP_ARROW = 72;
|
||||
public const GETCH_LEFT_ARROW = 75;
|
||||
public const GETCH_RIGHT_ARROW = 77;
|
||||
public const GETCH_DOWN_ARROW = 80;
|
||||
public const GETCH_DELETE = 83;
|
||||
public const GETCH_HOME = 102;
|
||||
public const GETCH_PGUP = 104;
|
||||
public const GETCH_END = 107;
|
||||
public const GETCH_PGDN = 109;
|
||||
public const GETCH_INSERT = 110;
|
||||
|
||||
private const LINUX_LIBRARY = __DIR__.'/Resources/libgetch.so';
|
||||
private const WINDOWS_LIBRARY = 'ucrtbase.dll';
|
||||
private const DECLARATIONS = <<<DECLARATIONS
|
||||
|
@ -28,6 +53,11 @@ final class Getch
|
|||
|
||||
private static ?FFI $ffi = null;
|
||||
|
||||
public static function resetFFI(): void
|
||||
{
|
||||
static::$ffi = null;
|
||||
}
|
||||
|
||||
public function __construct(string $linuxLibrary = null)
|
||||
{
|
||||
if (null === $linuxLibrary) {
|
||||
|
|
|
@ -3,8 +3,15 @@
|
|||
#include <unistd.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
static struct termios oldattr;
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
#define CTRL_KEY(k) ((k) & 0x1f)
|
||||
|
||||
static struct termios oldattr;
|
||||
static int stdin_flags;
|
||||
|
||||
/*
|
||||
static char *strrev(char *str)
|
||||
{
|
||||
char *p1, *p2;
|
||||
|
@ -19,26 +26,152 @@ static char *strrev(char *str)
|
|||
}
|
||||
return str;
|
||||
}
|
||||
|
||||
|
||||
static void setRawMode(void)
|
||||
{
|
||||
struct termios newattr;
|
||||
|
||||
tcgetattr(STDIN_FILENO, &oldattr);
|
||||
newattr = oldattr;
|
||||
cfmakeraw(&newattr);
|
||||
tcsetattr(STDIN_FILENO, TCSANOW, &newattr);
|
||||
|
||||
}
|
||||
*/
|
||||
static void setNormalMode(void)
|
||||
{
|
||||
tcsetattr(STDIN_FILENO, TCSANOW, &oldattr);
|
||||
fcntl(STDIN_FILENO, F_SETFL, stdin_flags);
|
||||
}
|
||||
|
||||
static void setRawMode(void)
|
||||
{
|
||||
tcgetattr(STDIN_FILENO, &oldattr);
|
||||
atexit(setNormalMode);
|
||||
|
||||
struct termios raw = oldattr;
|
||||
|
||||
raw.c_iflag &= ~(BRKINT | ICRNL | INPCK | ISTRIP | IXON);
|
||||
raw.c_oflag &= ~(OPOST);
|
||||
raw.c_cflag |= (CS8);
|
||||
raw.c_lflag &= ~(ECHO | ICANON | IEXTEN | ISIG);
|
||||
raw.c_cc[VMIN] = 0;
|
||||
raw.c_cc[VTIME] = 1;
|
||||
|
||||
tcsetattr(STDIN_FILENO, TCSANOW, &raw);
|
||||
|
||||
}
|
||||
|
||||
// F1 - 59
|
||||
// F2 - 60,
|
||||
// F3 - 61,
|
||||
// F2 - 62
|
||||
// F1-12 = 59 - 68
|
||||
enum special_keycodes {
|
||||
GETCH_F1 = 59,
|
||||
GETCH_F2,
|
||||
GETCH_F3,
|
||||
GETCH_F4,
|
||||
GETCH_F5,
|
||||
GETCH_F6,
|
||||
GETCH_F7,
|
||||
GETCH_F8,
|
||||
GETCH_F9,
|
||||
GETCH_F10,
|
||||
GETCH_UP_ARROW = 72,
|
||||
GETCH_LEFT_ARROW = 75,
|
||||
GETCH_RIGHT_ARROW = 77,
|
||||
GETCH_DOWN_ARROW = 80,
|
||||
GETCH_DELETE = 83,
|
||||
GETCH_F11 = 87,
|
||||
GETCH_F12,
|
||||
GETCH_HOME = 102,
|
||||
GETCH_PGUP = 104,
|
||||
GETCH_END = 107,
|
||||
GETCH_PGDOWN = 109,
|
||||
GETCH_INSERT
|
||||
};
|
||||
|
||||
void _ungetc(int c) {
|
||||
ungetc(c, stdin);
|
||||
}
|
||||
|
||||
int readKey(void) {
|
||||
|
||||
int bytesRead;
|
||||
|
||||
char key;
|
||||
|
||||
while ((key = fgetc(stdin)) == EOF) {
|
||||
}
|
||||
|
||||
if (key == '\x1b') {
|
||||
char seq[4];
|
||||
if ((seq[0] = getchar()) == EOF) return '\x1b'; // [
|
||||
if ((seq[1] = getchar()) == EOF) return '\x1b';
|
||||
|
||||
if (seq[0] == '[') {
|
||||
if(seq[1] == 'H') { _ungetc(GETCH_HOME); return 0; }
|
||||
if(seq[1] == 'F') { _ungetc(GETCH_END); return 0; }
|
||||
|
||||
if (seq[1] >= '0' && seq[1] <= '9') {
|
||||
if ((seq[2] = getchar()) == EOF) return '\x1b';
|
||||
if (seq[2] == '~') {
|
||||
switch (seq[1]) {
|
||||
case '1': _ungetc(GETCH_HOME); return 0;
|
||||
case '2': _ungetc(GETCH_INSERT); return 0;
|
||||
case '3': _ungetc(GETCH_DELETE); return 0;
|
||||
case '4': _ungetc(GETCH_END); return 0;
|
||||
case '5': _ungetc(GETCH_PGUP); return 0;
|
||||
case '6': _ungetc(GETCH_PGDOWN); return 0;
|
||||
case '7': _ungetc(GETCH_HOME); return 0;
|
||||
case '8': _ungetc(GETCH_END); return 0;
|
||||
}
|
||||
} else if(seq[2] >= '0' && seq[2] <= '9') {
|
||||
if ((seq[3] = getchar()) == EOF) return '\x1b';
|
||||
if(seq[3] != '~') return seq[3];
|
||||
|
||||
switch(seq[2]) {
|
||||
case '5': _ungetc(GETCH_F5); return 0;
|
||||
case '7': _ungetc(GETCH_F6); return 0;
|
||||
case '8': _ungetc(GETCH_F7); return 0;
|
||||
case '9': _ungetc(GETCH_F8); return 0;
|
||||
case '0': _ungetc(GETCH_F9); return 0;
|
||||
case '1': _ungetc(GETCH_F10); return 0;
|
||||
case '3': _ungetc(GETCH_F11); return 0;
|
||||
case '4': _ungetc(GETCH_F12); return 0;
|
||||
}
|
||||
|
||||
} else { return seq[2]; }
|
||||
} else {
|
||||
switch (seq[1]) {
|
||||
case 'A': _ungetc(GETCH_UP_ARROW); return 0;
|
||||
case 'B': _ungetc(GETCH_DOWN_ARROW); return 0;
|
||||
case 'C': _ungetc(GETCH_RIGHT_ARROW); return 0;
|
||||
case 'D': _ungetc(GETCH_LEFT_ARROW); return 0;
|
||||
case 'H': _ungetc(GETCH_HOME); return 0;
|
||||
case 'F': _ungetc(GETCH_END); return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (seq[0] == 'O') {
|
||||
switch (seq[1]) {
|
||||
case 'H': _ungetc(GETCH_HOME); return 0;
|
||||
case 'F': _ungetc(GETCH_END); return 0;
|
||||
case 'P': _ungetc(GETCH_F1); return 0;
|
||||
case 'Q': _ungetc(GETCH_F2); return 0;
|
||||
case 'R': _ungetc(GETCH_F3); return 0;
|
||||
case 'S': _ungetc(GETCH_F4); return 0;
|
||||
}
|
||||
}
|
||||
return '\x1b';
|
||||
} else {
|
||||
return key;
|
||||
}
|
||||
}
|
||||
|
||||
int _getch(void) {
|
||||
|
||||
setRawMode();
|
||||
|
||||
int key = readKey();
|
||||
|
||||
setNormalMode();
|
||||
|
||||
return key;
|
||||
}
|
||||
|
||||
/* reads from keypress, doesn't echo */
|
||||
int _getch(void)
|
||||
int old_getch(void)
|
||||
{
|
||||
int ch;
|
||||
|
||||
|
@ -49,6 +182,113 @@ int _getch(void)
|
|||
|
||||
setNormalMode();
|
||||
|
||||
if(ch == 27) {
|
||||
|
||||
char sequence[4];
|
||||
|
||||
if (read(STDIN_FILENO, &sequence[0], 1) != 1) return 27; // [
|
||||
if (read(STDIN_FILENO, &sequence[1], 1) != 1) return 27; // 0-9
|
||||
|
||||
switch(ch)
|
||||
{
|
||||
case 79: // F1-F4
|
||||
ch = getchar();
|
||||
switch(ch) {
|
||||
case 80: // F1, [ESC]OP
|
||||
_ungetc(GETCH_F1);
|
||||
return 0;
|
||||
break;
|
||||
case 81: // F2, [ESC]OQ
|
||||
_ungetc(GETCH_F2);
|
||||
return 0;
|
||||
break;
|
||||
case 82: // F3,, [ESC]OR
|
||||
_ungetc(61);
|
||||
return 0;
|
||||
case 83: // F4, , [ESC]OS
|
||||
_ungetc(62);
|
||||
return 0;
|
||||
}
|
||||
case 91: // [, Everything else
|
||||
ch = getchar();
|
||||
switch(ch) {
|
||||
case 49: // 1, F5-F8, HOME
|
||||
ch = getchar();
|
||||
switch(ch) {
|
||||
case 53: // 5, F5
|
||||
getchar(); // get the ~
|
||||
_ungetc(63);
|
||||
return 0;
|
||||
case 55: // 7, F6
|
||||
getchar();
|
||||
_ungetc(64);
|
||||
return 0;
|
||||
case 56: // 8, F7
|
||||
getchar();
|
||||
_ungetc(65);
|
||||
return 0;
|
||||
case 57: // 9, F8
|
||||
getchar();
|
||||
_ungetc(66);
|
||||
return 0;
|
||||
case 126: // ~, HOME
|
||||
_ungetc(102);
|
||||
return 0;
|
||||
}
|
||||
case 50: // 2, F9-F12, INSERT
|
||||
ch = getchar();
|
||||
switch(ch) {
|
||||
case 48: // 0, F9, [ESC][20~
|
||||
getchar();
|
||||
_ungetc(67);
|
||||
return 0;
|
||||
case 49: // 1, F10, [ESC][21~
|
||||
getchar();
|
||||
_ungetc(68);
|
||||
return 0;
|
||||
case 51: // 3, F11, [ESC][23~
|
||||
getchar();
|
||||
_ungetc(87);
|
||||
return 0;
|
||||
case 52: // 4, F12, [ESC][24~
|
||||
getchar();
|
||||
_ungetc(88);
|
||||
return 0;
|
||||
case 126: // ~, INSERT, [ESC][2~
|
||||
_ungetc(110);
|
||||
return 0;
|
||||
}
|
||||
case 51: // 3, DELETE, [ESC][3~
|
||||
getchar(); // ~
|
||||
_ungetc(83);
|
||||
return 0;
|
||||
case 52: // 4, END, [ESC][4~
|
||||
getchar(); // ~
|
||||
_ungetc(107);
|
||||
return 0;
|
||||
case 53: // 5, PGUP, [ESC][5~
|
||||
getchar(); // ~
|
||||
_ungetc(104);
|
||||
return 0;
|
||||
case 54: // 6, PGDN, [ESC][6~
|
||||
getchar(); // ~
|
||||
_ungetc(109);
|
||||
return 0;
|
||||
case 65: // A, UP_ARROW, [ESC][A //72
|
||||
_ungetc(72);
|
||||
return 0;
|
||||
case 66: // B, DOWN_ARROW, [ESC][B // 80
|
||||
_ungetc(80);
|
||||
return 0;
|
||||
case 67: // C, RIGHT_ARROW, [ESC][C /77
|
||||
_ungetc(77);
|
||||
return 0;
|
||||
case 68: // D, LEFT_ARROW, [ESC][D //75
|
||||
_ungetc(75);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
return ch;
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,16 @@
|
|||
F1-10 = 59..68
|
||||
UP_ARROW = 72
|
||||
LEFT_ARROW = 75
|
||||
RIGHT_ARROW = 77
|
||||
DOWN_ARROW = 80
|
||||
DELETE = 83
|
||||
F11-12 = 87..88
|
||||
HOME = 102
|
||||
PGUP = 104
|
||||
END = 107
|
||||
PGDN = 109
|
||||
INSERT = 110
|
||||
|
||||
|
||||
|
||||
|
Binary file not shown.
|
@ -8,24 +8,27 @@ 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');
|
||||
$stdin = $this->ffi->stdin;
|
||||
$file = $this->ffi->stdin;
|
||||
$stdin = $this->ffi->fopen('/dev/stdin', 'a+');
|
||||
|
||||
foreach (range('D', 'A') as $character) {
|
||||
$this->ffi->ungetc(ord($character), $stdin);
|
||||
$this->ffi->ungetc(ord($character), $file);
|
||||
}
|
||||
|
||||
parent::setUp(); // TODO: Change the autogenerated stub
|
||||
}
|
||||
|
||||
/**
|
||||
* @preserveGlobalState disabled
|
||||
* @backupStaticAttributes false
|
||||
* @backupGlobals false
|
||||
*/
|
||||
public function testFailureOnInvalidLibrary()
|
||||
{
|
||||
Getch::resetFFI();
|
||||
$this->expectException(\RuntimeException::class);
|
||||
\getch(__DIR__.'/library.so');
|
||||
}
|
||||
|
@ -53,4 +56,16 @@ class GetchTest extends TestCase
|
|||
$this->expectException(\RuntimeException::class);
|
||||
\getch();
|
||||
}
|
||||
|
||||
public function testHomeKey()
|
||||
{
|
||||
$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(102, $g->getch());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -13,5 +13,7 @@ typedef struct _iobuf
|
|||
|
||||
FILE *stdin;
|
||||
|
||||
FILE *fopen(const char *filename, const char *mode);
|
||||
|
||||
int ungetc(int ch, FILE *stream);
|
||||
|
||||
|
|
Loading…
Reference in New Issue