diff --git a/lib/src/core/escape/parser.dart b/lib/src/core/escape/parser.dart index 0c7e74a9..c9da20ac 100644 --- a/lib/src/core/escape/parser.dart +++ b/lib/src/core/escape/parser.dart @@ -408,6 +408,9 @@ class EscapeParser { /// /// https://terminalguide.namepad.de/seq/csi_sm/ void _csiHandleSgr() { + // `CSI > Ps m` (XTMODKEYS) and `CSI ? Ps m` are not SGR. + if (_csi.prefix != null) return; + final params = _csi.params; if (params.isEmpty) { diff --git a/test/src/core/escape/parser_test.dart b/test/src/core/escape/parser_test.dart index 96fa5bb1..b93f1443 100644 --- a/test/src/core/escape/parser_test.dart +++ b/test/src/core/escape/parser_test.dart @@ -13,5 +13,24 @@ void main() { parser.write('\x1b[8;24;80t'); verify(parser.handler.resize(80, 24)); }); + + test('does not treat CSI > Ps m as SGR', () { + final parser = EscapeParser(MockEscapeHandler()); + // XTMODKEYS, e.g. sent by programs enabling modifyOtherKeys. + parser.write('\x1b[>4m'); + verifyNever(parser.handler.setCursorUnderline()); + }); + + test('does not treat CSI ? Ps m as SGR', () { + final parser = EscapeParser(MockEscapeHandler()); + parser.write('\x1b[?4m'); + verifyNever(parser.handler.setCursorUnderline()); + }); + + test('still parses plain SGR', () { + final parser = EscapeParser(MockEscapeHandler()); + parser.write('\x1b[4m'); + verify(parser.handler.setCursorUnderline()).called(1); + }); }); }