mirror of
https://github.com/ghostty-org/ghostty.git
synced 2025-07-15 08:16:13 +03:00
core: start on key2Callback for the new callback that uses KeyEncoder
This commit is contained in:
@ -1139,39 +1139,78 @@ pub fn charCallback(
|
|||||||
try self.io_thread.wakeup.notify();
|
try self.io_thread.wakeup.notify();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A key input event.
|
pub fn key2Callback(
|
||||||
pub const KeyEvent = struct {
|
self: *Surface,
|
||||||
/// The action: press, release, etc.
|
event: input.KeyEvent,
|
||||||
action: input.Action,
|
) !bool {
|
||||||
|
// Before encoding, we see if we have any keybindings for this
|
||||||
|
// key. Those always intercept before any encoding tasks.
|
||||||
|
if (event.action == .press or event.action == .repeat) {
|
||||||
|
const binding_mods = event.mods.effectiveMods().binding();
|
||||||
|
const binding_action_: ?input.Binding.Action = action: {
|
||||||
|
var trigger: input.Binding.Trigger = .{
|
||||||
|
.mods = binding_mods,
|
||||||
|
.key = event.key,
|
||||||
|
};
|
||||||
|
|
||||||
/// "key" is the logical key that was pressed. For example, if
|
const set = self.config.keybind.set;
|
||||||
/// a Dvorak keyboard layout is being used on a US keyboard,
|
if (set.get(trigger)) |v| break :action v;
|
||||||
/// the "i" physical key will be reported as "c". The physical
|
|
||||||
/// key is the key that was physically pressed on the keyboard.
|
|
||||||
key: input.Key,
|
|
||||||
physical_key: input.Key,
|
|
||||||
|
|
||||||
/// Mods are the modifiers that are pressed.
|
trigger.key = event.physical_key;
|
||||||
mods: input.Mods,
|
trigger.physical = true;
|
||||||
|
if (set.get(trigger)) |v| break :action v;
|
||||||
|
|
||||||
/// The mods that were consumed in order to generate the text
|
break :action null;
|
||||||
/// in utf8. This has the mods set that were consumed, so to
|
};
|
||||||
/// get the set of mods that are effective you must negate
|
|
||||||
/// mods with this.
|
|
||||||
///
|
|
||||||
/// This field is meaningless if utf8 is empty.
|
|
||||||
consumed_mods: input.Mods,
|
|
||||||
|
|
||||||
/// Composing is true when this key event is part of a dead key
|
if (binding_action_) |binding_action| {
|
||||||
/// composition sequence and we're in the middle of it.
|
//log.warn("BINDING ACTION={}", .{binding_action});
|
||||||
composing: bool,
|
try self.performBindingAction(binding_action);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// The utf8 sequence that was generated by this key event.
|
// No binding, so we have to perform an encoding task. This
|
||||||
/// This will be an empty string if there is no text generated.
|
// may still result in no encoding. Under different modes and
|
||||||
/// If composing is true and this is non-empty, this is preedit
|
// inputs there are many keybindings that result in no encoding
|
||||||
/// text.
|
// whatsoever.
|
||||||
utf8: []const u8,
|
const enc: input.KeyEncoder = enc: {
|
||||||
};
|
self.renderer_state.mutex.lock();
|
||||||
|
defer self.renderer_state.mutex.unlock();
|
||||||
|
const t = &self.io.terminal;
|
||||||
|
break :enc .{
|
||||||
|
.event = event,
|
||||||
|
.alt_esc_prefix = t.modes.get(.alt_esc_prefix),
|
||||||
|
.cursor_key_application = t.modes.get(.cursor_keys),
|
||||||
|
.keypad_key_application = t.modes.get(.keypad_keys),
|
||||||
|
.modify_other_keys_state_2 = t.flags.modify_other_keys_2,
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
var data: termio.Message.WriteReq.Small.Array = undefined;
|
||||||
|
const seq = try enc.legacy(&data);
|
||||||
|
if (seq.len == 0) return false;
|
||||||
|
|
||||||
|
_ = self.io_thread.mailbox.push(.{
|
||||||
|
.write_small = .{
|
||||||
|
.data = data,
|
||||||
|
.len = seq.len,
|
||||||
|
},
|
||||||
|
}, .{ .forever = {} });
|
||||||
|
try self.io_thread.wakeup.notify();
|
||||||
|
|
||||||
|
// If we have a sequence to emit then we always want to clear the
|
||||||
|
// selection and scroll to the bottom.
|
||||||
|
{
|
||||||
|
self.renderer_state.mutex.lock();
|
||||||
|
defer self.renderer_state.mutex.unlock();
|
||||||
|
self.setSelection(null);
|
||||||
|
try self.io.terminal.scrollViewport(.{ .bottom = {} });
|
||||||
|
try self.queueRender();
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
/// Called for a single key event.
|
/// Called for a single key event.
|
||||||
///
|
///
|
||||||
|
@ -25,7 +25,7 @@ modify_other_keys_state_2: bool = false,
|
|||||||
/// These together combine the legacy protocol because they're all
|
/// These together combine the legacy protocol because they're all
|
||||||
/// meant to be extensions that do not change any existing behavior
|
/// meant to be extensions that do not change any existing behavior
|
||||||
/// and therefore safe to combine.
|
/// and therefore safe to combine.
|
||||||
fn legacy(
|
pub fn legacy(
|
||||||
self: *const KeyEncoder,
|
self: *const KeyEncoder,
|
||||||
buf: []u8,
|
buf: []u8,
|
||||||
) ![]const u8 {
|
) ![]const u8 {
|
||||||
|
Reference in New Issue
Block a user