1
0
mirror of https://github.com/vlang/v.git synced 2023-08-10 21:13:21 +03:00

term.ui: handle middle mouse button events and modifier keys (#6821)

This commit is contained in:
spaceface777
2020-11-14 08:14:54 +01:00
committed by GitHub
parent 5069be04a2
commit 6b47c61fe4
6 changed files with 94 additions and 59 deletions

View File

@@ -123,9 +123,9 @@ pub enum Direction {
pub enum MouseButton {
unknown
primary
secondary
tertiary
left
middle
right
}
pub enum EventType {

View File

@@ -9,15 +9,6 @@ pub fn init(cfg Config) &Context {
cfg: cfg,
read_buf: []byte{ cap: cfg.buffer_size }
}
ctx.save_title()
if cfg.hide_cursor {
print('\x1b[?25l')
}
if cfg.window_title != '' {
print('\x1b]0;$cfg.window_title\x07')
}
// lmao
unsafe {

View File

@@ -48,9 +48,12 @@ fn restore_terminal_state() {
c.load_title()
}
println('')
}
}
fn (mut ctx Context) termios_setup() {
// store the current title, so restore_terminal_state can get it back
ctx.save_title()
mut termios := get_termios()
if ctx.cfg.capture_events {
@@ -62,23 +65,31 @@ fn (mut ctx Context) termios_setup() {
// Set raw input mode by unsetting ICANON and ECHO
termios.c_lflag &= ~u32(C.ICANON | C.ECHO)
}
if ctx.cfg.hide_cursor {
print('\x1b[?25l')
}
if ctx.cfg.window_title != '' {
print('\x1b]0;$ctx.cfg.window_title\x07')
}
// Prevent stdin from blocking by making its read time 0
termios.c_cc[C.VTIME] = 0
termios.c_cc[C.VMIN] = 0
C.tcsetattr(C.STDIN_FILENO, C.TCSAFLUSH, &termios)
print('\x1b[?1003h\x1b[?1015h\x1b[?1006h')
print('\x1b[?1003h\x1b[?1006h')
ctx.termios = termios
ctx.window_height, ctx.window_width = get_terminal_size()
// Reset console on exit
C.atexit(restore_terminal_state)
C.atexit(restore_terminal_state)
os.signal(C.SIGTSTP, restore_terminal_state)
os.signal(C.SIGCONT, fn () {
mut c := ctx_ptr
if c != 0 {
c.save_title()
c.termios_setup()
c.window_height, c.window_width = get_terminal_size()
mut event := &Event{
@@ -260,31 +271,43 @@ fn escape_sequence(buf_ string) (&Event, int) {
// Mouse events
// ----------------
// TODO: rxvt uses different escape sequences for mouse events :/
// Documentation: https://invisible-island.net/xterm/ctlseqs/ctlseqs.html#h2-Mouse-Tracking
if buf.len > 2 && buf[1] == `<` {
split := buf[2..].split(';')
if split.len < 3 { return &Event(0), 0 }
typ, x, y := split[0].int(), split[1].int(), split[2].int()
lo := typ & 0b00011
hi := typ & 0b11100
mut modifiers := u32(0)
if hi & 4 != 0 { modifiers |= shift }
if hi & 8 != 0 { modifiers |= alt }
if hi & 16 != 0 { modifiers |= ctrl }
match typ {
0, 2 {
0...31 {
last := buf[buf.len - 1]
button := if typ == 0 { MouseButton.primary } else { MouseButton.secondary }
event := if last == `M` { EventType.mouse_down } else { EventType.mouse_up }
return &Event{ typ: event, x: x, y: y, button: button, utf8: single }, end
button := if lo < 3 { MouseButton(lo + 1) } else { MouseButton.unknown }
event := if last == `m` || lo == 3 { EventType.mouse_up } else { EventType.mouse_down }
return &Event{ typ: event, x: x, y: y, button: button, modifiers: modifiers utf8: single }, end
}
32, 34 {
button := if typ == 32 { MouseButton.primary } else { MouseButton.secondary }
return &Event{ typ: .mouse_drag, x: x, y: y, button: button, utf8: single }, end
32...63 {
button, event := if lo < 3 {
MouseButton(lo + 1), EventType.mouse_drag
} else {
MouseButton.unknown, EventType.mouse_move
}
return &Event{ typ: event, x: x, y: y, button: button, modifiers: modifiers, utf8: single }, end
}
35 {
return &Event{ typ: .mouse_move, x: x, y: y, utf8: single }, end
64...95 {
direction := if typ & 1 == 0 { Direction.down } else { Direction.up }
return &Event{ typ: .mouse_scroll, x: x, y: y, direction: direction, modifiers: modifiers, utf8: single }, end
} else {
return &Event{ typ: .unknown, utf8: single }, end
}
64, 65 {
direction := if typ == 64 { Direction.down } else { Direction.up }
return &Event{ typ: .mouse_scroll, x: x, y: y, direction: direction, utf8: single }, end
} else {}
}
}
@@ -320,7 +343,7 @@ fn escape_sequence(buf_ string) (&Event, int) {
else {}
}
if buf.len == 5 && buf[0] == `[` && buf[1] == `1` && buf[2] == `;` {
if buf.len == 5 && buf[0] == `[` && buf[1].is_digit() && buf[2] == `;` {
// code = KeyCode(buf[4] + 197)
modifiers = match buf[3] {
`2` { shift }
@@ -333,20 +356,25 @@ fn escape_sequence(buf_ string) (&Event, int) {
else { modifiers } // probably unreachable? idk, terminal events are strange
}
code = match buf[4] {
`A` { KeyCode.up }
`B` { KeyCode.down }
`C` { KeyCode.right }
`D` { KeyCode.left }
`F` { KeyCode.end }
`H` { KeyCode.home }
`P` { KeyCode.f1 }
`Q` { KeyCode.f2 }
`R` { KeyCode.f3 }
`S` { KeyCode.f4 }
else { code }
if buf[1] == `1` {
code = match buf[4] {
`A` { KeyCode.up }
`B` { KeyCode.down }
`C` { KeyCode.right }
`D` { KeyCode.left }
`F` { KeyCode.end }
`H` { KeyCode.home }
`P` { KeyCode.f1 }
`Q` { KeyCode.f2 }
`R` { KeyCode.f3 }
`S` { KeyCode.f4 }
else { code }
}
} else if buf[1] == `5` {
code = KeyCode.page_up
} else if buf[1] == `6` {
code = KeyCode.page_down
}
// && buf[3] >= `2` && buf[3] <= `8` && buf[4] >= `A` && buf[4] <= `D`
}
return &Event{ typ: .key_down, code: code, utf8: single, modifiers: modifiers }, end

View File

@@ -1,5 +1,6 @@
module ui
import os
import strings
pub struct Color {
@@ -18,6 +19,7 @@ pub fn (c Color) hex() string {
const (
bsu = '\x1bP=1s\x1b\\'
esu = '\x1bP=2s\x1b\\'
vno_bsu_esu = os.getenv('VNO_BSU_ESU').len>0
)
[inline]
@@ -32,9 +34,13 @@ pub fn (mut ctx Context) flush() {
// TODO
} $else {
// TODO: Diff the previous frame against this one, and only render things that changed?
C.write(C.STDOUT_FILENO, bsu.str, bsu.len)
C.write(C.STDOUT_FILENO, ctx.print_buf.data, ctx.print_buf.len)
C.write(C.STDOUT_FILENO, esu.str, esu.len)
if vno_bsu_esu {
C.write(C.STDOUT_FILENO, ctx.print_buf.data, ctx.print_buf.len)
} else {
C.write(C.STDOUT_FILENO, bsu.str, bsu.len)
C.write(C.STDOUT_FILENO, ctx.print_buf.data, ctx.print_buf.len)
C.write(C.STDOUT_FILENO, esu.str, esu.len)
}
ctx.print_buf.clear()
}
}