Current section
Files
Jump to
Current section
Files
src/etch@event.erl
-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 => <<?FILEPATH/utf8>>,
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 => <<?FILEPATH/utf8>>,
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 => <<?FILEPATH/utf8>>,
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 => <<?FILEPATH/utf8>>,
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(<<Esc_acc/binary, C/binary>>),
List_acc@2 = [Event | List_acc],
parse_events(Rest@2, <<""/utf8>>, List_acc@2, false);
_ ->
parse_events(
Rest@2,
<<Esc_acc/binary, C/binary>>,
List_acc,
true
)
end;
{[S | Rest@3], false} ->
List_acc@3 = [{ok, {key, default_key_event({char, S})}} | List_acc],
parse_events(
Rest@3,
<<Esc_acc/binary, S/binary>>,
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>>.