-
Notifications
You must be signed in to change notification settings - Fork 5
InputSystem
This file is concerned only with the fe-text
version of irssi (that is, the
standard tty client), and investigates the inner workings of the binding,
dispatch and key handling code.
YMMV.
If you register a signal of the form key <key_name>
where <key_name>
is
one of the functions listed with /bind -list
, you can trigger that action
by subsequent emission of the signal.
For example:
/bind meta-q /se signal_register({'key backward_history' => \
[qw/string string int/]}); signal_emit('key backward_history', '', 0, 0)
In practice, the signal only needs to be registered once (is persistent across
a whole irssi process instance, and survives even /script reset
)
TODO: Are the arguments important? The majority of key_*
function
definitions in gui-readline.c
are prototyped void, but some
(key_change_window(const char *data)
, key_completion(int erase, int backward)
) are exceptions. Not sure how they'd take to being called in a
horrible way like this.
- Is it possible to listen for signals for complex key events by binding
a key sequence to
key <foo>
, and then observing thekey <foo>
signal? Apparently not, so far.
Interestingly, /eval /bind meta-q key bacon; /bind bacon /echo bacon pressed
appears to work - indicating that arbitrary key names can be used.
- Using
"key nothing"
as a hook seems to work. Registered with a singlestring
argument:
Irssi::signal_register({'key nothing' => [qw/string/]});
Irssi::signal_add_first('key nothing' => \\&sig_key_nothing);
Irssi::command("bind meta-q nothing SOMESTRING");
sub sig_key_nothing {
my ($data) = @_;
print "key nothing: " . Dumper($data);
}
Not perfect (still have to observe every "key nothing"
, rather than a single
"key mykey"
, but definitely progress.
Main files:
keyboard
keyboard.c
keyboard.h
gui-readline
gui-readline.c
gui-readline.h
Associated Signals:
- "
keyboard created
" - "
keyboard destroyed
" - "
key created
" - "
key destroyed
" - "
keyinfo created
" - "
keyinfo destroyed
" - "
key <keyname>
" - "
gui key pressed
"
Data Structures:
-
char *key_state; /* the ongoing key combo */
void *gui_data; /* GUI specific data sent in "key pressed" signal */
-
char *id;
char *description;
GSList
*keys, *default_keys;
-
KEYINFO_REC *info;
char *key;
char *data;
The following is a high-level description of the keyboard and binding system.
The GLib event-loop that irssi operates around detects keystroke input. Each
key triggers a gui key pressed
signal, which is then further
gui-readline
is responsible for creating and owning the KEYBOARD_REC
instance. The keyboard instance is created in gui_readline_init()
, setting
rec->gui_data
to NULL. rec->key_state
isn't initialised.
Only a single keyboard instance is ever created. The creation causes the
emission of a "keyboard created
" signal, but this occurs before the perl
script interpreter is loaded, and hence cannot be captured for use in scripts.
Once the keyboard object is created, is it populated with the default bindings,
still within the gui_readline_init()
function. A simple lock-style
function-pair (key_configure_freeze()
, key_configure_thaw()
) allows the
manipulation of large numbers of key entries at once without running the costly
key_states_rescan()
function each time.
void
key_bind
(const char *id, const char *description, const char *key_default, const char *data, SIGNAL_FUNC func)
is the entry-point for setting up both bindings, and the actions which bindings perform. An example of each:
key_bind("key", NULL, " ", "space", (SIGNAL_FUNC) key_combo);
key_bind("backward_character", "Move the cursor a character backward", "left", NULL, (SIGNAL_FUNC) key_backward_character);
There seem to be a few things a key can be bound to:
-
command
-- fires a"key command"
signal when the bound key-seq is pressed. -
key
-- alias one key to another. Seems to operate below the signal dispatch level. -
multi
-- allow multiple actions, separated by;
. -
nothing
-- Do...Nothing.
sig_gui_key_pressed
sig_gui_key_pressed
is the entry point to the key dispatcher, as a low-level
signal handler listening for "gui key pressed"
signals. It checks if keyboard
entry is being redirected (for example, the password entry mode of /oper
). If
so, throws it off to handle_key_redirect
, which we'll ignore for now.
Otherwise, it checks the value of the pressed key, and does various things
depending on what it is. The interesting bits seem to be a char str[20]
buffer, into which the key is "symbolically" decoded.
If it's a control character (key < 32
), it's prepended with a ^
, and the
value + 64 is used. So 0x01 -> "^A"
, etc.
If key == 127
, it's converted to "^?"
, the generally accepted sequence for
backspace.
Failing both those cases, some utf-8 decoding magic happens, upon which we
probably have a symbolic char representation in str
.
The string is then passed to key_pressed()
in keyboard.c
, unless it was
preceeded by an escape char, in which case it's just inserted into the input
line. If the return value key_pressed() < 0
, the lookup is assumed to have
not matched, and the key is again inserted into the input line as a fallback.
TODO: Note about key repeat when key_pressed() == 0
.
key_pressed
things.
Much of the content on these pages is taken from original Irssi documentation and is Copyright © 2000-2010 The Irssi project. Formatting and additional documentation, examples, etc by Tom Feist and the other editors of this wiki. This work is licensed under a Creative Commons Attribution-ShareAlike 2.5 License. Please see http://creativecommons.org/licenses/by-sa/2.5/ for details.