macos: don't do full surface-style key translation for imgui

This commit is contained in:
Mitchell Hashimoto
2023-10-19 14:40:11 -07:00
parent b2fd3fae6c
commit 92d172377e
5 changed files with 124 additions and 201 deletions

View File

@ -413,7 +413,7 @@ void ghostty_inspector_set_size(ghostty_inspector_t, uint32_t, uint32_t);
void ghostty_inspector_mouse_button(ghostty_inspector_t, ghostty_input_mouse_state_e, ghostty_input_mouse_button_e, ghostty_input_mods_e);
void ghostty_inspector_mouse_pos(ghostty_inspector_t, double, double);
void ghostty_inspector_mouse_scroll(ghostty_inspector_t, double, double, ghostty_input_scroll_mods_t);
void ghostty_inspector_key(ghostty_inspector_t, ghostty_input_action_e, uint32_t, ghostty_input_mods_e);
void ghostty_inspector_key(ghostty_inspector_t, ghostty_input_action_e, ghostty_input_key_e, ghostty_input_mods_e);
void ghostty_inspector_text(ghostty_inspector_t, const char *);
// APIs I'd like to get rid of eventually but are still needed for now.

View File

@ -235,5 +235,122 @@ extension Ghostty {
0x3B: GHOSTTY_KEY_SEMICOLON,
0x2F: GHOSTTY_KEY_SLASH,
]
// Mapping of event keyCode to ghostty input key values. This is cribbed from
// glfw mostly since we started as a glfw-based app way back in the day!
static let keycodeToKey: [UInt16 : ghostty_input_key_e] = [
0x1D: GHOSTTY_KEY_ZERO,
0x12: GHOSTTY_KEY_ONE,
0x13: GHOSTTY_KEY_TWO,
0x14: GHOSTTY_KEY_THREE,
0x15: GHOSTTY_KEY_FOUR,
0x17: GHOSTTY_KEY_FIVE,
0x16: GHOSTTY_KEY_SIX,
0x1A: GHOSTTY_KEY_SEVEN,
0x1C: GHOSTTY_KEY_EIGHT,
0x19: GHOSTTY_KEY_NINE,
0x00: GHOSTTY_KEY_A,
0x0B: GHOSTTY_KEY_B,
0x08: GHOSTTY_KEY_C,
0x02: GHOSTTY_KEY_D,
0x0E: GHOSTTY_KEY_E,
0x03: GHOSTTY_KEY_F,
0x05: GHOSTTY_KEY_G,
0x04: GHOSTTY_KEY_H,
0x22: GHOSTTY_KEY_I,
0x26: GHOSTTY_KEY_J,
0x28: GHOSTTY_KEY_K,
0x25: GHOSTTY_KEY_L,
0x2E: GHOSTTY_KEY_M,
0x2D: GHOSTTY_KEY_N,
0x1F: GHOSTTY_KEY_O,
0x23: GHOSTTY_KEY_P,
0x0C: GHOSTTY_KEY_Q,
0x0F: GHOSTTY_KEY_R,
0x01: GHOSTTY_KEY_S,
0x11: GHOSTTY_KEY_T,
0x20: GHOSTTY_KEY_U,
0x09: GHOSTTY_KEY_V,
0x0D: GHOSTTY_KEY_W,
0x07: GHOSTTY_KEY_X,
0x10: GHOSTTY_KEY_Y,
0x06: GHOSTTY_KEY_Z,
0x27: GHOSTTY_KEY_APOSTROPHE,
0x2A: GHOSTTY_KEY_BACKSLASH,
0x2B: GHOSTTY_KEY_COMMA,
0x18: GHOSTTY_KEY_EQUAL,
0x32: GHOSTTY_KEY_GRAVE_ACCENT,
0x21: GHOSTTY_KEY_LEFT_BRACKET,
0x1B: GHOSTTY_KEY_MINUS,
0x2F: GHOSTTY_KEY_PERIOD,
0x1E: GHOSTTY_KEY_RIGHT_BRACKET,
0x29: GHOSTTY_KEY_SEMICOLON,
0x2C: GHOSTTY_KEY_SLASH,
0x33: GHOSTTY_KEY_BACKSPACE,
0x39: GHOSTTY_KEY_CAPS_LOCK,
0x75: GHOSTTY_KEY_DELETE,
0x7D: GHOSTTY_KEY_DOWN,
0x77: GHOSTTY_KEY_END,
0x24: GHOSTTY_KEY_ENTER,
0x35: GHOSTTY_KEY_ESCAPE,
0x7A: GHOSTTY_KEY_F1,
0x78: GHOSTTY_KEY_F2,
0x63: GHOSTTY_KEY_F3,
0x76: GHOSTTY_KEY_F4,
0x60: GHOSTTY_KEY_F5,
0x61: GHOSTTY_KEY_F6,
0x62: GHOSTTY_KEY_F7,
0x64: GHOSTTY_KEY_F8,
0x65: GHOSTTY_KEY_F9,
0x6D: GHOSTTY_KEY_F10,
0x67: GHOSTTY_KEY_F11,
0x6F: GHOSTTY_KEY_F12,
0x69: GHOSTTY_KEY_PRINT_SCREEN,
0x6B: GHOSTTY_KEY_F14,
0x71: GHOSTTY_KEY_F15,
0x6A: GHOSTTY_KEY_F16,
0x40: GHOSTTY_KEY_F17,
0x4F: GHOSTTY_KEY_F18,
0x50: GHOSTTY_KEY_F19,
0x5A: GHOSTTY_KEY_F20,
0x73: GHOSTTY_KEY_HOME,
0x72: GHOSTTY_KEY_INSERT,
0x7B: GHOSTTY_KEY_LEFT,
0x3A: GHOSTTY_KEY_LEFT_ALT,
0x3B: GHOSTTY_KEY_LEFT_CONTROL,
0x38: GHOSTTY_KEY_LEFT_SHIFT,
0x37: GHOSTTY_KEY_LEFT_SUPER,
0x47: GHOSTTY_KEY_NUM_LOCK,
0x79: GHOSTTY_KEY_PAGE_DOWN,
0x74: GHOSTTY_KEY_PAGE_UP,
0x7C: GHOSTTY_KEY_RIGHT,
0x3D: GHOSTTY_KEY_RIGHT_ALT,
0x3E: GHOSTTY_KEY_RIGHT_CONTROL,
0x3C: GHOSTTY_KEY_RIGHT_SHIFT,
0x36: GHOSTTY_KEY_RIGHT_SUPER,
0x31: GHOSTTY_KEY_SPACE,
0x30: GHOSTTY_KEY_TAB,
0x7E: GHOSTTY_KEY_UP,
0x52: GHOSTTY_KEY_KP_0,
0x53: GHOSTTY_KEY_KP_1,
0x54: GHOSTTY_KEY_KP_2,
0x55: GHOSTTY_KEY_KP_3,
0x56: GHOSTTY_KEY_KP_4,
0x57: GHOSTTY_KEY_KP_5,
0x58: GHOSTTY_KEY_KP_6,
0x59: GHOSTTY_KEY_KP_7,
0x5B: GHOSTTY_KEY_KP_8,
0x5C: GHOSTTY_KEY_KP_9,
0x45: GHOSTTY_KEY_KP_ADD,
0x41: GHOSTTY_KEY_KP_DECIMAL,
0x4B: GHOSTTY_KEY_KP_DIVIDE,
0x4C: GHOSTTY_KEY_KP_ENTER,
0x51: GHOSTTY_KEY_KP_EQUAL,
0x43: GHOSTTY_KEY_KP_MULTIPLY,
0x4E: GHOSTTY_KEY_KP_SUBTRACT,
];
}

