|
|
@@ -50,13 +50,16 @@ void GtkWindowController::set_cursor_visible(bool visible) {
|
|
|
}
|
|
|
|
|
|
|
|
|
-std::string GtkWindowController::resolve_key(guint keyval, Gdk::ModifierType state) {
|
|
|
- // Handle modifier keys
|
|
|
- unsigned int state_uint = static_cast<unsigned int>(state);
|
|
|
- bool is_control = (state_uint & static_cast<unsigned int>(Gdk::ModifierType::CONTROL_MASK)) != 0;
|
|
|
-
|
|
|
- // Convert keyval to string
|
|
|
+bool GtkWindowController::on_key_pressed(guint keyval, guint /*keycode*/, Gdk::ModifierType state) {
|
|
|
+ if (!window_) return false;
|
|
|
+
|
|
|
+ // Make cursor visible immediately when typing
|
|
|
+ cursor_visible_ = true;
|
|
|
+ drawing_area_.queue_draw(); // Redraw immediately to show cursor
|
|
|
+
|
|
|
+ // 1. Convert GDK keyval and state to our canonical Key representation
|
|
|
std::string key_name;
|
|
|
+ // Special handling for some keys
|
|
|
switch (keyval) {
|
|
|
case GDK_KEY_Return: key_name = "Return"; break;
|
|
|
case GDK_KEY_Tab: key_name = "Tab"; break;
|
|
|
@@ -77,11 +80,6 @@ std::string GtkWindowController::resolve_key(guint keyval, Gdk::ModifierType sta
|
|
|
// Handle printable characters
|
|
|
if (keyval >= GDK_KEY_a && keyval <= GDK_KEY_z) {
|
|
|
key_name = std::string(1, static_cast<char>(keyval));
|
|
|
- if (is_control) {
|
|
|
- // Logic for Control keys if needed
|
|
|
- } else if ((state_uint & static_cast<unsigned int>(Gdk::ModifierType::SHIFT_MASK)) != 0) {
|
|
|
- key_name = std::string(1, static_cast<char>(keyval - (GDK_KEY_a - GDK_KEY_A)));
|
|
|
- }
|
|
|
} else if (keyval >= GDK_KEY_0 && keyval <= GDK_KEY_9) {
|
|
|
key_name = std::string(1, static_cast<char>(keyval));
|
|
|
} else if (keyval >= 32 && keyval <= 126) {
|
|
|
@@ -89,28 +87,23 @@ std::string GtkWindowController::resolve_key(guint keyval, Gdk::ModifierType sta
|
|
|
}
|
|
|
break;
|
|
|
}
|
|
|
- return key_name;
|
|
|
-}
|
|
|
|
|
|
-bool GtkWindowController::on_key_pressed(guint keyval, guint /*keycode*/, Gdk::ModifierType state) {
|
|
|
- if (!window_) return false;
|
|
|
+ if (key_name.empty()) return false; // Unhandled key
|
|
|
|
|
|
- // Make cursor visible immediately when typing
|
|
|
- cursor_visible_ = true;
|
|
|
- drawing_area_.queue_draw(); // Redraw immediately to show cursor
|
|
|
-
|
|
|
- // 1. Resolve the base key name
|
|
|
- std::string key_name = resolve_key(keyval, state);
|
|
|
- if (key_name.empty()) return false;
|
|
|
-
|
|
|
- // 2. Handle Modifiers
|
|
|
+ // Apply modifiers
|
|
|
unsigned int state_uint = static_cast<unsigned int>(state);
|
|
|
- bool is_control = (state_uint & static_cast<unsigned int>(Gdk::ModifierType::CONTROL_MASK)) != 0;
|
|
|
- bool is_alt = (state_uint & static_cast<unsigned int>(Gdk::ModifierType::ALT_MASK)) != 0;
|
|
|
- bool is_meta = (state_uint & static_cast<unsigned int>(Gdk::ModifierType::META_MASK)) != 0;
|
|
|
- bool is_lumacs_meta = is_alt || is_meta;
|
|
|
+ if (state_uint & static_cast<unsigned int>(Gdk::ModifierType::CONTROL_MASK)) {
|
|
|
+ key_name = "C-" + key_name;
|
|
|
+ }
|
|
|
+ if (state_uint & static_cast<unsigned int>(Gdk::ModifierType::ALT_MASK) ||
|
|
|
+ state_uint & static_cast<unsigned int>(Gdk::ModifierType::META_MASK)) {
|
|
|
+ key_name = "M-" + key_name;
|
|
|
+ }
|
|
|
+ if (state_uint & static_cast<unsigned int>(Gdk::ModifierType::SHIFT_MASK)) {
|
|
|
+ key_name = "S-" + key_name;
|
|
|
+ }
|
|
|
|
|
|
- // 3. Handle Minibuffer Input Logic (Command/Buffer/File modes)
|
|
|
+ // 2. Handle Minibuffer Input Logic (Command/Buffer/File modes)
|
|
|
if (core_.minibuffer_manager().is_active()) {
|
|
|
// Pass the key event to the MinibufferManager
|
|
|
core_.minibuffer_manager().handle_key_event(key_name);
|
|
|
@@ -118,96 +111,15 @@ bool GtkWindowController::on_key_pressed(guint keyval, guint /*keycode*/, Gdk::M
|
|
|
return true;
|
|
|
}
|
|
|
|
|
|
- // 4. Normal Mode Processing (Pass to Lua)
|
|
|
- if (is_control && key_name.length() == 1) key_name = "C-" + key_name;
|
|
|
- if (is_lumacs_meta) key_name = "M-" + key_name; // Use combined meta/alt
|
|
|
-
|
|
|
- KeyResult result = core_.lua_api()->process_key(key_name);
|
|
|
+ // 3. Normal Mode Processing (Pass to KeyBindingManager)
|
|
|
+ KeyProcessingResult result = core_.keybinding_manager().process_key(key_name);
|
|
|
|
|
|
- // Fallback handlers for common editing keys
|
|
|
- if (result == KeyResult::Unbound) {
|
|
|
- // Return - insert newline
|
|
|
- if (key_name == "Return") {
|
|
|
- auto cursor = core_.cursor();
|
|
|
- window_->buffer().insert_newline(cursor);
|
|
|
- window_->set_cursor({cursor.line + 1, 0});
|
|
|
- }
|
|
|
- // Backspace - delete character
|
|
|
- else if (key_name == "Backspace") {
|
|
|
- auto cursor = core_.cursor();
|
|
|
- window_->buffer().erase_char(cursor);
|
|
|
- if (cursor.column > 0) {
|
|
|
- window_->set_cursor({cursor.line, cursor.column - 1});
|
|
|
- } else if (cursor.line > 0) {
|
|
|
- // Join with previous line
|
|
|
- const auto& prev_line = window_->buffer().line(cursor.line - 1);
|
|
|
- size_t prev_line_len = prev_line.length();
|
|
|
- window_->set_cursor({cursor.line - 1, prev_line_len});
|
|
|
- }
|
|
|
- }
|
|
|
- // Delete - delete character forward
|
|
|
- else if (key_name == "Delete") {
|
|
|
- auto cursor = core_.cursor();
|
|
|
- window_->buffer().erase_char({cursor.line, cursor.column + 1});
|
|
|
- // No cursor movement needed for forward delete
|
|
|
- }
|
|
|
- // Arrow key navigation - use Window methods for proper scrolling
|
|
|
- else if (key_name == "ArrowUp") {
|
|
|
- window_->move_up();
|
|
|
- }
|
|
|
- else if (key_name == "ArrowDown") {
|
|
|
- window_->move_down();
|
|
|
- }
|
|
|
- else if (key_name == "ArrowLeft") {
|
|
|
- window_->move_left();
|
|
|
- }
|
|
|
- else if (key_name == "ArrowRight") {
|
|
|
- window_->move_right();
|
|
|
- }
|
|
|
- // Page navigation - scroll multiple lines
|
|
|
- else if (key_name == "PageUp") {
|
|
|
- auto cursor = window_->cursor();
|
|
|
- int page_size = std::max(1, window_->viewport().height - 2); // Leave 2 lines overlap
|
|
|
-
|
|
|
- // Move cursor up by page size
|
|
|
- size_t new_line = (cursor.line >= static_cast<size_t>(page_size))
|
|
|
- ? cursor.line - page_size
|
|
|
- : 0;
|
|
|
-
|
|
|
- window_->set_cursor({new_line, cursor.column});
|
|
|
- }
|
|
|
- else if (key_name == "PageDown") {
|
|
|
- auto cursor = window_->cursor();
|
|
|
- int page_size = std::max(1, window_->viewport().height - 2); // Leave 2 lines overlap
|
|
|
-
|
|
|
- // Move cursor down by page size
|
|
|
- size_t max_line = window_->buffer().line_count() - 1;
|
|
|
- size_t new_line = std::min(cursor.line + page_size, max_line);
|
|
|
-
|
|
|
- window_->set_cursor({new_line, cursor.column});
|
|
|
- }
|
|
|
- // Home/End navigation
|
|
|
- else if (key_name == "Home") {
|
|
|
- window_->move_to_line_start();
|
|
|
- }
|
|
|
- else if (key_name == "End") {
|
|
|
- window_->move_to_line_end();
|
|
|
- }
|
|
|
- // Insert printable characters if unbound
|
|
|
- else if (key_name.size() == 1 && key_name[0] >= 32 && key_name[0] <= 126) {
|
|
|
- auto cursor = window_->cursor();
|
|
|
- window_->buffer().insert_char(cursor, key_name[0]);
|
|
|
- window_->set_cursor({cursor.line, cursor.column + 1});
|
|
|
-
|
|
|
- // Debug cursor position
|
|
|
- auto new_cursor = window_->cursor();
|
|
|
- std::cerr << "[DEBUG] Inserted '" << key_name[0] << "' at (" << cursor.line << "," << cursor.column
|
|
|
- << ") -> cursor now at (" << new_cursor.line << "," << new_cursor.column << ")" << std::endl;
|
|
|
- }
|
|
|
+ if (result.command_result.has_value()) {
|
|
|
+ core_.set_message(result.command_result->message);
|
|
|
}
|
|
|
|
|
|
drawing_area_.queue_draw();
|
|
|
- return true;
|
|
|
+ return result.type != KeyResult::Unbound; // Return true if handled, false otherwise
|
|
|
}
|
|
|
|
|
|
|