-module(etch@event). -compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -define(FILEPATH, "src/etch/event.gleam"). -export([poll/1, read/0, to_string/1, parse_cursor_position/1, get_cursor_position/0, translate_functional_key_code/1, parse_modifier_to_state/1, starts_with_number/1, parse_keyboard_enhancement_flags/1, get_keyboard_enhancement_flags/0, parse_kind/1, parse_modifier_and_kind/1, enable_mouse_capture/0, disable_mouse_capture/0, parse_cb/1, parse_rxvt_mouse/1, parse_normal_mouse/1, parse_sgr_mouse/1, parse_modifiers/1, parse_u_encoded_key_code/1, parse_special_key_code/1, parse_modifier_key_code/1, handle_escape_code/1, parse_events/4, init_event_server/0, enable_focus_change/0, disable_focus_change/0, push_keyboard_enhancement_flags/1, pop_keyboard_enhancement_flags/0]). -export_type([event_error/0, keyboard_enhancement_flag/0, modifiers/0, mouse_button/0, mouse_event_kind/0, mouse_event/0, media_key_code/0, modifier_key_code/0, key_code/0, key_event_kind/0, key_event_state/0, key_event/0, event/0]). -if(?OTP_RELEASE >= 27). -define(MODULEDOC(Str), -moduledoc(Str)). -define(DOC(Str), -doc(Str)). -else. -define(MODULEDOC(Str), -compile([])). -define(DOC(Str), -compile([])). -endif. ?MODULEDOC( " This module provides functionality to capture different events like\n" " pressing keys, mouse movement etc.\n" " In order to be able to read events, [`init_event_server`](event.html#init_event_server)\n" " must be called at the start of the application. See `events` example.\n" " ```gleam\n" " pub fn main()\n" " stdout.execute([\n" " command.EnterRaw,\n" " ])\n" " init_event_server()\n" " loop()\n" "\n" " fn loop() {\n" " handle_input()\n" " loop()\n" " }\n" "\n" " fn handle_input() {\n" " case event.read() {\n" " Some(Ok(Mouse(m))) -> {\n" " stdout.execute([\n" " command.Println(\"Got mouse event\"),\n" " ])\n" " }\n" " Some(Ok(Key(s))) -> {\n" " stdout.execute([\n" " command.Println(\n" " \"Got key event: \\\"\" <> event.to_string(s.code) <> \"\\\"\",\n" " ),\n" " ])\n" " }\n" " }\n" " }\n" " Some(Error(_)) -> Nil\n" " None -> Nil\n" " }\n" " }\n" " ```\n" ). -type event_error() :: {failed_to_parse_event, binary()}. -type keyboard_enhancement_flag() :: disambiguate_escape_code | report_event_types | report_alternate_keys | report_all_keys_as_escape_code | report_associated_text. -type modifiers() :: {modifiers, boolean(), boolean(), boolean(), boolean(), boolean(), boolean()}. -type mouse_button() :: left | right | middle. -type mouse_event_kind() :: {down, mouse_button()} | {up, mouse_button()} | {drag, mouse_button()} | moved | scroll_down | scroll_up | scroll_left | scroll_right. -type mouse_event() :: {mouse_event, mouse_event_kind(), integer(), integer(), modifiers()}. -type media_key_code() :: play | pause | play_pause | reverse | stop | fast_forward | rewind | track_next | track_previous | record | lower_volume | raise_volume | mute_volume. -type modifier_key_code() :: left_shift | left_control | left_alt | left_super | left_hyper | left_meta | right_shift | right_control | right_alt | right_super | right_hyper | right_meta | iso_level3_shift | iso_level5_shift. -type key_code() :: {char, binary()} | up_arrow | left_arrow | down_arrow | right_arrow | home | 'end' | page_down | insert | delete | page_up | keypad_begin | enter | backspace | esc | {media, media_key_code()} | {modifier, modifier_key_code()} | {f, integer()} | caps_lock | scroll_lock | num_lock | print_screen | pause_key_code | tab | backtab | menu. -type key_event_kind() :: press | repeat | release. -type key_event_state() :: {key_event_state, boolean(), boolean(), boolean()}. -type key_event() :: {key_event, key_code(), modifiers(), key_event_kind(), key_event_state(), binary()}. -type event() :: focus_gained | focus_lost | {key, key_event()} | {mouse, mouse_event()} | {resize, integer(), integer()}. -file("src/etch/event.gleam", 220). ?DOC( " Checks if there is an [`Event`](event.html#Event) available.\n" " Returns None if no events were received within the timeout.\n" " See also [`read`](event.html#read).\n" ). -spec poll(integer()) -> gleam@option:option({ok, event()} | {error, event_error()}). poll(Timeout) -> event_ffi:poll(Timeout). -file("src/etch/event.gleam", 226). ?DOC( " Checks if there is an [`Event`](event.html#Event) available.\n" " Waits forever for an available event.\n" " See also [`poll`](event.html#poll).\n" ). -spec read() -> gleam@option:option({ok, event()} | {error, event_error()}). read() -> event_ffi:read(). -file("src/etch/event.gleam", 242). -spec push_events(list({ok, event()} | {error, event_error()})) -> nil. push_events(Events) -> case Events of [] -> nil; [E | Rest] -> event_ffi:push(E), push_events(Rest) end. -file("src/etch/event.gleam", 294). -spec default_key_event(key_code()) -> key_event(). default_key_event(Key_code) -> {key_event, Key_code, {modifiers, false, false, false, false, false, false}, press, {key_event_state, false, false, false}, <<""/utf8>>}. -file("src/etch/event.gleam", 305). ?DOC(" Convert [`KeyCode`](event.html#KeyCode) to a string.\n"). -spec to_string(key_code()) -> binary(). to_string(Key_code) -> case Key_code of {char, S} -> S; down_arrow -> <<"down arrow"/utf8>>; 'end' -> <<"end"/utf8>>; home -> <<"home"/utf8>>; left_arrow -> <<"left arrow"/utf8>>; right_arrow -> <<"right arrow"/utf8>>; up_arrow -> <<"up arrow"/utf8>>; {f, N} -> <<"F"/utf8, (erlang:integer_to_binary(N))/binary>>; page_down -> <<"page down"/utf8>>; page_up -> <<"page up"/utf8>>; insert -> <<"insert"/utf8>>; delete -> <<"delete"/utf8>>; caps_lock -> <<"capslock"/utf8>>; enter -> <<"enter"/utf8>>; keypad_begin -> <<"keypad begin"/utf8>>; {media, M} -> case M of fast_forward -> <<"fast forward"/utf8>>; lower_volume -> <<"lower volume"/utf8>>; mute_volume -> <<"mute volume"/utf8>>; pause -> <<"pause"/utf8>>; play -> <<"play"/utf8>>; play_pause -> <<"play-pause"/utf8>>; raise_volume -> <<"raise volume"/utf8>>; record -> <<"record"/utf8>>; reverse -> <<"reverse"/utf8>>; rewind -> <<"rewind"/utf8>>; stop -> <<"stop"/utf8>>; track_next -> <<"track next"/utf8>>; track_previous -> <<"track previous"/utf8>> end; menu -> <<"menu"/utf8>>; {modifier, M@1} -> case M@1 of iso_level3_shift -> <<"iso level-3 shift"/utf8>>; iso_level5_shift -> <<"iso level-5 shift"/utf8>>; left_alt -> <<"left alt"/utf8>>; left_control -> <<"left control"/utf8>>; left_hyper -> <<"left hyper"/utf8>>; left_meta -> <<"left meta"/utf8>>; left_shift -> <<"left shift"/utf8>>; left_super -> <<"left super"/utf8>>; right_alt -> <<"right alt"/utf8>>; right_control -> <<"right control"/utf8>>; right_hyper -> <<"right hyper"/utf8>>; right_meta -> <<"right meta"/utf8>>; right_shift -> <<"right shift"/utf8>>; right_super -> <<"right super"/utf8>> end; num_lock -> <<"num lock"/utf8>>; pause_key_code -> <<"pause"/utf8>>; print_screen -> <<"print screen"/utf8>>; scroll_lock -> <<"scroll lock"/utf8>>; esc -> <<"escape"/utf8>>; backspace -> <<"backspace"/utf8>>; backtab -> <<"backtab"/utf8>>; tab -> <<"tab"/utf8>> end. -file("src/etch/event.gleam", 428). ?DOC(false). -spec parse_cursor_position(binary()) -> {ok, {integer(), integer()}} | {error, event_error()}. parse_cursor_position(S) -> Code = gleam@string:drop_end(S, 1), Split = gleam@string:split(Code, <<";"/utf8>>), Res = case Split of [X, Y] -> {ok, {X, Y}}; _ -> {error, {failed_to_parse_event, <<"Failed to parse cursor position"/utf8>>}} end, gleam@result:'try'( Res, fun(_use0) -> {X@1, Y@1} = _use0, X@2 = begin _pipe = gleam_stdlib:parse_int(X@1), gleam@result:unwrap(_pipe, 0) end, Y@2 = begin _pipe@1 = gleam_stdlib:parse_int(Y@1), gleam@result:unwrap(_pipe@1, 0) end, {ok, {X@2, Y@2}} end ). -file("src/etch/event.gleam", 413). ?DOC( " Returns cursor position.\n" " Be careful when calling this function inside a loop where you are also listening for events.\n" " Some events may be lost.\n" ). -spec get_cursor_position() -> {ok, {integer(), integer()}} | {error, event_error()}. get_cursor_position() -> gleam_stdlib:print(<<"\x{001b}["/utf8, "6n"/utf8>>), Pos = io:get_chars(<<""/utf8>>, 32), case Pos of <<"\x{001b}["/utf8, S/binary>> -> case gleam@string:last(S) of {ok, <<"R"/utf8>>} -> parse_cursor_position(S); _ -> {error, {failed_to_parse_event, <<"Could not get cursor position"/utf8>>}} end; _ -> {error, {failed_to_parse_event, <<"Could not get cursor position"/utf8>>}} end. -file("src/etch/event.gleam", 543). ?DOC(false). -spec translate_functional_key_code(binary()) -> gleam@option:option({key_code(), key_event_state()}). translate_functional_key_code(Code) -> Keycode = case Code of <<"57399"/utf8>> -> {some, {char, <<"0"/utf8>>}}; <<"57400"/utf8>> -> {some, {char, <<"1"/utf8>>}}; <<"57401"/utf8>> -> {some, {char, <<"2"/utf8>>}}; <<"57402"/utf8>> -> {some, {char, <<"3"/utf8>>}}; <<"57403"/utf8>> -> {some, {char, <<"4"/utf8>>}}; <<"57404"/utf8>> -> {some, {char, <<"5"/utf8>>}}; <<"57405"/utf8>> -> {some, {char, <<"6"/utf8>>}}; <<"57406"/utf8>> -> {some, {char, <<"7"/utf8>>}}; <<"57407"/utf8>> -> {some, {char, <<"8"/utf8>>}}; <<"57408"/utf8>> -> {some, {char, <<"9"/utf8>>}}; <<"57409"/utf8>> -> {some, {char, <<"."/utf8>>}}; <<"57410"/utf8>> -> {some, {char, <<"/"/utf8>>}}; <<"57411"/utf8>> -> {some, {char, <<"*"/utf8>>}}; <<"57412"/utf8>> -> {some, {char, <<"-"/utf8>>}}; <<"57413"/utf8>> -> {some, {char, <<"+"/utf8>>}}; <<"57414"/utf8>> -> {some, enter}; <<"57415"/utf8>> -> {some, {char, <<"="/utf8>>}}; <<"57416"/utf8>> -> {some, {char, <<","/utf8>>}}; <<"57417"/utf8>> -> {some, left_arrow}; <<"57418"/utf8>> -> {some, right_arrow}; <<"57419"/utf8>> -> {some, up_arrow}; <<"57420"/utf8>> -> {some, down_arrow}; <<"57421"/utf8>> -> {some, page_up}; <<"57422"/utf8>> -> {some, page_down}; <<"57423"/utf8>> -> {some, home}; <<"57424"/utf8>> -> {some, 'end'}; <<"57425"/utf8>> -> {some, insert}; <<"57426"/utf8>> -> {some, delete}; <<"57427"/utf8>> -> {some, keypad_begin}; _ -> none end, case Keycode of {some, C} -> {some, {C, {key_event_state, false, false, true}}}; none -> Keycode@1 = case Code of <<"57358"/utf8>> -> {some, caps_lock}; <<"57359"/utf8>> -> {some, scroll_lock}; <<"57360"/utf8>> -> {some, num_lock}; <<"57361"/utf8>> -> {some, print_screen}; <<"57362"/utf8>> -> {some, pause_key_code}; <<"57363"/utf8>> -> {some, menu}; <<"57376"/utf8>> -> {some, {f, 13}}; <<"57377"/utf8>> -> {some, {f, 14}}; <<"57378"/utf8>> -> {some, {f, 15}}; <<"57379"/utf8>> -> {some, {f, 16}}; <<"57380"/utf8>> -> {some, {f, 17}}; <<"57381"/utf8>> -> {some, {f, 18}}; <<"57382"/utf8>> -> {some, {f, 19}}; <<"57383"/utf8>> -> {some, {f, 20}}; <<"57384"/utf8>> -> {some, {f, 21}}; <<"57385"/utf8>> -> {some, {f, 22}}; <<"57386"/utf8>> -> {some, {f, 23}}; <<"57387"/utf8>> -> {some, {f, 24}}; <<"57388"/utf8>> -> {some, {f, 25}}; <<"57389"/utf8>> -> {some, {f, 26}}; <<"57390"/utf8>> -> {some, {f, 27}}; <<"57391"/utf8>> -> {some, {f, 28}}; <<"57392"/utf8>> -> {some, {f, 29}}; <<"57393"/utf8>> -> {some, {f, 30}}; <<"57394"/utf8>> -> {some, {f, 31}}; <<"57395"/utf8>> -> {some, {f, 32}}; <<"57396"/utf8>> -> {some, {f, 33}}; <<"57397"/utf8>> -> {some, {f, 34}}; <<"57398"/utf8>> -> {some, {f, 35}}; <<"57428"/utf8>> -> {some, {media, play}}; <<"57429"/utf8>> -> {some, {media, pause}}; <<"57430"/utf8>> -> {some, {media, play_pause}}; <<"57431"/utf8>> -> {some, {media, reverse}}; <<"57432"/utf8>> -> {some, {media, stop}}; <<"57433"/utf8>> -> {some, {media, fast_forward}}; <<"57434"/utf8>> -> {some, {media, rewind}}; <<"57435"/utf8>> -> {some, {media, track_next}}; <<"57436"/utf8>> -> {some, {media, track_previous}}; <<"57437"/utf8>> -> {some, {media, record}}; <<"57438"/utf8>> -> {some, {media, lower_volume}}; <<"57439"/utf8>> -> {some, {media, raise_volume}}; <<"57440"/utf8>> -> {some, {media, mute_volume}}; <<"57441"/utf8>> -> {some, {modifier, left_shift}}; <<"57442"/utf8>> -> {some, {modifier, left_control}}; <<"57443"/utf8>> -> {some, {modifier, left_alt}}; <<"57444"/utf8>> -> {some, {modifier, left_super}}; <<"57445"/utf8>> -> {some, {modifier, left_hyper}}; <<"57446"/utf8>> -> {some, {modifier, left_meta}}; <<"57447"/utf8>> -> {some, {modifier, right_shift}}; <<"57448"/utf8>> -> {some, {modifier, right_control}}; <<"57449"/utf8>> -> {some, {modifier, right_alt}}; <<"57450"/utf8>> -> {some, {modifier, right_super}}; <<"57451"/utf8>> -> {some, {modifier, right_hyper}}; <<"57452"/utf8>> -> {some, {modifier, right_meta}}; <<"57453"/utf8>> -> {some, {modifier, iso_level3_shift}}; <<"57454"/utf8>> -> {some, {modifier, iso_level5_shift}}; _ -> none end, case Keycode@1 of none -> none; {some, C@1} -> {some, {C@1, {key_event_state, false, false, false}}} end end. -file("src/etch/event.gleam", 700). ?DOC(false). -spec parse_modifier_to_state(integer()) -> key_event_state(). parse_modifier_to_state(Modifier_mask) -> State = {key_event_state, false, false, false}, Mask = case Modifier_mask - 1 of N when N < 0 -> 0; N@1 -> N@1 end, State@1 = case erlang:'band'(Mask, 64) /= 0 of true -> {key_event_state, erlang:element(2, State), true, erlang:element(4, State)}; false -> State end, State@2 = case erlang:'band'(Mask, 128) /= 0 of true -> {key_event_state, erlang:element(2, State@1), erlang:element(3, State@1), true}; false -> State@1 end, State@2. -file("src/etch/event.gleam", 739). ?DOC(false). -spec starts_with_number(binary()) -> boolean(). starts_with_number(S) -> _pipe = gleam@string:first(S), _pipe@1 = gleam@result:unwrap(_pipe, <<""/utf8>>), _pipe@2 = gleam_stdlib:parse_int(_pipe@1), gleam@result:is_ok(_pipe@2). -file("src/etch/event.gleam", 764). ?DOC(false). -spec parse_keyboard_enhancement_flags(binary()) -> list(keyboard_enhancement_flag()). parse_keyboard_enhancement_flags(Code) -> Code@1 = begin _pipe = gleam@string:drop_end(Code, 1), _pipe@1 = gleam_stdlib:parse_int(_pipe), gleam@result:unwrap(_pipe@1, 0) end, List = [], List@1 = case erlang:'band'(Code@1, 1) /= 0 of true -> [disambiguate_escape_code | List]; false -> List end, List@2 = case erlang:'band'(Code@1, 2) /= 0 of true -> [report_event_types | List@1]; false -> List@1 end, List@3 = case erlang:'band'(Code@1, 4) /= 0 of true -> [report_alternate_keys | List@2]; false -> List@2 end, List@4 = case erlang:'band'(Code@1, 8) /= 0 of true -> [report_all_keys_as_escape_code | List@3]; false -> List@3 end, List@5 = case erlang:'band'(Code@1, 16) /= 0 of true -> [report_associated_text | List@4]; false -> List@4 end, List@5. -file("src/etch/event.gleam", 746). ?DOC( " Get keyboard enhancement flags. See https://sw.kovidgoyal.net/kitty/keyboard-protocol/#progressive-enhancement\n" " Be careful when calling this function inside a loop where you are also listening for events.\n" " Some events may be lost.\n" ). -spec get_keyboard_enhancement_flags() -> {ok, list(keyboard_enhancement_flag())} | {error, event_error()}. get_keyboard_enhancement_flags() -> gleam_stdlib:print(<<"\x{001b}["/utf8, "?u"/utf8>>), Flags = io:get_chars(<<""/utf8>>, 32), case Flags of <<"\x{001b}[?"/utf8, S/binary>> -> case gleam@string:last(S) of {ok, <<"u"/utf8>>} -> {ok, parse_keyboard_enhancement_flags(S)}; _ -> {error, {failed_to_parse_event, <<"Could not get cursor position"/utf8>>}} end; _ -> {error, {failed_to_parse_event, <<"Could not get cursor position"/utf8>>}} end. -file("src/etch/event.gleam", 840). ?DOC(false). -spec parse_kind(integer()) -> key_event_kind(). parse_kind(Kind) -> case Kind of 1 -> press; 2 -> repeat; 3 -> release; _ -> press end. -file("src/etch/event.gleam", 850). ?DOC(false). -spec parse_modifier_and_kind(binary()) -> {ok, {integer(), integer()}} | {error, event_error()}. parse_modifier_and_kind(Code) -> Split = gleam@string:split(Code, <<":"/utf8>>), case Split of [Modifier_mask, Kind_mask] -> Modifier_mask@1 = begin _pipe = gleam_stdlib:parse_int(Modifier_mask), gleam@result:unwrap(_pipe, 0) end, Kind_mask@1 = begin _pipe@1 = gleam_stdlib:parse_int(Kind_mask), gleam@result:unwrap(_pipe@1, 0) end, {ok, {Modifier_mask@1, Kind_mask@1}}; [Modifier_mask@2] -> Modifier_mask@3 = begin _pipe@2 = gleam_stdlib:parse_int(Modifier_mask@2), gleam@result:unwrap(_pipe@2, 0) end, {ok, {Modifier_mask@3, 0}}; _ -> {error, {failed_to_parse_event, <<"Failed to parse modifiers"/utf8>>}} end. -file("src/etch/event.gleam", 868). ?DOC( " Enables mouse capture.\n" " It is prefered not to use this directly. See [`EnableMouseCapture`](command.html#EnableMouseCapture).\n" ). -spec enable_mouse_capture() -> binary(). enable_mouse_capture() -> <<<<<<<<<<<<<<<<<<"\x{001b}["/utf8, "?1000h"/utf8>>/binary, "\x{001b}["/utf8>>/binary, "?1002h"/utf8>>/binary, "\x{001b}["/utf8>>/binary, "?1003h"/utf8>>/binary, "\x{001b}["/utf8>>/binary, "?1015h"/utf8>>/binary, "\x{001b}["/utf8>>/binary, "?1006h"/utf8>>. -file("src/etch/event.gleam", 883). ?DOC( " Disables mouse capture.\n" " It is prefered not to use this directly. See [`DisableMouseCapture`](command.html#DisableMouseCapture).\n" ). -spec disable_mouse_capture() -> binary(). disable_mouse_capture() -> <<<<<<<<<<<<<<<<<<"\x{001b}["/utf8, "?1000l"/utf8>>/binary, "\x{001b}["/utf8>>/binary, "?1002l"/utf8>>/binary, "\x{001b}["/utf8>>/binary, "?1003l"/utf8>>/binary, "\x{001b}["/utf8>>/binary, "?1015l"/utf8>>/binary, "\x{001b}["/utf8>>/binary, "?1006l"/utf8>>. -file("src/etch/event.gleam", 943). ?DOC(false). -spec parse_cb(binary()) -> {ok, {modifiers(), mouse_event_kind()}} | {error, event_error()}. parse_cb(Code) -> Code@1 = begin _pipe = gleam_stdlib:parse_int(Code), gleam@result:unwrap(_pipe, 0) end, Button_number = begin _pipe@1 = erlang:'band'(Code@1, 2#00000011), erlang:'bor'( _pipe@1, begin _pipe@2 = erlang:'band'(Code@1, 2#11000000), erlang:'bsr'(_pipe@2, 4) end ) end, Dragging = erlang:'band'(Code@1, 2#00100000) =:= 2#00100000, Modifiers = {modifiers, erlang:'band'(Code@1, 4) /= 0, erlang:'band'(Code@1, 8) /= 0, erlang:'band'(Code@1, 16) /= 0, erlang:'band'(Code@1, 32) /= 0, erlang:'band'(Code@1, 64) /= 0, erlang:'band'(Code@1, 128) /= 0}, Button = case Button_number of 0 -> left; 1 -> middle; _ -> right end, Res = case {Button_number, Dragging} of {0, false} -> {ok, {down, left}}; {1, false} -> {ok, {down, middle}}; {2, false} -> {ok, {down, right}}; {0, true} -> {ok, {drag, left}}; {1, true} -> {ok, {drag, middle}}; {2, true} -> {ok, {drag, right}}; {3, false} -> {ok, {up, left}}; {4, false} -> {ok, scroll_up}; {5, false} -> {ok, scroll_down}; {6, false} -> {ok, scroll_left}; {7, false} -> {ok, scroll_right}; {C, true} when ((C =:= 3) orelse (C =:= 4)) orelse (C =:= 5) -> {ok, moved}; {_, true} -> {ok, {drag, Button}}; {_, _} -> {error, {failed_to_parse_event, <<"Failed to parse sgr mouse code"/utf8>>}} end, gleam@result:'try'(Res, fun(Kind) -> {ok, {Modifiers, Kind}} end). -file("src/etch/event.gleam", 718). ?DOC(false). -spec parse_rxvt_mouse(binary()) -> {ok, event()} | {error, event_error()}. parse_rxvt_mouse(S) -> S@1 = gleam@string:drop_end(S, 1), Split = gleam@string:split(S@1, <<";"/utf8>>), Res = case Split of [Code, Column, Row] -> {ok, {Code, Column, Row}}; _ -> {error, {failed_to_parse_event, <<"Failed to parse sgr mouse code"/utf8>>}} end, gleam@result:'try'( Res, fun(_use0) -> {Code@1, Column@1, Row@1} = _use0, Column@2 = begin _pipe = gleam_stdlib:parse_int(Column@1), gleam@result:unwrap(_pipe, 0) end, Row@2 = begin _pipe@1 = gleam_stdlib:parse_int(Row@1), gleam@result:unwrap(_pipe@1, 0) end, Column@3 = Column@2 - 1, Row@3 = Row@2 - 1, gleam@result:'try'( parse_cb(Code@1), fun(_use0@1) -> {Modifiers, Kind} = _use0@1, {ok, {mouse, {mouse_event, Kind, Column@3, Row@3, Modifiers}}} end ) end ). -file("src/etch/event.gleam", 897). ?DOC(false). -spec parse_normal_mouse(binary()) -> {ok, event()} | {error, event_error()}. parse_normal_mouse(Code) -> Res = case gleam@string:to_graphemes(Code) of [Cb, Cx, Cy] -> {ok, {Cb, Cx, Cy}}; _ -> {error, {failed_to_parse_event, <<"Failed to parse normal mouse code"/utf8>>}} end, gleam@result:'try'( Res, fun(_use0) -> {Cb@1, Cx@1, Cy@1} = _use0, Column = begin _pipe = gleam_stdlib:parse_int(Cx@1), gleam@result:unwrap(_pipe, 0) end, Row = begin _pipe@1 = gleam_stdlib:parse_int(Cy@1), gleam@result:unwrap(_pipe@1, 0) end, gleam@result:'try'( parse_cb(Cb@1), fun(_use0@1) -> {Modifiers, Kind} = _use0@1, {ok, {mouse, {mouse_event, Kind, Column, Row, Modifiers}}} end ) end ). -file("src/etch/event.gleam", 913). ?DOC(false). -spec parse_sgr_mouse(binary()) -> {ok, event()} | {error, event_error()}. parse_sgr_mouse(S) -> Split = gleam@string:split(S, <<";"/utf8>>), Res = case Split of [Code, Column, Row] -> {ok, {Code, Column, Row}}; _ -> {error, {failed_to_parse_event, <<"Failed to parse sgr mouse code"/utf8>>}} end, gleam@result:'try'( Res, fun(_use0) -> {Code@1, Column@1, Row@1} = _use0, Column@2 = begin _pipe = gleam_stdlib:parse_int(Column@1), gleam@result:unwrap(_pipe, 0) end, Is_release = gleam_stdlib:string_ends_with(Row@1, <<"m"/utf8>>), Row@2 = begin _pipe@1 = gleam@string:drop_end(Row@1, 1), _pipe@2 = gleam_stdlib:parse_int(_pipe@1), gleam@result:unwrap(_pipe@2, 0) end, gleam@result:'try'( parse_cb(Code@1), fun(_use0@1) -> {Modifiers, Kind} = _use0@1, Kind@1 = case Is_release of true -> case Kind of {down, B} -> {up, B}; Other -> Other end; false -> Kind end, {ok, {mouse, {mouse_event, Kind@1, Column@2, Row@2, Modifiers}}} end ) end ). -file("src/etch/event.gleam", 991). ?DOC(false). -spec parse_modifiers(integer()) -> modifiers(). parse_modifiers(Code) -> Mask = case Code - 1 of X when X < 0 -> 0; X@1 -> X@1 end, {modifiers, erlang:'band'(Mask, 1) /= 0, erlang:'band'(Mask, 2) /= 0, erlang:'band'(Mask, 4) /= 0, erlang:'band'(Mask, 8) /= 0, erlang:'band'(Mask, 16) /= 0, erlang:'band'(Mask, 32) /= 0}. -file("src/etch/event.gleam", 442). ?DOC(false). -spec parse_u_encoded_key_code(binary()) -> {ok, event()} | {error, event_error()}. parse_u_encoded_key_code(Code) -> Code@1 = gleam@string:drop_end(Code, 1), Split = gleam@string:split(Code@1, <<";"/utf8>>), Res = case Split of [Code@2, Modifiers, Text] -> {ok, {Code@2, Modifiers, {some, Text}}}; [Code@3, Modifiers@1] -> {ok, {Code@3, Modifiers@1, none}}; [Code@4] -> {ok, {Code@4, <<"0"/utf8>>, none}}; _ -> {error, {failed_to_parse_event, <<"Failed to parse u encoded code (CSI <..> u)"/utf8>>}} end, gleam@result:'try'( Res, fun(_use0) -> {Code@5, Modifiers@2, Text@1} = _use0, Text@5 = case Text@1 of {some, Text@2} -> Text@4 = case begin _pipe = gleam_stdlib:parse_int(Text@2), _pipe@1 = gleam@result:unwrap(_pipe, 0), gleam@string:utf_codepoint(_pipe@1) end of {ok, Text@3} -> Text@3; _assert_fail -> erlang:error(#{gleam_error => let_assert, message => <<"Pattern match failed, no pattern matched the value."/utf8>>, file => <>, module => <<"etch/event"/utf8>>, function => <<"parse_u_encoded_key_code"/utf8>>, line => 456, value => _assert_fail, start => 10970, 'end' => 11077, pattern_start => 10981, pattern_end => 10989}) end, gleam_stdlib:utf_codepoint_list_to_string([Text@4]); none -> <<""/utf8>> end, Code_parts = gleam@string:split(Code@5, <<":"/utf8>>), Res@1 = case Code_parts of [Unicode, Alternate_code] -> {ok, {Unicode, {some, Alternate_code}}}; [Unicode@1] -> {ok, {Unicode@1, none}}; _ -> {error, {failed_to_parse_event, <<"Failed to parse u encoded code"/utf8>>}} end, gleam@result:'try'( Res@1, fun(_use0@1) -> {Code@6, Alternate_code@1} = _use0@1, gleam@result:'try'( parse_modifier_and_kind(Modifiers@2), fun(_use0@2) -> {Modifier_mask, Kind_mask} = _use0@2, {Modifiers@3, Kind, State_from_modifier} = {parse_modifiers( Modifier_mask ), parse_kind(Kind_mask), parse_modifier_to_state(Modifier_mask)}, {Keycode@2, State_from_keycode} = case translate_functional_key_code( Code@6 ) of {some, {Keycode, State}} -> {Keycode, State}; none -> C@1 = case begin _pipe@2 = gleam_stdlib:parse_int(Code@6), _pipe@3 = gleam@result:unwrap( _pipe@2, 0 ), gleam@string:utf_codepoint(_pipe@3) end of {ok, C} -> C; _assert_fail@1 -> erlang:error( #{gleam_error => let_assert, message => <<"Pattern match failed, no pattern matched the value."/utf8>>, file => <>, module => <<"etch/event"/utf8>>, function => <<"parse_u_encoded_key_code"/utf8>>, line => 484, value => _assert_fail@1, start => 11838, 'end' => 11942, pattern_start => 11849, pattern_end => 11854} ) end, C@2 = gleam_stdlib:utf_codepoint_list_to_string( [C@1] ), Keycode@1 = case C@2 of <<"\r"/utf8>> -> enter; <<"\n"/utf8>> -> enter; <<"\x{001b}"/utf8>> -> esc; <<"\x{0007}"/utf8>> -> backspace; <<"\t"/utf8>> when erlang:element( 2, Modifiers@3 ) -> backtab; <<"\t"/utf8>> -> tab; C@3 -> {char, C@3} end, {Keycode@1, {key_event_state, false, false, false}} end, Modifiers@4 = case Keycode@2 of {modifier, X} when (X =:= left_alt) orelse (X =:= right_alt) -> {modifiers, erlang:element(2, Modifiers@3), true, erlang:element(4, Modifiers@3), erlang:element(5, Modifiers@3), erlang:element(6, Modifiers@3), erlang:element(7, Modifiers@3)}; {modifier, X@1} when (X@1 =:= left_shift) orelse (X@1 =:= right_shift) -> {modifiers, true, erlang:element(3, Modifiers@3), erlang:element(4, Modifiers@3), erlang:element(5, Modifiers@3), erlang:element(6, Modifiers@3), erlang:element(7, Modifiers@3)}; {modifier, X@2} when (X@2 =:= left_control) orelse (X@2 =:= right_control) -> {modifiers, erlang:element(2, Modifiers@3), erlang:element(3, Modifiers@3), true, erlang:element(5, Modifiers@3), erlang:element(6, Modifiers@3), erlang:element(7, Modifiers@3)}; {modifier, X@3} when (X@3 =:= left_super) orelse (X@3 =:= right_super) -> {modifiers, erlang:element(2, Modifiers@3), erlang:element(3, Modifiers@3), erlang:element(4, Modifiers@3), true, erlang:element(6, Modifiers@3), erlang:element(7, Modifiers@3)}; {modifier, X@4} when (X@4 =:= left_hyper) orelse (X@4 =:= right_hyper) -> {modifiers, erlang:element(2, Modifiers@3), erlang:element(3, Modifiers@3), erlang:element(4, Modifiers@3), erlang:element(5, Modifiers@3), true, erlang:element(7, Modifiers@3)}; {modifier, X@5} when (X@5 =:= left_meta) orelse (X@5 =:= right_meta) -> {modifiers, erlang:element(2, Modifiers@3), erlang:element(3, Modifiers@3), erlang:element(4, Modifiers@3), erlang:element(5, Modifiers@3), erlang:element(6, Modifiers@3), true}; _ -> Modifiers@3 end, Keycode@3 = case erlang:element(2, Modifiers@4) of false -> Keycode@2; true -> case Alternate_code@1 of {some, C@4} -> C@6 = case begin _pipe@4 = gleam_stdlib:parse_int( C@4 ), _pipe@5 = gleam@result:unwrap( _pipe@4, 0 ), gleam@string:utf_codepoint( _pipe@5 ) end of {ok, C@5} -> C@5; _assert_fail@2 -> erlang:error( #{gleam_error => let_assert, message => <<"Pattern match failed, no pattern matched the value."/utf8>>, file => <>, module => <<"etch/event"/utf8>>, function => <<"parse_u_encoded_key_code"/utf8>>, line => 523, value => _assert_fail@2, start => 13049, 'end' => 13162, pattern_start => 13060, pattern_end => 13065} ) end, C@7 = gleam_stdlib:utf_codepoint_list_to_string( [C@6] ), {char, C@7}; none -> Keycode@2 end end, State@1 = {key_event_state, erlang:element(2, State_from_modifier) orelse erlang:element( 2, State_from_keycode ), erlang:element(3, State_from_modifier) orelse erlang:element( 3, State_from_keycode ), erlang:element(4, State_from_modifier) orelse erlang:element( 4, State_from_keycode )}, {ok, {key, {key_event, Keycode@3, Modifiers@4, Kind, State@1, Text@5}}} end ) end ) end ). -file("src/etch/event.gleam", 649). ?DOC(false). -spec parse_special_key_code(binary()) -> {ok, event()} | {error, event_error()}. parse_special_key_code(Code) -> Code@1 = gleam@string:drop_end(Code, 1), Split = gleam@string:split(Code@1, <<";"/utf8>>), Res = case Split of [Key, Modifier] -> {ok, {Key, Modifier}}; [Key@1] -> {ok, {Key@1, <<"0"/utf8>>}}; _ -> {error, {failed_to_parse_event, <<"Failed to parse special key code (CSI <..> ~)"/utf8>>}} end, gleam@result:'try'( Res, fun(_use0) -> {Key@2, Modifier@1} = _use0, gleam@result:'try'( parse_modifier_and_kind(Modifier@1), fun(_use0@1) -> {Modifier_mask, Kind_mask} = _use0@1, {Modifiers, Kind, State} = {parse_modifiers(Modifier_mask), parse_kind(Kind_mask), parse_modifier_to_state(Modifier_mask)}, Key@3 = begin _pipe = gleam_stdlib:parse_int(Key@2), gleam@result:unwrap(_pipe, 1) end, Key@4 = case Key@3 of 1 -> {ok, home}; 7 -> {ok, home}; 2 -> {ok, insert}; 3 -> {ok, delete}; 4 -> {ok, 'end'}; 8 -> {ok, 'end'}; 5 -> {ok, page_up}; 6 -> {ok, page_down}; K -> case K of K@1 when (K@1 >= 11) andalso (K@1 =< 15) -> {ok, {f, K@1 - 10}}; K@2 when (K@2 >= 17) andalso (K@2 =< 21) -> {ok, {f, K@2 - 11}}; K@3 when (K@3 >= 23) andalso (K@3 =< 26) -> {ok, {f, K@3 - 12}}; 28 -> {ok, {f, K - 15}}; 29 -> {ok, {f, K - 15}}; K@4 when (K@4 >= 31) andalso (K@4 =< 34) -> {ok, {f, K@4 - 17}}; _ -> {error, {failed_to_parse_event, <<"Failed to parse special key code (CSI <..> ~)"/utf8>>}} end end, gleam@result:'try'( Key@4, fun(Key@5) -> {ok, {key, {key_event, Key@5, Modifiers, Kind, State, <<""/utf8>>}}} end ) end ) end ). -file("src/etch/event.gleam", 794). ?DOC(false). -spec parse_modifier_key_code(binary()) -> {ok, event()} | {error, event_error()}. parse_modifier_key_code(Code) -> Key = begin _pipe = gleam@string:last(Code), gleam@result:unwrap(_pipe, <<"fallback"/utf8>>) end, Code@1 = gleam@string:drop_end(Code, 1), Split = gleam@string:split(Code@1, <<";"/utf8>>), Res = case Split of [_, Modifiers] -> {ok, Modifiers}; _ -> {error, {failed_to_parse_event, <<"Failed to parse special key code (CSI <..> ~)"/utf8>>}} end, gleam@result:'try'( Res, fun(Modifiers@1) -> gleam@result:'try'( parse_modifier_and_kind(Modifiers@1), fun(_use0) -> {Modifier_mask, Kind_mask} = _use0, {Modifiers@2, Kind} = {parse_modifiers(Modifier_mask), parse_kind(Kind_mask)}, Res@1 = case Key of <<"A"/utf8>> -> {ok, up_arrow}; <<"B"/utf8>> -> {ok, down_arrow}; <<"C"/utf8>> -> {ok, right_arrow}; <<"D"/utf8>> -> {ok, left_arrow}; <<"F"/utf8>> -> {ok, 'end'}; <<"H"/utf8>> -> {ok, home}; <<"P"/utf8>> -> {ok, {f, 1}}; <<"Q"/utf8>> -> {ok, {f, 2}}; <<"R"/utf8>> -> {ok, {f, 3}}; <<"S"/utf8>> -> {ok, {f, 4}}; _ -> {error, {failed_to_parse_event, <<"Failed to parse modifier key code"/utf8>>}} end, gleam@result:'try'( Res@1, fun(Key@1) -> {ok, {key, {key_event, Key@1, Modifiers@2, Kind, {key_event_state, false, false, false}, <<""/utf8>>}}} end ) end ) end ). -file("src/etch/event.gleam", 368). ?DOC(false). -spec handle_escape_code(binary()) -> {ok, event()} | {error, event_error()}. handle_escape_code(S) -> case S of <<"A"/utf8>> -> {ok, {key, default_key_event(up_arrow)}}; <<"B"/utf8>> -> {ok, {key, default_key_event(down_arrow)}}; <<"C"/utf8>> -> {ok, {key, default_key_event(right_arrow)}}; <<"D"/utf8>> -> {ok, {key, default_key_event(left_arrow)}}; <<"H"/utf8>> -> {ok, {key, default_key_event(home)}}; <<"F"/utf8>> -> {ok, {key, default_key_event('end')}}; <<"O"/utf8>> -> {ok, focus_lost}; <<"I"/utf8>> -> {ok, focus_gained}; <<"M"/utf8, Code/binary>> -> parse_normal_mouse(Code); <<"<"/utf8, Code@1/binary>> -> parse_sgr_mouse(Code@1); <<";"/utf8, Code@2/binary>> -> parse_modifier_key_code(Code@2); <<"P"/utf8>> -> {ok, {key, default_key_event({f, 1})}}; <<"Q"/utf8>> -> {ok, {key, default_key_event({f, 2})}}; <<"S"/utf8>> -> {ok, {key, default_key_event({f, 4})}}; <<"?"/utf8, _/binary>> -> {error, {failed_to_parse_event, <<"Failed to parse escape code"/utf8>>}}; S@1 -> case starts_with_number(S@1) of true -> case gleam@string:last(S@1) of {ok, <<"M"/utf8>>} -> parse_rxvt_mouse(S@1); {ok, <<"~"/utf8>>} -> parse_special_key_code(S@1); {ok, <<"u"/utf8>>} -> parse_u_encoded_key_code(S@1); {ok, L} when L =/= <<"R"/utf8>> -> parse_modifier_key_code(S@1); _ -> {error, {failed_to_parse_event, <<"Unsupported numbered escape code"/utf8>>}} end; false -> {error, {failed_to_parse_event, <<"Failed to parse escape code"/utf8>>}} end end. -file("src/etch/event.gleam", 253). ?DOC(false). -spec parse_events( list(binary()), binary(), list({ok, event()} | {error, event_error()}), boolean() ) -> list({ok, event()} | {error, event_error()}). parse_events(Str, Esc_acc, List_acc, In_escape_sequence) -> case {Str, In_escape_sequence} of {[<<"\x{001b}"/utf8>>, <<"["/utf8>> | Rest], false} -> parse_events(Rest, <<""/utf8>>, List_acc, true); {[<<"\x{001b}"/utf8>>, <<"["/utf8>> | Rest@1], true} -> List_acc@1 = [{error, {failed_to_parse_event, <<"Unterminated escape sequence"/utf8>>}} | List_acc], parse_events(Rest@1, <<""/utf8>>, List_acc@1, true); {[C | Rest@2], true} -> X@1 = case begin _pipe = gleam@string:to_utf_codepoints(C), gleam@list:first(_pipe) end of {ok, X} -> X; _assert_fail -> erlang:error(#{gleam_error => let_assert, message => <<"Pattern match failed, no pattern matched the value."/utf8>>, file => <>, module => <<"etch/event"/utf8>>, function => <<"parse_events"/utf8>>, line => 271, value => _assert_fail, start => 5329, 'end' => 5391, pattern_start => 5340, pattern_end => 5345}) end, X@2 = gleam_stdlib:identity(X@1), case X@2 of X@3 when (X@3 >= 64) andalso (X@3 =< 126) -> Event = handle_escape_code(<>), List_acc@2 = [Event | List_acc], parse_events(Rest@2, <<""/utf8>>, List_acc@2, false); _ -> parse_events( Rest@2, <>, List_acc, true ) end; {[S | Rest@3], false} -> List_acc@3 = [{ok, {key, default_key_event({char, S})}} | List_acc], parse_events( Rest@3, <>, List_acc@3, false ); {[], _} -> lists:reverse(List_acc) end. -file("src/etch/event.gleam", 234). -spec input_loop() -> any(). input_loop() -> Str = io:get_chars(<<""/utf8>>, 1024), Str@1 = gleam@string:to_graphemes(Str), Events = begin _pipe = parse_events(Str@1, <<""/utf8>>, [], false), lists:reverse(_pipe) end, push_events(Events), input_loop(). -file("src/etch/event.gleam", 229). ?DOC(" Initializes the event server responsible for listening for events.\n"). -spec init_event_server() -> gleam@erlang@process:pid_(). init_event_server() -> event_ffi:start_link(), proc_lib:spawn_link(fun() -> input_loop() end). -file("src/etch/event.gleam", 1008). ?DOC( " Enables focus change.\n" " It is prefered not to use this directly. See [`EnableFocusChange`](command.html#EnableFocusChange).\n" ). -spec enable_focus_change() -> binary(). enable_focus_change() -> <<"\x{001b}["/utf8, "?1004h"/utf8>>. -file("src/etch/event.gleam", 1014). ?DOC( " Disables focus change.\n" " It is prefered not to use this directly. See [`DisableFocusChange`](command.html#DisableFocusChange).\n" ). -spec disable_focus_change() -> binary(). disable_focus_change() -> <<"\x{001b}["/utf8, "?1004l"/utf8>>. -file("src/etch/event.gleam", 1024). -spec push_keyboard_enhancement_flags_inner( list(keyboard_enhancement_flag()), integer() ) -> binary(). push_keyboard_enhancement_flags_inner(Flags, Acc) -> case Flags of [disambiguate_escape_code | Rest] -> push_keyboard_enhancement_flags_inner(Rest, Acc + 1); [report_event_types | Rest@1] -> push_keyboard_enhancement_flags_inner(Rest@1, Acc + 2); [report_alternate_keys | Rest@2] -> push_keyboard_enhancement_flags_inner(Rest@2, Acc + 4); [report_all_keys_as_escape_code | Rest@3] -> push_keyboard_enhancement_flags_inner(Rest@3, Acc + 8); [report_associated_text | Rest@4] -> push_keyboard_enhancement_flags_inner(Rest@4, Acc + 16); [] -> <<<<<<"\x{001b}["/utf8, ">"/utf8>>/binary, (erlang:integer_to_binary(Acc))/binary>>/binary, "u"/utf8>> end. -file("src/etch/event.gleam", 1020). ?DOC( " Pushes keyboard enhancement flags.\n" " It is prefered not to use this directly. See [`PushKeyboardEnhancementFlags`](command.html#PushKeyboardEnhancementFlags).\n" ). -spec push_keyboard_enhancement_flags(list(keyboard_enhancement_flag())) -> binary(). push_keyboard_enhancement_flags(Flags) -> push_keyboard_enhancement_flags_inner(Flags, 0). -file("src/etch/event.gleam", 1047). ?DOC( " Pops keyboard enhancement flags.\n" " It is prefered not to use this directly. See [`PopKeyboardEnhancementFlags`](command.html#PopKeyboardEnhancementFlags).\n" ). -spec pop_keyboard_enhancement_flags() -> binary(). pop_keyboard_enhancement_flags() -> <<"\x{001b}["/utf8, "<1u"/utf8>>.