mirror of
https://github.com/ghostty-org/ghostty.git
synced 2025-07-16 16:56:09 +03:00
Merge pull request #626 from mitchellh/xt-ff
xterm audit: LF, VT, FF, CUD (cursor down), IND (index)
This commit is contained in:
@ -898,11 +898,16 @@ pub fn index(self: *Terminal) !void {
|
|||||||
// If the cursor is inside the scrolling region and on the bottom-most
|
// If the cursor is inside the scrolling region and on the bottom-most
|
||||||
// line, then we scroll up. If our scrolling region is the full screen
|
// line, then we scroll up. If our scrolling region is the full screen
|
||||||
// we create scrollback.
|
// we create scrollback.
|
||||||
if (self.screen.cursor.y == self.scrolling_region.bottom) {
|
if (self.screen.cursor.y == self.scrolling_region.bottom and
|
||||||
|
self.screen.cursor.x >= self.scrolling_region.left and
|
||||||
|
self.screen.cursor.x <= self.scrolling_region.right)
|
||||||
|
{
|
||||||
// If our scrolling region is the full screen, we create scrollback.
|
// If our scrolling region is the full screen, we create scrollback.
|
||||||
// Otherwise, we simply scroll the region.
|
// Otherwise, we simply scroll the region.
|
||||||
if (self.scrolling_region.top == 0 and
|
if (self.scrolling_region.top == 0 and
|
||||||
self.scrolling_region.bottom == self.rows - 1)
|
self.scrolling_region.bottom == self.rows - 1 and
|
||||||
|
self.scrolling_region.left == 0 and
|
||||||
|
self.scrolling_region.right == self.cols - 1)
|
||||||
{
|
{
|
||||||
try self.screen.scroll(.{ .screen = 1 });
|
try self.screen.scroll(.{ .screen = 1 });
|
||||||
} else {
|
} else {
|
||||||
@ -1449,16 +1454,21 @@ pub fn cursorRight(self: *Terminal, count: usize) void {
|
|||||||
/// Move the cursor down amount lines. If amount is greater than the maximum
|
/// Move the cursor down amount lines. If amount is greater than the maximum
|
||||||
/// move distance then it is internally adjusted to the maximum. This sequence
|
/// move distance then it is internally adjusted to the maximum. This sequence
|
||||||
/// will not scroll the screen or scroll region. If amount is 0, adjust it to 1.
|
/// will not scroll the screen or scroll region. If amount is 0, adjust it to 1.
|
||||||
// TODO: test
|
pub fn cursorDown(self: *Terminal, count_req: usize) void {
|
||||||
pub fn cursorDown(self: *Terminal, count: usize) void {
|
|
||||||
const tracy = trace(@src());
|
const tracy = trace(@src());
|
||||||
defer tracy.end();
|
defer tracy.end();
|
||||||
|
|
||||||
|
// Always resets pending wrap
|
||||||
self.screen.cursor.pending_wrap = false;
|
self.screen.cursor.pending_wrap = false;
|
||||||
self.screen.cursor.y += if (count == 0) 1 else count;
|
|
||||||
if (self.screen.cursor.y >= self.rows) {
|
// The max the cursor can move to depends where the cursor currently is
|
||||||
self.screen.cursor.y = self.rows - 1;
|
const max = if (self.screen.cursor.y <= self.scrolling_region.bottom)
|
||||||
}
|
self.scrolling_region.bottom
|
||||||
|
else
|
||||||
|
self.rows - 1;
|
||||||
|
|
||||||
|
const count = @max(count_req, 1);
|
||||||
|
self.screen.cursor.y = @min(max, self.screen.cursor.y +| count);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Move the cursor up amount lines. If amount is greater than the maximum
|
/// Move the cursor up amount lines. If amount is greater than the maximum
|
||||||
@ -2823,6 +2833,138 @@ test "Terminal: index from the bottom outside of scroll region" {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
test "Terminal: index no scroll region, top of screen" {
|
||||||
|
const alloc = testing.allocator;
|
||||||
|
var t = try init(alloc, 5, 5);
|
||||||
|
defer t.deinit(alloc);
|
||||||
|
|
||||||
|
try t.print('A');
|
||||||
|
try t.index();
|
||||||
|
try t.print('X');
|
||||||
|
|
||||||
|
{
|
||||||
|
var str = try t.plainString(testing.allocator);
|
||||||
|
defer testing.allocator.free(str);
|
||||||
|
try testing.expectEqualStrings("A\n X", str);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
test "Terminal: index bottom of primary screen" {
|
||||||
|
const alloc = testing.allocator;
|
||||||
|
var t = try init(alloc, 5, 5);
|
||||||
|
defer t.deinit(alloc);
|
||||||
|
|
||||||
|
t.setCursorPos(5, 1);
|
||||||
|
try t.print('A');
|
||||||
|
try t.index();
|
||||||
|
try t.print('X');
|
||||||
|
|
||||||
|
{
|
||||||
|
var str = try t.plainString(testing.allocator);
|
||||||
|
defer testing.allocator.free(str);
|
||||||
|
try testing.expectEqualStrings("\n\n\nA\n X", str);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
test "Terminal: index inside scroll region" {
|
||||||
|
const alloc = testing.allocator;
|
||||||
|
var t = try init(alloc, 5, 5);
|
||||||
|
defer t.deinit(alloc);
|
||||||
|
|
||||||
|
t.setScrollingRegion(1, 3);
|
||||||
|
try t.print('A');
|
||||||
|
try t.index();
|
||||||
|
try t.print('X');
|
||||||
|
|
||||||
|
{
|
||||||
|
var str = try t.plainString(testing.allocator);
|
||||||
|
defer testing.allocator.free(str);
|
||||||
|
try testing.expectEqualStrings("A\n X", str);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
test "Terminal: index bottom of scroll region" {
|
||||||
|
const alloc = testing.allocator;
|
||||||
|
var t = try init(alloc, 5, 5);
|
||||||
|
defer t.deinit(alloc);
|
||||||
|
|
||||||
|
t.setScrollingRegion(1, 3);
|
||||||
|
t.setCursorPos(4, 1);
|
||||||
|
try t.print('B');
|
||||||
|
t.setCursorPos(3, 1);
|
||||||
|
try t.print('A');
|
||||||
|
try t.index();
|
||||||
|
try t.print('X');
|
||||||
|
|
||||||
|
{
|
||||||
|
var str = try t.plainString(testing.allocator);
|
||||||
|
defer testing.allocator.free(str);
|
||||||
|
try testing.expectEqualStrings("\nA\n X\nB", str);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
test "Terminal: index bottom of primary screen with scroll region" {
|
||||||
|
const alloc = testing.allocator;
|
||||||
|
var t = try init(alloc, 5, 5);
|
||||||
|
defer t.deinit(alloc);
|
||||||
|
|
||||||
|
t.setScrollingRegion(1, 3);
|
||||||
|
t.setCursorPos(3, 1);
|
||||||
|
try t.print('A');
|
||||||
|
t.setCursorPos(5, 1);
|
||||||
|
try t.index();
|
||||||
|
try t.index();
|
||||||
|
try t.index();
|
||||||
|
try t.print('X');
|
||||||
|
|
||||||
|
{
|
||||||
|
var str = try t.plainString(testing.allocator);
|
||||||
|
defer testing.allocator.free(str);
|
||||||
|
try testing.expectEqualStrings("\n\nA\n\nX", str);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
test "Terminal: index outside left/right margin" {
|
||||||
|
const alloc = testing.allocator;
|
||||||
|
var t = try init(alloc, 10, 5);
|
||||||
|
defer t.deinit(alloc);
|
||||||
|
|
||||||
|
t.setScrollingRegion(1, 3);
|
||||||
|
t.scrolling_region.left = 3;
|
||||||
|
t.scrolling_region.right = 5;
|
||||||
|
t.setCursorPos(3, 3);
|
||||||
|
try t.print('A');
|
||||||
|
t.setCursorPos(3, 1);
|
||||||
|
try t.index();
|
||||||
|
try t.print('X');
|
||||||
|
|
||||||
|
{
|
||||||
|
var str = try t.plainString(testing.allocator);
|
||||||
|
defer testing.allocator.free(str);
|
||||||
|
try testing.expectEqualStrings("\n\nX A", str);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
test "Terminal: index inside left/right margin" {
|
||||||
|
const alloc = testing.allocator;
|
||||||
|
var t = try init(alloc, 10, 5);
|
||||||
|
defer t.deinit(alloc);
|
||||||
|
|
||||||
|
t.setScrollingRegion(1, 3);
|
||||||
|
t.scrolling_region.left = 3;
|
||||||
|
t.scrolling_region.right = 5;
|
||||||
|
t.setCursorPos(3, 3);
|
||||||
|
try t.print('A');
|
||||||
|
try t.index();
|
||||||
|
try t.print('X');
|
||||||
|
|
||||||
|
{
|
||||||
|
var str = try t.plainString(testing.allocator);
|
||||||
|
defer testing.allocator.free(str);
|
||||||
|
try testing.expectEqualStrings("\n A\n X", str);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
test "Terminal: DECALN" {
|
test "Terminal: DECALN" {
|
||||||
const alloc = testing.allocator;
|
const alloc = testing.allocator;
|
||||||
var t = try init(alloc, 2, 2);
|
var t = try init(alloc, 2, 2);
|
||||||
@ -3561,3 +3703,72 @@ test "Terminal: cursorLeft extended reverse wrap is priority if both set" {
|
|||||||
try testing.expectEqualStrings("ABCDE\n1\n X", str);
|
try testing.expectEqualStrings("ABCDE\n1\n X", str);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
test "Terminal: cursorDown basic" {
|
||||||
|
const alloc = testing.allocator;
|
||||||
|
var t = try init(alloc, 5, 5);
|
||||||
|
defer t.deinit(alloc);
|
||||||
|
|
||||||
|
try t.print('A');
|
||||||
|
t.cursorDown(10);
|
||||||
|
try t.print('X');
|
||||||
|
|
||||||
|
{
|
||||||
|
var str = try t.plainString(testing.allocator);
|
||||||
|
defer testing.allocator.free(str);
|
||||||
|
try testing.expectEqualStrings("A\n\n\n\n X", str);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
test "Terminal: cursorDown above bottom scroll margin" {
|
||||||
|
const alloc = testing.allocator;
|
||||||
|
var t = try init(alloc, 5, 5);
|
||||||
|
defer t.deinit(alloc);
|
||||||
|
|
||||||
|
t.setScrollingRegion(1, 3);
|
||||||
|
try t.print('A');
|
||||||
|
t.cursorDown(10);
|
||||||
|
try t.print('X');
|
||||||
|
|
||||||
|
{
|
||||||
|
var str = try t.plainString(testing.allocator);
|
||||||
|
defer testing.allocator.free(str);
|
||||||
|
try testing.expectEqualStrings("A\n\n X", str);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
test "Terminal: cursorDown below bottom scroll margin" {
|
||||||
|
const alloc = testing.allocator;
|
||||||
|
var t = try init(alloc, 5, 5);
|
||||||
|
defer t.deinit(alloc);
|
||||||
|
|
||||||
|
t.setScrollingRegion(1, 3);
|
||||||
|
try t.print('A');
|
||||||
|
t.setCursorPos(4, 1);
|
||||||
|
t.cursorDown(10);
|
||||||
|
try t.print('X');
|
||||||
|
|
||||||
|
{
|
||||||
|
var str = try t.plainString(testing.allocator);
|
||||||
|
defer testing.allocator.free(str);
|
||||||
|
try testing.expectEqualStrings("A\n\n\n\nX", str);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
test "Terminal: cursorDown resets wrap" {
|
||||||
|
const alloc = testing.allocator;
|
||||||
|
var t = try init(alloc, 5, 5);
|
||||||
|
defer t.deinit(alloc);
|
||||||
|
|
||||||
|
for ("ABCDE") |c| try t.print(c);
|
||||||
|
try testing.expect(t.screen.cursor.pending_wrap);
|
||||||
|
t.cursorDown(1);
|
||||||
|
try testing.expect(!t.screen.cursor.pending_wrap);
|
||||||
|
try t.print('X');
|
||||||
|
|
||||||
|
{
|
||||||
|
var str = try t.plainString(testing.allocator);
|
||||||
|
defer testing.allocator.free(str);
|
||||||
|
try testing.expectEqualStrings("ABCDE\n X", str);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -21,6 +21,8 @@ pub const C0 = enum(u7) {
|
|||||||
LF = 0x0A,
|
LF = 0x0A,
|
||||||
/// Vertical Tab
|
/// Vertical Tab
|
||||||
VT = 0x0B,
|
VT = 0x0B,
|
||||||
|
/// Form feed
|
||||||
|
FF = 0x0C,
|
||||||
/// Carriage return
|
/// Carriage return
|
||||||
CR = 0x0D,
|
CR = 0x0D,
|
||||||
/// Shift out
|
/// Shift out
|
||||||
|
@ -115,13 +115,7 @@ pub fn Stream(comptime Handler: type) type {
|
|||||||
else
|
else
|
||||||
log.warn("unimplemented execute: {x}", .{c}),
|
log.warn("unimplemented execute: {x}", .{c}),
|
||||||
|
|
||||||
.LF => if (@hasDecl(T, "linefeed"))
|
.LF, .VT, .FF => if (@hasDecl(T, "linefeed"))
|
||||||
try self.handler.linefeed()
|
|
||||||
else
|
|
||||||
log.warn("unimplemented execute: {x}", .{c}),
|
|
||||||
|
|
||||||
// VT is same as LF
|
|
||||||
.VT => if (@hasDecl(T, "linefeed"))
|
|
||||||
try self.handler.linefeed()
|
try self.handler.linefeed()
|
||||||
else
|
else
|
||||||
log.warn("unimplemented execute: {x}", .{c}),
|
log.warn("unimplemented execute: {x}", .{c}),
|
||||||
|
75
website/app/vt/cud/page.mdx
Normal file
75
website/app/vt/cud/page.mdx
Normal file
@ -0,0 +1,75 @@
|
|||||||
|
import VTSequence from "@/components/VTSequence";
|
||||||
|
|
||||||
|
# Cursor Down (CUD)
|
||||||
|
|
||||||
|
<VTSequence sequence={["CSI", "Pn", "B"]} />
|
||||||
|
|
||||||
|
Move the cursor `n` cells down.
|
||||||
|
|
||||||
|
The parameter `n` must be an integer greater than or equal to 1. If `n` is less than
|
||||||
|
or equal to 0, adjust `n` to be 1. If `n` is omitted, `n` defaults to 1.
|
||||||
|
|
||||||
|
This sequence always unsets the pending wrap state.
|
||||||
|
|
||||||
|
If the current cursor position is at or above the [bottom margin](#TODO),
|
||||||
|
the lowest point the cursor can move is the bottom margin. If the current
|
||||||
|
cursor position is below the bottom margin, the lowest point the cursor
|
||||||
|
can move is the final row.
|
||||||
|
|
||||||
|
This sequence never triggers scrolling.
|
||||||
|
|
||||||
|
## Validation
|
||||||
|
|
||||||
|
### CUD V-1: Cursor Down
|
||||||
|
|
||||||
|
```bash
|
||||||
|
printf "A"
|
||||||
|
printf "\033[2B" # cursor down
|
||||||
|
printf "X"
|
||||||
|
```
|
||||||
|
|
||||||
|
```
|
||||||
|
|A_________|
|
||||||
|
|__________|
|
||||||
|
|_Xc_______|
|
||||||
|
```
|
||||||
|
|
||||||
|
### CUD V-2: Cursor Down Above Bottom Margin
|
||||||
|
|
||||||
|
```bash
|
||||||
|
printf "\033[1;1H" # move to top-left
|
||||||
|
printf "\033[0J" # clear screen
|
||||||
|
printf "\n\n\n\n" # screen is 4 high
|
||||||
|
printf "\033[1;3r" # set scrolling region
|
||||||
|
printf "A"
|
||||||
|
printf "\033[5B" # cursor down
|
||||||
|
printf "X"
|
||||||
|
```
|
||||||
|
|
||||||
|
```
|
||||||
|
|A_________|
|
||||||
|
|__________|
|
||||||
|
|_Xc_______|
|
||||||
|
|__________|
|
||||||
|
```
|
||||||
|
|
||||||
|
### CUD V-3: Cursor Down Below Bottom Margin
|
||||||
|
|
||||||
|
```bash
|
||||||
|
printf "\033[1;1H" # move to top-left
|
||||||
|
printf "\033[0J" # clear screen
|
||||||
|
printf "\n\n\n\n\n" # screen is 5 high
|
||||||
|
printf "\033[1;3r" # set scrolling region
|
||||||
|
printf "A"
|
||||||
|
printf "\033[4;1H" # move below region
|
||||||
|
printf "\033[5B" # cursor down
|
||||||
|
printf "X"
|
||||||
|
```
|
||||||
|
|
||||||
|
```
|
||||||
|
|A_________|
|
||||||
|
|__________|
|
||||||
|
|__________|
|
||||||
|
|__________|
|
||||||
|
|_Xc_______|
|
||||||
|
```
|
138
website/app/vt/ind/page.mdx
Normal file
138
website/app/vt/ind/page.mdx
Normal file
@ -0,0 +1,138 @@
|
|||||||
|
import VTSequence from "@/components/VTSequence";
|
||||||
|
|
||||||
|
# Index (IND)
|
||||||
|
|
||||||
|
<VTSequence sequence={["ESC", "D"]} />
|
||||||
|
|
||||||
|
Move the cursor down one cell, scrolling if necessary.
|
||||||
|
|
||||||
|
This sequence always unsets the pending wrap state.
|
||||||
|
|
||||||
|
If the cursor is exactly on the bottom margin and is at or within the
|
||||||
|
[left](#TODO) and [right margin](#TODO), [scroll up](#TODO) one line.
|
||||||
|
If the scroll region is the full terminal screen and the terminal is on
|
||||||
|
the [primary screen](#TODO), this may create scrollback. See the
|
||||||
|
[scroll](#TODO) documentation for more details.
|
||||||
|
|
||||||
|
If the cursor is outside of the scroll region or not on the bottom
|
||||||
|
margin of the scroll region, perform the [cursor down](/vt/cud) operation with
|
||||||
|
`n = 1`.
|
||||||
|
|
||||||
|
This sequence will only scroll when the cursor is exactly on the bottom
|
||||||
|
margin and within the remaining scroll region. If the cursor is outside
|
||||||
|
the scroll region and on the bottom line of the terminal, the cursor
|
||||||
|
does not move.
|
||||||
|
|
||||||
|
## Validation
|
||||||
|
|
||||||
|
### IND V-1: No Scroll Region, Top of Screen
|
||||||
|
|
||||||
|
```bash
|
||||||
|
printf "\033[1;1H" # move to top-left
|
||||||
|
printf "\033[0J" # clear screen
|
||||||
|
printf "A"
|
||||||
|
printf "\033D" # index
|
||||||
|
printf "X"
|
||||||
|
```
|
||||||
|
|
||||||
|
```
|
||||||
|
|A_________|
|
||||||
|
|_Xc_______|
|
||||||
|
```
|
||||||
|
|
||||||
|
### IND V-2: Bottom of Primary Screen
|
||||||
|
|
||||||
|
```bash
|
||||||
|
lines=$(tput lines)
|
||||||
|
printf "\033[1;1H" # move to top-left
|
||||||
|
printf "\033[0J" # clear screen
|
||||||
|
printf "\033[${lines};1H" # move to bottom-left
|
||||||
|
printf "A"
|
||||||
|
printf "\033D" # index
|
||||||
|
printf "X"
|
||||||
|
```
|
||||||
|
|
||||||
|
```
|
||||||
|
|A_________|
|
||||||
|
|_Xc_______|
|
||||||
|
```
|
||||||
|
|
||||||
|
### IND V-3: Inside Scroll Region
|
||||||
|
|
||||||
|
```bash
|
||||||
|
printf "\033[1;1H" # move to top-left
|
||||||
|
printf "\033[0J" # clear screen
|
||||||
|
printf "\033[1;3r" # scroll region
|
||||||
|
printf "A"
|
||||||
|
printf "\033D" # index
|
||||||
|
printf "X"
|
||||||
|
```
|
||||||
|
|
||||||
|
```
|
||||||
|
|A_________|
|
||||||
|
|_Xc_______|
|
||||||
|
```
|
||||||
|
|
||||||
|
### IND V-4: Bottom of Scroll Region
|
||||||
|
|
||||||
|
```bash
|
||||||
|
printf "\033[1;1H" # move to top-left
|
||||||
|
printf "\033[0J" # clear screen
|
||||||
|
printf "\033[1;3r" # scroll region
|
||||||
|
printf "\033[4;1H" # below scroll region
|
||||||
|
printf "B"
|
||||||
|
printf "\033[3;1H" # move to last row of region
|
||||||
|
printf "A"
|
||||||
|
printf "\033D" # index
|
||||||
|
printf "X"
|
||||||
|
```
|
||||||
|
|
||||||
|
```
|
||||||
|
|__________|
|
||||||
|
|A_________|
|
||||||
|
|_Xc_______|
|
||||||
|
|B_________|
|
||||||
|
```
|
||||||
|
|
||||||
|
### IND V-5: Bottom of Primary Screen with Scroll Region
|
||||||
|
|
||||||
|
```bash
|
||||||
|
lines=$(tput lines)
|
||||||
|
printf "\033[1;1H" # move to top-left
|
||||||
|
printf "\033[0J" # clear screen
|
||||||
|
printf "\033[1;3r" # scroll region
|
||||||
|
printf "\033[3;1H" # move to last row of region
|
||||||
|
printf "A"
|
||||||
|
printf "\033[${lines};1H" # move to bottom-left
|
||||||
|
printf "\033D" # index
|
||||||
|
printf "X"
|
||||||
|
```
|
||||||
|
|
||||||
|
```
|
||||||
|
|__________|
|
||||||
|
|__________|
|
||||||
|
|A_________|
|
||||||
|
|__________|
|
||||||
|
|Xc________|
|
||||||
|
```
|
||||||
|
|
||||||
|
### IND V-6: Outside of Left/Right Scroll Region
|
||||||
|
|
||||||
|
```bash
|
||||||
|
printf "\033[1;1H" # move to top-left
|
||||||
|
printf "\033[0J" # clear screen
|
||||||
|
printf "\033[?69h" # enable left/right margins
|
||||||
|
printf "\033[1;3r" # scroll region top/bottom
|
||||||
|
printf "\033[3;5s" # scroll region left/right
|
||||||
|
printf "\033[3;3H"
|
||||||
|
printf "A"
|
||||||
|
printf "\033[3;1H"
|
||||||
|
printf "\033D" # index
|
||||||
|
printf "X"
|
||||||
|
```
|
||||||
|
|
||||||
|
```
|
||||||
|
|__________|
|
||||||
|
|__________|
|
||||||
|
|XcA_______|
|
||||||
|
```
|
10
website/app/vt/lf/page.mdx
Normal file
10
website/app/vt/lf/page.mdx
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
import VTSequence from "@/components/VTSequence";
|
||||||
|
|
||||||
|
# Linefeed (LF)
|
||||||
|
|
||||||
|
<VTSequence sequence="LF" />
|
||||||
|
|
||||||
|
This is an alias for [index (IND)](/vt/ind).
|
||||||
|
|
||||||
|
If [linefeed mode (mode 20)](#TODO) is enabled, perform a
|
||||||
|
[carriage return](/vt/cr) after the IND operation.
|
@ -45,6 +45,7 @@ function VTElem({ elem }: { elem: string }) {
|
|||||||
const special: { [key: string]: number } = {
|
const special: { [key: string]: number } = {
|
||||||
BEL: 0x07,
|
BEL: 0x07,
|
||||||
BS: 0x08,
|
BS: 0x08,
|
||||||
|
LF: 0x0a,
|
||||||
CR: 0x0d,
|
CR: 0x0d,
|
||||||
ESC: 0x1b,
|
ESC: 0x1b,
|
||||||
};
|
};
|
||||||
|
Reference in New Issue
Block a user