diff --git a/examples/term.ui/event_viewer.v b/examples/term.ui/event_viewer.v index 585faabd8f..f9c443fd87 100644 --- a/examples/term.ui/event_viewer.v +++ b/examples/term.ui/event_viewer.v @@ -12,15 +12,15 @@ fn event(e &tui.Event, x voidptr) { app.tui.write('V term.input event viewer (press `esc` to exit)\n\n') app.tui.write('$e') app.tui.write('\n\nRaw event bytes: "$e.utf8.bytes().hex()" = $e.utf8.bytes()') - if e.modifiers != 0 { + if !e.modifiers.is_empty() { app.tui.write('\nModifiers: $e.modifiers = ') - if e.modifiers & tui.ctrl != 0 { + if e.modifiers.has(.ctrl) { app.tui.write('ctrl. ') } - if e.modifiers & tui.shift != 0 { + if e.modifiers.has(.shift) { app.tui.write('shift ') } - if e.modifiers & tui.alt != 0 { + if e.modifiers.has(.alt) { app.tui.write('alt. ') } } diff --git a/examples/term.ui/term_drawing.v b/examples/term.ui/term_drawing.v index e6fd25880f..285cc87d90 100644 --- a/examples/term.ui/term_drawing.v +++ b/examples/term.ui/term_drawing.v @@ -174,8 +174,8 @@ fn event(event &ui.Event, x voidptr) { y: event.y } d := event.direction == .down - if event.modifiers & ui.ctrl != 0 { - p := event.modifiers & ui.shift == 0 + if event.modifiers.has(.ctrl) { + p := !event.modifiers.has(.shift) c := if d { if p { app.primary_color_idx - 1 } else { app.secondary_color_idx - 1 } } else { @@ -212,43 +212,53 @@ fn event(event &ui.Event, x voidptr) { } app.paint(nevent) } - .space { + .space, .enter { oevent := *event nevent := ui.Event{ ...oevent - button: ui.MouseButton.middle + button: .left + x: app.mouse_pos.x + y: app.mouse_pos.y + } + app.paint(nevent) + } + .delete, .backspace { + oevent := *event + nevent := ui.Event{ + ...oevent + button: .middle x: app.mouse_pos.x y: app.mouse_pos.y } app.paint(nevent) } .j, .down { - if event.modifiers & ui.shift != 0 { + if event.modifiers.has(.shift) { app.set_pixel((1 + app.mouse_pos.x) / 2, app.mouse_pos.y, app.primary_color) } app.mouse_pos.y++ } .k, .up { - if event.modifiers & ui.shift != 0 { + if event.modifiers.has(.shift) { app.set_pixel((1 + app.mouse_pos.x) / 2, app.mouse_pos.y, app.primary_color) } app.mouse_pos.y-- } .h, .left { - if event.modifiers & ui.shift != 0 { + if event.modifiers.has(.shift) { app.set_pixel((1 + app.mouse_pos.x) / 2, app.mouse_pos.y, app.primary_color) } app.mouse_pos.x -= 2 } .l, .right { - if event.modifiers & ui.shift != 0 { + if event.modifiers.has(.shift) { app.set_pixel((1 + app.mouse_pos.x) / 2, app.mouse_pos.y, app.primary_color) } app.mouse_pos.x += 2 } .t { - p := event.modifiers & ui.alt == 0 - c := if event.modifiers & ui.shift != 0 { + p := !event.modifiers.has(.alt) + c := if event.modifiers.has(.shift) { if p { app.primary_color_idx - 19 } else { app.secondary_color_idx - 19 } } else { if p { app.primary_color_idx + 19 } else { app.secondary_color_idx + 19 } @@ -256,8 +266,8 @@ fn event(event &ui.Event, x voidptr) { app.select_color(p, c) } .r { - p := event.modifiers & ui.alt == 0 - c := if event.modifiers & ui.shift != 0 { + p := !event.modifiers.has(.alt) + c := if event.modifiers.has(.shift) { if p { app.primary_color_idx - 1 } else { app.secondary_color_idx - 1 } } else { if p { app.primary_color_idx + 1 } else { app.secondary_color_idx + 1 } diff --git a/examples/term.ui/text_editor.v b/examples/term.ui/text_editor.v index 74ac41789d..a08efa59be 100644 --- a/examples/term.ui/text_editor.v +++ b/examples/term.ui/text_editor.v @@ -515,17 +515,17 @@ fn event(e &tui.Event, x voidptr) { buffer.del(1) } .left { - if e.modifiers == tui.ctrl { + if e.modifiers == .ctrl { buffer.move_to_word(.left) - } else if e.modifiers == 0 { + } else if e.modifiers.is_empty() { buffer.move_cursor(1, .left) } a.magnet_x = buffer.cursor.pos_x } .right { - if e.modifiers == tui.ctrl { + if e.modifiers == .ctrl { buffer.move_to_word(.right) - } else if e.modifiers == 0 { + } else if e.modifiers.is_empty() { buffer.move_cursor(1, .right) } a.magnet_x = buffer.cursor.pos_x @@ -551,16 +551,16 @@ fn event(e &tui.Event, x voidptr) { buffer.move_cursor(1, .end) } 48...57, 97...122 { // 0-9a-zA-Z - if e.modifiers == tui.ctrl { + if e.modifiers == .ctrl { if e.code == .s { a.save() } - } else if e.modifiers in [tui.shift, 0] && e.code != .null { + } else if !(e.modifiers.has(.ctrl | .alt) || e.code == .null) { buffer.put(e.ascii.ascii_str()) } } else { - if e.modifiers == tui.alt { + if e.modifiers == .alt { if e.code == .comma { a.visit_prev_file() return diff --git a/vlib/term/ui/README.md b/vlib/term/ui/README.md index 81a9756523..6bce054123 100644 --- a/vlib/term/ui/README.md +++ b/vlib/term/ui/README.md @@ -15,6 +15,9 @@ mut: fn event(e &tui.Event, x voidptr) { mut app := &App(x) println(e) + if e.typ == .key_down && e.code == .escape { + exit(0) + } } fn frame(x voidptr) { @@ -77,11 +80,6 @@ In the case of the various callbacks, they will not be fired if a handler has no #### FAQ -Q: Why does this module not work on Windows? -A: As with many other things, Windows has a completely different and incompatible way of handling -input parsing and drawing primitives, and support has not been implemented yet. -Contributions are definitely welcome though. - Q: My terminal (doesn't receive events / doesn't print anything / prints gibberish characters), what's up with that? A: Please check if your terminal. The module has been tested with `xterm`-based terminals on Linux diff --git a/vlib/term/ui/input.v b/vlib/term/ui/input.v index 4c89cc2bd1..839e67905c 100644 --- a/vlib/term/ui/input.v +++ b/vlib/term/ui/input.v @@ -122,12 +122,6 @@ pub enum KeyCode { f24 = 313 } -pub const ( - shift = u32(1 << 0) - ctrl = u32(1 << 1) - alt = u32(1 << 2) -) - pub enum Direction { unknown up @@ -154,6 +148,15 @@ pub enum EventType { resized } +[flag] +pub enum Modifiers { + ctrl + shift + alt +} + +[inline] pub fn (m &Modifiers) is_empty() bool { return int(m) == 0 } + pub struct Event { pub: typ EventType @@ -166,7 +169,7 @@ pub: // Keyboard event info code KeyCode - modifiers u32 + modifiers Modifiers ascii byte utf8 string diff --git a/vlib/term/ui/input_windows.c.v b/vlib/term/ui/input_windows.c.v index c87f314b80..ac4f9316b0 100644 --- a/vlib/term/ui/input_windows.c.v +++ b/vlib/term/ui/input_windows.c.v @@ -164,10 +164,10 @@ fn (mut ctx Context) parse_events() { else { KeyCode(ascii) } } - mut modifiers := u32(0) - if e.dwControlKeyState & (0x1 | 0x2) != 0 { modifiers |= alt } - if e.dwControlKeyState & (0x4 | 0x8) != 0 { modifiers |= ctrl } - if e.dwControlKeyState & 0x10 != 0 { modifiers |= shift } + mut modifiers := Modifiers{} + if e.dwControlKeyState & (0x1 | 0x2) != 0 { modifiers.set(.alt) } + if e.dwControlKeyState & (0x4 | 0x8) != 0 { modifiers.set(.ctrl) } + if e.dwControlKeyState & 0x10 != 0 { modifiers.set(.shift) } mut event := &Event{ typ: .key_down @@ -188,10 +188,10 @@ fn (mut ctx Context) parse_events() { } x := e.dwMousePosition.X + 1 y := int(e.dwMousePosition.Y) - sb_info.srWindow.Top + 1 - mut modifiers := u32(0) - if e.dwControlKeyState & (0x1 | 0x2) != 0 { modifiers |= alt } - if e.dwControlKeyState & (0x4 | 0x8) != 0 { modifiers |= ctrl } - if e.dwControlKeyState & 0x10 != 0 { modifiers |= shift } + mut modifiers := Modifiers{} + if e.dwControlKeyState & (0x1 | 0x2) != 0 { modifiers.set(.alt) } + if e.dwControlKeyState & (0x4 | 0x8) != 0 { modifiers.set(.ctrl) } + if e.dwControlKeyState & 0x10 != 0 { modifiers.set(.shift) } // TODO: handle capslock/numlock/etc?? events exist for those keys match int(e.dwEventFlags) { C.MOUSE_MOVED { diff --git a/vlib/term/ui/termios_nix.c.v b/vlib/term/ui/termios_nix.c.v index 267fc4da05..cb0b0873b3 100644 --- a/vlib/term/ui/termios_nix.c.v +++ b/vlib/term/ui/termios_nix.c.v @@ -283,8 +283,8 @@ fn single_char(buf string) &Event { match ch { // special handling for `ctrl + letter` // TODO: Fix assoc in V and remove this workaround :/ - // 1 ... 26 { event = Event{ ...event, code: KeyCode(96 | ch), modifiers: ctrl } } - // 65 ... 90 { event = Event{ ...event, code: KeyCode(32 | ch), modifiers: shift } } + // 1 ... 26 { event = Event{ ...event, code: KeyCode(96 | ch), modifiers: .ctrl } } + // 65 ... 90 { event = Event{ ...event, code: KeyCode(32 | ch), modifiers: .shift } } // The bit `or`s here are really just `+`'s, just written in this way for a tiny performance improvement // don't treat tab, enter as ctrl+i, ctrl+j 1...8, 11...26 { event = &Event{ @@ -292,14 +292,14 @@ fn single_char(buf string) &Event { ascii: event.ascii utf8: event.utf8 code: KeyCode(96 | ch) - modifiers: ctrl + modifiers: .ctrl } } 65...90 { event = &Event{ typ: event.typ ascii: event.ascii utf8: event.utf8 code: KeyCode(32 | ch) - modifiers: shift + modifiers: .shift } } else {} } @@ -351,13 +351,14 @@ fn escape_sequence(buf_ string) (&Event, int) { if buf.len == 1 { c := single_char(buf) - + mut modifiers := c.modifiers + modifiers.set(.alt) return &Event{ typ: c.typ ascii: c.ascii code: c.code utf8: single - modifiers: c.modifiers | alt + modifiers: modifiers }, 2 } // ---------------- @@ -374,15 +375,15 @@ fn escape_sequence(buf_ string) (&Event, int) { lo := typ & 0b00011 hi := typ & 0b11100 - mut modifiers := u32(0) + mut modifiers := Modifiers{} if hi & 4 != 0 { - modifiers |= shift + modifiers.set(.shift) } if hi & 8 != 0 { - modifiers |= alt + modifiers.set(.alt) } if hi & 16 != 0 { - modifiers |= ctrl + modifiers.set(.ctrl) } match typ { @@ -444,7 +445,7 @@ fn escape_sequence(buf_ string) (&Event, int) { // ---------------------------- mut code := KeyCode.null - mut modifiers := u32(0) + mut modifiers := Modifiers{} match buf { '[A', 'OA' { code = .up } '[B', 'OB' { code = .down } @@ -473,35 +474,34 @@ fn escape_sequence(buf_ string) (&Event, int) { if buf == '[Z' { code = .tab - modifiers |= shift + modifiers.set(.shift) } if buf.len == 5 && buf[0] == `[` && buf[1].is_digit() && buf[2] == `;` { - // code = KeyCode(buf[4] + 197) - modifiers = match buf[3] { - `2` { shift } - `3` { alt } - `4` { shift | alt } - `5` { ctrl } - `6` { ctrl | shift } - `7` { ctrl | alt } - `8` { ctrl | alt | shift } - else { modifiers } // probably unreachable? idk, terminal events are strange + match buf[3] { + `2` { modifiers = .shift } + `3` { modifiers = .alt } + `4` { modifiers = .shift | .alt } + `5` { modifiers = .ctrl } + `6` { modifiers = .ctrl | .shift } + `7` { modifiers = .ctrl | .alt } + `8` { modifiers = .ctrl | .alt | .shift } + else {} } 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 } + match buf[4] { + `A` { code = KeyCode.up } + `B` { code = KeyCode.down } + `C` { code = KeyCode.right } + `D` { code = KeyCode.left } + `F` { code = KeyCode.end } + `H` { code = KeyCode.home } + `P` { code = KeyCode.f1 } + `Q` { code = KeyCode.f2 } + `R` { code = KeyCode.f3 } + `S` { code = KeyCode.f4 } + else {} } } else if buf[1] == `5` { code = KeyCode.page_up diff --git a/vlib/v/parser/parser.v b/vlib/v/parser/parser.v index bf5536282a..7277a379ca 100644 --- a/vlib/v/parser/parser.v +++ b/vlib/v/parser/parser.v @@ -2200,10 +2200,10 @@ fn (mut p Parser) enum_decl() ast.EnumDecl { pubfn := if p.mod == 'main' { 'fn' } else { 'pub fn' } p.scanner.codegen(' // -$pubfn ( e &$enum_name) has(flag $enum_name) bool { return (int(*e) & (int(flag))) != 0 } -$pubfn (mut e $enum_name) set(flag $enum_name) { unsafe{ *e = ${enum_name}(int(*e) | (int(flag))) } } -$pubfn (mut e $enum_name) clear(flag $enum_name) { unsafe{ *e = ${enum_name}(int(*e) & ~(int(flag))) } } -$pubfn (mut e $enum_name) toggle(flag $enum_name) { unsafe{ *e = ${enum_name}(int(*e) ^ (int(flag))) } } +[inline] $pubfn ( e &$enum_name) has(flag $enum_name) bool { return (int(*e) & (int(flag))) != 0 } +[inline] $pubfn (mut e $enum_name) set(flag $enum_name) { unsafe{ *e = ${enum_name}(int(*e) | (int(flag))) } } +[inline] $pubfn (mut e $enum_name) clear(flag $enum_name) { unsafe{ *e = ${enum_name}(int(*e) & ~(int(flag))) } } +[inline] $pubfn (mut e $enum_name) toggle(flag $enum_name) { unsafe{ *e = ${enum_name}(int(*e) ^ (int(flag))) } } // ') }