Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Redesigning the terminal event messages #6

Open
ndreynolds opened this issue Mar 29, 2019 · 0 comments
Open

Redesigning the terminal event messages #6

ndreynolds opened this issue Mar 29, 2019 · 0 comments

Comments

@ndreynolds
Copy link
Owner

ndreynolds commented Mar 29, 2019

Current Situtation

Currently, the runtime / event manager sends terminal events as messages to the application in the following format:

{:event, 
  %ExTermbox.Event{
    ch: 0, 
    h: 38, 
    key: 0, 
    mod: 0, 
    type: 2, 
    w: 147, 
    x: 0, 
    y: 0
  }}

The ExTermbox.Event struct is directly based off of the C struct from the termbox API, which uses integer codes for the event type, key (based on terminfo), modifier, character, etc.:

https://github.com/nsf/termbox/blob/master/src/termbox.h

So far, the recommended way to match events on a certain key has been to match the integer for that key by first looking up the constant, e.g.:

@ctrl_c Constants.key(:ctrl_c)

case message do
  {:event, %{key: @ctrl_c}} ->
    # handle ctrl-c keypress

This project evolved out of the termbox bindings library, so this event API made sense in the beginning.

Problems

Constants are clumsy

Looking up constants and storing them in an attribute just to pattern match on them feels clumsy and is an unnecessary extra step. It should be possible to simplify the above as such:

case message do
  {:event, %{key: :ctrl_c}} ->
    # handle ctrl-c keypress

However, one issue with this is that some keys are defined to have the same integer value. For example, ctrl-~ (tilde) and ctrl-2 are both set to 0x00. Which begs the question: which one do we set as key above?

Not integrated with views and rendering

So far, events are completely separate from the views. The "target" of an event is always the terminal. I think we can do better than that. If I click on a label element, it should be possible for the rendering library to figure out that I've clicked that element and expose that information via the event.

Union type has a lot of extraneous information

The event struct is really a sort of union type---each event has a different type and depending on the type, certain information will be filled in and other information will be blank. From a usability standpoint, this can be very confusing.

Ideas

Extended events

In order to (mostly) maintain backwards compatibility, we could take the existing ExTermbox.Event{} struct and extend it with computed information, e.g.:

%Ratatouille.Event{
  ch: 0,
  key: 1,
  key_name: :ctrl_a,
  mod: 0,
  mod_name: :alt,
  type: 1,
  type_name: :key,
  w: 0,
  h: 0,
  x: 0,
  y: 0,
  target: nil
}

AFAIK, it would only break code that explicitly matches the struct (vs. matching any map with the keys).

New event structs by type (Breaking change)

Another approach would be to totally overhaul it in a new major version:

%Ratatouille.KeyEvent{
  key: :a,
  mod: :alt,
  key_code: 0,
  character_code: 97
}

%Ratatouille.MouseEvent{
  x: 21,
  y: 56,
  target: %Element{tag: :label, ...}
}

%Ratatouille.ResizeEvent{
  width: 45,
  height: 21
}

These would also be sent as messages in a new style:

{:key, %KeyEvent{}}
{:mouse, %MouseEvent{}}
{:resize, %ResizeEvent{}}

Other Ideas ???

Next Steps

I'd like to get some feedback and let the problem simmer for a while before I start changing anything.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant