123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284 |
- // License: GPLv3 Copyright: 2023, Kovid Goyal, <kovid at kovidgoyal.net>
- package loop
- import (
- "fmt"
- "strconv"
- "strings"
- )
- var _ = fmt.Print
- type MouseEventType uint
- type MouseButtonFlag uint
- const (
- MOUSE_PRESS MouseEventType = iota
- MOUSE_RELEASE
- MOUSE_MOVE
- MOUSE_CLICK
- )
- func (e MouseEventType) String() string {
- switch e {
- case MOUSE_PRESS:
- return "press"
- case MOUSE_RELEASE:
- return "release"
- case MOUSE_MOVE:
- return "move"
- case MOUSE_CLICK:
- return "click"
- }
- return strconv.Itoa(int(e))
- }
- type PointerShape uint8
- const (
- // start pointer shape enum (auto generated by gen-key-constants.py do not edit)
- DEFAULT_POINTER PointerShape = 0
- TEXT_POINTER PointerShape = 1
- POINTER_POINTER PointerShape = 2
- HELP_POINTER PointerShape = 3
- WAIT_POINTER PointerShape = 4
- PROGRESS_POINTER PointerShape = 5
- CROSSHAIR_POINTER PointerShape = 6
- CELL_POINTER PointerShape = 7
- VERTICAL_TEXT_POINTER PointerShape = 8
- MOVE_POINTER PointerShape = 9
- E_RESIZE_POINTER PointerShape = 10
- NE_RESIZE_POINTER PointerShape = 11
- NW_RESIZE_POINTER PointerShape = 12
- N_RESIZE_POINTER PointerShape = 13
- SE_RESIZE_POINTER PointerShape = 14
- SW_RESIZE_POINTER PointerShape = 15
- S_RESIZE_POINTER PointerShape = 16
- W_RESIZE_POINTER PointerShape = 17
- EW_RESIZE_POINTER PointerShape = 18
- NS_RESIZE_POINTER PointerShape = 19
- NESW_RESIZE_POINTER PointerShape = 20
- NWSE_RESIZE_POINTER PointerShape = 21
- ZOOM_IN_POINTER PointerShape = 22
- ZOOM_OUT_POINTER PointerShape = 23
- ALIAS_POINTER PointerShape = 24
- COPY_POINTER PointerShape = 25
- NOT_ALLOWED_POINTER PointerShape = 26
- NO_DROP_POINTER PointerShape = 27
- GRAB_POINTER PointerShape = 28
- GRABBING_POINTER PointerShape = 29
- // end pointer shape enum
- )
- func (e PointerShape) String() string {
- switch e {
- // start pointer shape tostring (auto generated by gen-key-constants.py do not edit)
- case DEFAULT_POINTER:
- return "default"
- case TEXT_POINTER:
- return "text"
- case POINTER_POINTER:
- return "pointer"
- case HELP_POINTER:
- return "help"
- case WAIT_POINTER:
- return "wait"
- case PROGRESS_POINTER:
- return "progress"
- case CROSSHAIR_POINTER:
- return "crosshair"
- case CELL_POINTER:
- return "cell"
- case VERTICAL_TEXT_POINTER:
- return "vertical-text"
- case MOVE_POINTER:
- return "move"
- case E_RESIZE_POINTER:
- return "e-resize"
- case NE_RESIZE_POINTER:
- return "ne-resize"
- case NW_RESIZE_POINTER:
- return "nw-resize"
- case N_RESIZE_POINTER:
- return "n-resize"
- case SE_RESIZE_POINTER:
- return "se-resize"
- case SW_RESIZE_POINTER:
- return "sw-resize"
- case S_RESIZE_POINTER:
- return "s-resize"
- case W_RESIZE_POINTER:
- return "w-resize"
- case EW_RESIZE_POINTER:
- return "ew-resize"
- case NS_RESIZE_POINTER:
- return "ns-resize"
- case NESW_RESIZE_POINTER:
- return "nesw-resize"
- case NWSE_RESIZE_POINTER:
- return "nwse-resize"
- case ZOOM_IN_POINTER:
- return "zoom-in"
- case ZOOM_OUT_POINTER:
- return "zoom-out"
- case ALIAS_POINTER:
- return "alias"
- case COPY_POINTER:
- return "copy"
- case NOT_ALLOWED_POINTER:
- return "not-allowed"
- case NO_DROP_POINTER:
- return "no-drop"
- case GRAB_POINTER:
- return "grab"
- case GRABBING_POINTER:
- return "grabbing"
- // end pointer shape tostring
- }
- return strconv.Itoa(int(e))
- }
- const (
- SHIFT_INDICATOR int = 1 << 2
- ALT_INDICATOR = 1 << 3
- CTRL_INDICATOR = 1 << 4
- MOTION_INDICATOR = 1 << 5
- )
- const (
- NO_MOUSE_BUTTON MouseButtonFlag = 0
- LEFT_MOUSE_BUTTON MouseButtonFlag = 1 << iota
- MIDDLE_MOUSE_BUTTON
- RIGHT_MOUSE_BUTTON
- FOURTH_MOUSE_BUTTON
- FIFTH_MOUSE_BUTTON
- SIXTH_MOUSE_BUTTON
- SEVENTH_MOUSE_BUTTON
- MOUSE_WHEEL_UP
- MOUSE_WHEEL_DOWN
- MOUSE_WHEEL_LEFT
- MOUSE_WHEEL_RIGHT
- )
- var bmap = [...]MouseButtonFlag{LEFT_MOUSE_BUTTON, MIDDLE_MOUSE_BUTTON, RIGHT_MOUSE_BUTTON}
- var ebmap = [...]MouseButtonFlag{FOURTH_MOUSE_BUTTON, FIFTH_MOUSE_BUTTON, SIXTH_MOUSE_BUTTON, SEVENTH_MOUSE_BUTTON}
- var wbmap = [...]MouseButtonFlag{MOUSE_WHEEL_UP, MOUSE_WHEEL_DOWN, MOUSE_WHEEL_LEFT, MOUSE_WHEEL_RIGHT}
- func (b MouseButtonFlag) String() string {
- ans := ""
- switch {
- case b&LEFT_MOUSE_BUTTON != 0:
- ans += "|LEFT"
- case b&MIDDLE_MOUSE_BUTTON != 0:
- ans += "|MIDDLE"
- case b&RIGHT_MOUSE_BUTTON != 0:
- ans += "|RIGHT"
- case b&FOURTH_MOUSE_BUTTON != 0:
- ans += "|FOURTH"
- case b&FIFTH_MOUSE_BUTTON != 0:
- ans += "|FIFTH"
- case b&SIXTH_MOUSE_BUTTON != 0:
- ans += "|SIXTH"
- case b&SEVENTH_MOUSE_BUTTON != 0:
- ans += "|SEVENTH"
- case b&MOUSE_WHEEL_UP != 0:
- ans += "|WHEEL_UP"
- case b&MOUSE_WHEEL_DOWN != 0:
- ans += "|WHEEL_DOWN"
- case b&MOUSE_WHEEL_LEFT != 0:
- ans += "|WHEEL_LEFT"
- case b&MOUSE_WHEEL_RIGHT != 0:
- ans += "|WHEEL_RIGHT"
- }
- ans = strings.TrimLeft(ans, "|")
- if ans == "" {
- ans = "NONE"
- }
- return ans
- }
- type MouseEvent struct {
- Event_type MouseEventType
- Buttons MouseButtonFlag
- Mods KeyModifiers
- Cell, Pixel struct{ X, Y int }
- }
- func (e MouseEvent) String() string {
- return fmt.Sprintf("MouseEvent{%s %s %s Cell:%v Pixel:%v}", e.Event_type, e.Buttons, e.Mods, e.Cell, e.Pixel)
- }
- func pixel_to_cell(px, length, cell_length int) int {
- px = max(0, min(px, length-1))
- if cell_length > 0 {
- return px / cell_length
- }
- return 0
- }
- func decode_sgr_mouse(text string, screen_size ScreenSize) *MouseEvent {
- last_letter := text[len(text)-1]
- text = text[:len(text)-1]
- parts := strings.Split(text, ";")
- if len(parts) != 3 {
- return nil
- }
- cb, err := strconv.Atoi(parts[0])
- if err != nil {
- return nil
- }
- ans := MouseEvent{}
- ans.Pixel.X, err = strconv.Atoi(parts[1])
- if err != nil {
- return nil
- }
- if len(parts[2]) < 1 {
- return nil
- }
- if ans.Pixel.Y, err = strconv.Atoi(parts[2]); err != nil {
- return nil
- }
- if last_letter == 'm' {
- ans.Event_type = MOUSE_RELEASE
- } else if cb&MOTION_INDICATOR != 0 {
- ans.Event_type = MOUSE_MOVE
- }
- cb3 := cb & 3
- if cb >= 128 {
- ans.Buttons |= ebmap[cb3]
- } else if cb >= 64 {
- ans.Buttons |= wbmap[cb3]
- } else if cb3 < 3 {
- ans.Buttons |= bmap[cb3]
- }
- if cb&SHIFT_INDICATOR != 0 {
- ans.Mods |= SHIFT
- }
- if cb&ALT_INDICATOR != 0 {
- ans.Mods |= ALT
- }
- if cb&CTRL_INDICATOR != 0 {
- ans.Mods |= CTRL
- }
- ans.Cell.X = pixel_to_cell(ans.Pixel.X, int(screen_size.WidthPx), int(screen_size.CellWidth))
- ans.Cell.Y = pixel_to_cell(ans.Pixel.Y, int(screen_size.HeightPx), int(screen_size.CellHeight))
- return &ans
- }
- func MouseEventFromCSI(csi string, screen_size ScreenSize) *MouseEvent {
- if len(csi) == 0 {
- return nil
- }
- last_char := csi[len(csi)-1]
- if last_char != 'm' && last_char != 'M' {
- return nil
- }
- if !strings.HasPrefix(csi, "<") {
- return nil
- }
- return decode_sgr_mouse(csi[1:], screen_size)
- }
|