mirror of
https://github.com/ghostty-org/ghostty.git
synced 2025-08-02 14:57:31 +03:00
input: add unicode bindings
This commit is contained in:
@ -333,11 +333,13 @@ typedef struct {
|
||||
typedef enum {
|
||||
GHOSTTY_TRIGGER_TRANSLATED,
|
||||
GHOSTTY_TRIGGER_PHYSICAL,
|
||||
GHOSTTY_TRIGGER_UNICODE,
|
||||
} ghostty_input_trigger_tag_e;
|
||||
|
||||
typedef union {
|
||||
ghostty_input_key_e translated;
|
||||
ghostty_input_key_e physical;
|
||||
uint32_t unicode;
|
||||
} ghostty_input_trigger_key_u;
|
||||
|
||||
typedef struct {
|
||||
|
@ -131,6 +131,9 @@ extension Ghostty {
|
||||
return nil
|
||||
}
|
||||
|
||||
case GHOSTTY_TRIGGER_UNICODE:
|
||||
equiv = String(trigger.key.unicode)
|
||||
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
|
@ -1205,6 +1205,15 @@ pub fn keyCallback(
|
||||
set.getConsumed(trigger),
|
||||
};
|
||||
|
||||
if (event.unshifted_codepoint > 0) {
|
||||
trigger.key = .{ .unicode = event.unshifted_codepoint };
|
||||
if (set.get(trigger)) |v| break :action .{
|
||||
v,
|
||||
trigger,
|
||||
set.getConsumed(trigger),
|
||||
};
|
||||
}
|
||||
|
||||
break :binding;
|
||||
};
|
||||
|
||||
|
@ -89,11 +89,7 @@ pub fn parse(raw_input: []const u8) !Binding {
|
||||
if (!std.mem.eql(u8, field.name, "invalid")) {
|
||||
if (std.mem.eql(u8, key_part, field.name)) {
|
||||
// Repeat not allowed
|
||||
if (result.key != .translated or
|
||||
result.key.translated != .invalid)
|
||||
{
|
||||
return Error.InvalidFormat;
|
||||
}
|
||||
if (!result.isKeyUnset()) return Error.InvalidFormat;
|
||||
|
||||
const keyval = @field(key.Key, field.name);
|
||||
result.key = if (physical)
|
||||
@ -105,6 +101,21 @@ pub fn parse(raw_input: []const u8) !Binding {
|
||||
}
|
||||
}
|
||||
|
||||
// If we're still unset and we have exactly one unicode
|
||||
// character then we can use that as a key.
|
||||
if (result.isKeyUnset()) unicode: {
|
||||
// Invalid UTF8 drops to invalid format
|
||||
const view = std.unicode.Utf8View.init(key_part) catch break :unicode;
|
||||
var it = view.iterator();
|
||||
|
||||
// No codepoints or multiple codepoints drops to invalid format
|
||||
const cp = it.nextCodepoint() orelse break :unicode;
|
||||
if (it.nextCodepoint() != null) break :unicode;
|
||||
|
||||
result.key = .{ .unicode = cp };
|
||||
continue :loop;
|
||||
}
|
||||
|
||||
// We didn't recognize this value
|
||||
return Error.InvalidFormat;
|
||||
}
|
||||
@ -524,6 +535,11 @@ pub const Trigger = struct {
|
||||
/// is used to bind to a physical key location rather than a translated
|
||||
/// key.
|
||||
physical: key.Key,
|
||||
|
||||
/// This is used for binding to keys that produce a certain unicode
|
||||
/// codepoint. This is useful for binding to keys that don't have a
|
||||
/// registered keycode with Ghostty.
|
||||
unicode: u21,
|
||||
};
|
||||
|
||||
/// The extern struct used for triggers in the C API.
|
||||
@ -535,14 +551,24 @@ pub const Trigger = struct {
|
||||
pub const Tag = enum(c_int) {
|
||||
translated,
|
||||
physical,
|
||||
unicode,
|
||||
};
|
||||
|
||||
pub const Key = extern union {
|
||||
translated: key.Key,
|
||||
physical: key.Key,
|
||||
unicode: u32,
|
||||
};
|
||||
};
|
||||
|
||||
/// Returns true if this trigger has no key set.
|
||||
pub fn isKeyUnset(self: Trigger) bool {
|
||||
return switch (self.key) {
|
||||
.translated => |v| v == .invalid,
|
||||
else => false,
|
||||
};
|
||||
}
|
||||
|
||||
/// Returns a hash code that can be used to uniquely identify this trigger.
|
||||
pub fn hash(self: Trigger) u64 {
|
||||
var hasher = std.hash.Wyhash.init(0);
|
||||
@ -558,6 +584,7 @@ pub const Trigger = struct {
|
||||
.key = switch (self.key) {
|
||||
.translated => |v| .{ .translated = v },
|
||||
.physical => |v| .{ .physical = v },
|
||||
.unicode => |v| .{ .unicode = @intCast(v) },
|
||||
},
|
||||
.mods = self.mods,
|
||||
};
|
||||
@ -583,6 +610,7 @@ pub const Trigger = struct {
|
||||
switch (self.key) {
|
||||
.translated => |k| try writer.print("{s}", .{@tagName(k)}),
|
||||
.physical => |k| try writer.print("physical:{s}", .{@tagName(k)}),
|
||||
.unicode => |c| try writer.print("{u}", .{c}),
|
||||
}
|
||||
}
|
||||
};
|
||||
@ -813,6 +841,15 @@ test "parse: triggers" {
|
||||
.action = .{ .ignore = {} },
|
||||
}, try parse("shift+physical:a=ignore"));
|
||||
|
||||
// unicode keys
|
||||
try testing.expectEqual(Binding{
|
||||
.trigger = .{
|
||||
.mods = .{ .shift = true },
|
||||
.key = .{ .unicode = 'ö' },
|
||||
},
|
||||
.action = .{ .ignore = {} },
|
||||
}, try parse("shift+ö=ignore"));
|
||||
|
||||
// unconsumed keys
|
||||
try testing.expectEqual(Binding{
|
||||
.trigger = .{
|
||||
|
Reference in New Issue
Block a user