diff --git a/README.md b/README.md index ecb0a82..731b5a2 100644 --- a/README.md +++ b/README.md @@ -75,6 +75,12 @@ are supported as defined in [ISO/IEC 2022](https://en.wikipedia.org/wiki/ISO/IEC * PM (Privacy Message) +* SS2 (Single Shift 2) + this means select the following character form the G2 character set + +* SS3 (Single Shift 3) + this means select the following character form the G3 character set + Each code sequence gets emitted with a dedicated event with its raw byte sequence: ```php @@ -90,6 +96,8 @@ $stream->on('osc', function ($sequence) { … }); $stream->on('apc', function ($sequence) { … }); $stream->on('dps', function ($sequence) { … }); $stream->on('pm', function ($sequence) { … }); +$stream->on('ss2', function ($sequence) { … }); +$stream->on('ss3', function ($sequence) { … }); ``` Other lesser known [C1 control codes](https://en.wikipedia.org/wiki/C0_and_C1_control_codes#C1_set) diff --git a/src/ControlCodeParser.php b/src/ControlCodeParser.php index abbe400..73f503c 100644 --- a/src/ControlCodeParser.php +++ b/src/ControlCodeParser.php @@ -21,6 +21,8 @@ class ControlCodeParser extends EventEmitter implements ReadableStreamInterface * followed by "_" means it's APC (Application Program-Control) * followed by "P" means it's DPS (Device-Control string) * followed by "^" means it's PM (Privacy Message) + * followed by "N" means it's SS2 (Single Shift 2) + * followed by "O" means it's SS3 (Single Shift 3) * * Each of these will be parsed until the sequence ends and then emitted * under their respective name. @@ -39,6 +41,8 @@ class ControlCodeParser extends EventEmitter implements ReadableStreamInterface '_' => 'apc', 'P' => 'dps', '^' => 'pm', + 'N' => 'ss2', + 'O' => 'ss3', ); public function __construct(ReadableStreamInterface $input) @@ -171,6 +175,12 @@ public function handleData($data) break; } } + } else if ($type === 'ss2' || $type === 'ss3') { + $data = substr($this->buffer, 0, 3); + $this->buffer = (string) substr($this->buffer, 3); + + $this->emit($type, array($data)); + $found = true; } else { // all other types are terminated by ST // only OSC can also be terminted by BEL (whichever comes first) diff --git a/tests/ControlCodeParserTest.php b/tests/ControlCodeParserTest.php index c94399e..ee08550 100644 --- a/tests/ControlCodeParserTest.php +++ b/tests/ControlCodeParserTest.php @@ -226,6 +226,38 @@ public function testDoesNotEmitDpsIfItDoesNotEndWithSt() $this->input->emit('data', array("\x1BPasd\x07")); } + public function testEmitsSs2AndData() + { + $this->parser->on('data', $this->expectCallableOnceWith('hello')); + $this->parser->on('ss2', $this->expectCallableOnceWith("\x1BNE")); + + $this->input->emit('data', array("\x1BNEhello")); + } + + public function testEmitsDataAndSs2() + { + $this->parser->on('data', $this->expectCallableOnceWith('hello')); + $this->parser->on('ss2', $this->expectCallableOnceWith("\x1BNE")); + + $this->input->emit('data', array("hello\x1BNE")); + } + + public function testEmitsSs3AndData() + { + $this->parser->on('data', $this->expectCallableOnceWith('hello')); + $this->parser->on('ss3', $this->expectCallableOnceWith("\x1BOP")); + + $this->input->emit('data', array("\x1BOPhello")); + } + + public function testEmitsDataAndSs3() + { + $this->parser->on('data', $this->expectCallableOnceWith('hello')); + $this->parser->on('ss3', $this->expectCallableOnceWith("\x1BOP")); + + $this->input->emit('data', array("hello\x1BOP")); + } + public function testEmitsUnknownC1AsOneChunk() { $this->parser->on('data', $this->expectCallableNever());