View File

@ -260,16 +260,7 @@ extension Ghostty {
override func keyDown(with event: NSEvent) {
let action = event.isARepeat ? GHOSTTY_ACTION_REPEAT : GHOSTTY_ACTION_PRESS
keyAction(action, event: event)
// We specifically DO NOT call interpretKeyEvents because ghostty_surface_key
// automatically handles all key translation, and we don't handle any commands
// currently.
//
// It is possible that in the future we'll have to modify ghostty_surface_key
// and the embedding API so that we can call this because macOS needs to do
// some things with certain keys. I'm not sure. For now this works.
//
// self.interpretKeyEvents([event])
self.interpretKeyEvents([event])
}
override func keyUp(with event: NSEvent) {
@ -300,8 +291,9 @@ extension Ghostty {
private func keyAction(_ action: ghostty_input_action_e, event: NSEvent) {
guard let inspector = self.inspector else { return }
guard let key = Ghostty.keycodeToKey[event.keyCode] else { return }
let mods = Ghostty.ghosttyMods(event.modifierFlags)
ghostty_inspector_key(inspector, action, UInt32(event.keyCode), mods)
ghostty_inspector_key(inspector, action, key, mods)
}
// MARK: NSTextInputClient

View File

@ -865,123 +865,6 @@ extension Ghostty {
print("SEL: \(selector)")
}
// Mapping of event keyCode to ghostty input key values. This is cribbed from
// glfw mostly since we started as a glfw-based app way back in the day!
static let keycodes: [UInt16 : ghostty_input_key_e] = [
0x1D: GHOSTTY_KEY_ZERO,
0x12: GHOSTTY_KEY_ONE,
0x13: GHOSTTY_KEY_TWO,
0x14: GHOSTTY_KEY_THREE,
0x15: GHOSTTY_KEY_FOUR,
0x17: GHOSTTY_KEY_FIVE,
0x16: GHOSTTY_KEY_SIX,
0x1A: GHOSTTY_KEY_SEVEN,
0x1C: GHOSTTY_KEY_EIGHT,
0x19: GHOSTTY_KEY_NINE,
0x00: GHOSTTY_KEY_A,
0x0B: GHOSTTY_KEY_B,
0x08: GHOSTTY_KEY_C,
0x02: GHOSTTY_KEY_D,
0x0E: GHOSTTY_KEY_E,
0x03: GHOSTTY_KEY_F,
0x05: GHOSTTY_KEY_G,
0x04: GHOSTTY_KEY_H,
0x22: GHOSTTY_KEY_I,
0x26: GHOSTTY_KEY_J,
0x28: GHOSTTY_KEY_K,
0x25: GHOSTTY_KEY_L,
0x2E: GHOSTTY_KEY_M,
0x2D: GHOSTTY_KEY_N,
0x1F: GHOSTTY_KEY_O,
0x23: GHOSTTY_KEY_P,
0x0C: GHOSTTY_KEY_Q,
0x0F: GHOSTTY_KEY_R,
0x01: GHOSTTY_KEY_S,
0x11: GHOSTTY_KEY_T,
0x20: GHOSTTY_KEY_U,
0x09: GHOSTTY_KEY_V,
0x0D: GHOSTTY_KEY_W,
0x07: GHOSTTY_KEY_X,
0x10: GHOSTTY_KEY_Y,
0x06: GHOSTTY_KEY_Z,
0x27: GHOSTTY_KEY_APOSTROPHE,
0x2A: GHOSTTY_KEY_BACKSLASH,
0x2B: GHOSTTY_KEY_COMMA,
0x18: GHOSTTY_KEY_EQUAL,
0x32: GHOSTTY_KEY_GRAVE_ACCENT,
0x21: GHOSTTY_KEY_LEFT_BRACKET,
0x1B: GHOSTTY_KEY_MINUS,
0x2F: GHOSTTY_KEY_PERIOD,
0x1E: GHOSTTY_KEY_RIGHT_BRACKET,
0x29: GHOSTTY_KEY_SEMICOLON,
0x2C: GHOSTTY_KEY_SLASH,
0x33: GHOSTTY_KEY_BACKSPACE,
0x39: GHOSTTY_KEY_CAPS_LOCK,
0x75: GHOSTTY_KEY_DELETE,
0x7D: GHOSTTY_KEY_DOWN,
0x77: GHOSTTY_KEY_END,
0x24: GHOSTTY_KEY_ENTER,
0x35: GHOSTTY_KEY_ESCAPE,
0x7A: GHOSTTY_KEY_F1,
0x78: GHOSTTY_KEY_F2,
0x63: GHOSTTY_KEY_F3,
0x76: GHOSTTY_KEY_F4,
0x60: GHOSTTY_KEY_F5,
0x61: GHOSTTY_KEY_F6,
0x62: GHOSTTY_KEY_F7,
0x64: GHOSTTY_KEY_F8,
0x65: GHOSTTY_KEY_F9,
0x6D: GHOSTTY_KEY_F10,
0x67: GHOSTTY_KEY_F11,
0x6F: GHOSTTY_KEY_F12,
0x69: GHOSTTY_KEY_PRINT_SCREEN,
0x6B: GHOSTTY_KEY_F14,
0x71: GHOSTTY_KEY_F15,
0x6A: GHOSTTY_KEY_F16,
0x40: GHOSTTY_KEY_F17,
0x4F: GHOSTTY_KEY_F18,
0x50: GHOSTTY_KEY_F19,
0x5A: GHOSTTY_KEY_F20,
0x73: GHOSTTY_KEY_HOME,
0x72: GHOSTTY_KEY_INSERT,
0x7B: GHOSTTY_KEY_LEFT,
0x3A: GHOSTTY_KEY_LEFT_ALT,
0x3B: GHOSTTY_KEY_LEFT_CONTROL,
0x38: GHOSTTY_KEY_LEFT_SHIFT,
0x37: GHOSTTY_KEY_LEFT_SUPER,
0x47: GHOSTTY_KEY_NUM_LOCK,
0x79: GHOSTTY_KEY_PAGE_DOWN,
0x74: GHOSTTY_KEY_PAGE_UP,
0x7C: GHOSTTY_KEY_RIGHT,
0x3D: GHOSTTY_KEY_RIGHT_ALT,
0x3E: GHOSTTY_KEY_RIGHT_CONTROL,
0x3C: GHOSTTY_KEY_RIGHT_SHIFT,
0x36: GHOSTTY_KEY_RIGHT_SUPER,
0x31: GHOSTTY_KEY_SPACE,
0x30: GHOSTTY_KEY_TAB,
0x7E: GHOSTTY_KEY_UP,
0x52: GHOSTTY_KEY_KP_0,
0x53: GHOSTTY_KEY_KP_1,
0x54: GHOSTTY_KEY_KP_2,
0x55: GHOSTTY_KEY_KP_3,
0x56: GHOSTTY_KEY_KP_4,
0x57: GHOSTTY_KEY_KP_5,
0x58: GHOSTTY_KEY_KP_6,
0x59: GHOSTTY_KEY_KP_7,
0x5B: GHOSTTY_KEY_KP_8,
0x5C: GHOSTTY_KEY_KP_9,
0x45: GHOSTTY_KEY_KP_ADD,
0x41: GHOSTTY_KEY_KP_DECIMAL,
0x4B: GHOSTTY_KEY_KP_DIVIDE,
0x4C: GHOSTTY_KEY_KP_ENTER,
0x51: GHOSTTY_KEY_KP_EQUAL,
0x43: GHOSTTY_KEY_KP_MULTIPLY,
0x4E: GHOSTTY_KEY_KP_SUBTRACT,
];
}
}

View File

@ -1010,65 +1010,9 @@ pub const Inspector = struct {
pub fn keyCallback(
self: *Inspector,
action: input.Action,
keycode: u32,
key: input.Key,
mods: input.Mods,
) !void {
// True if this is a key down event
const is_down = action == .press or action == .repeat;
// Translate our key using the keymap for our localized keyboard layout.
// We only translate for keydown events. Otherwise, we only care about
// the raw keycode.
var buf: [128]u8 = undefined;
const result: input.Keymap.Translation = if (is_down) translate: {
const result = try self.surface.app.keymap.translate(
&buf,
&self.keymap_state,
@intCast(keycode),
mods,
);
// If this is a dead key, then we're composing a character and
// we don't do anything.
if (result.composing) return;
// If the text is just a single non-printable ASCII character
// then we clear the text. We handle non-printables in the
// key encoder manual (such as tab, ctrl+c, etc.)
if (result.text.len == 1 and result.text[0] < 0x20) {
break :translate .{ .composing = false, .text = "" };
}
break :translate result;
} else .{ .composing = false, .text = "" };
// We want to get the physical unmapped key to process keybinds.
const physical_key = keycode: for (input.keycodes.entries) |entry| {
if (entry.native == keycode) break :keycode entry.key;
} else .invalid;
// If the resulting text has length 1 then we can take its key
// and attempt to translate it to a key enum and call the key callback.
// If the length is greater than 1 then we're going to call the
// charCallback.
//
// We also only do key translation if this is not a dead key.
const key = if (!result.composing) key: {
// If our physical key is a keypad key, we use that.
if (physical_key.keypad()) break :key physical_key;
// A completed key. If the length of the key is one then we can
// attempt to translate it to a key enum and call the key
// callback. First try plain ASCII.
if (result.text.len > 0) {
if (input.Key.fromASCII(result.text[0])) |key| {
break :key key;
}
}
break :key physical_key;
} else .invalid;
self.queueRender();
cimgui.c.igSetCurrentContext(self.ig_ctx);
const io: *cimgui.c.ImGuiIO = cimgui.c.igGetIO();
@ -1087,19 +1031,6 @@ pub const Inspector = struct {
action == .press or action == .repeat,
);
}
// Send any text
if (result.text.len > 0) text: {
const view = std.unicode.Utf8View.init(result.text) catch |err| {
log.warn("cannot build utf8 view over input: {}", .{err});
break :text;
};
var it = view.iterator();
while (it.nextCodepoint()) |cp| {
cimgui.c.ImGuiIO_AddInputCharacter(io, cp);
}
}
}
fn newFrame(self: *Inspector) !void {
@ -1462,12 +1393,12 @@ pub const CAPI = struct {
export fn ghostty_inspector_key(
ptr: *Inspector,
action: input.Action,
keycode: u32,
key: input.Key,
c_mods: c_int,
) void {
ptr.keyCallback(
action,
keycode,
key,
@bitCast(@as(
input.Mods.Backing,
@truncate(@as(c_uint, @bitCast(c_mods))),