123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376 |
- // Copyright (c) 2012 The Chromium Authors. All rights reserved.
- // Use of this source code is governed by a BSD-style license that can be
- // found in the LICENSE file.
- #include "ui/gtk/gtk_key_bindings_handler.h"
- #include <cstddef>
- #include <string>
- #include "base/logging.h"
- #include "base/strings/string_util.h"
- #include "ui/base/glib/glib_cast.h"
- #include "ui/base/ime/text_edit_commands.h"
- #include "ui/events/event.h"
- #include "ui/gtk/gtk_compat.h"
- #include "ui/gtk/gtk_util.h"
- using ui::TextEditCommand;
- namespace gtk {
- GtkKeyBindingsHandler::GtkKeyBindingsHandler()
- : fake_window_(gtk_offscreen_window_new()), handler_(CreateNewHandler()) {
- DCHECK(!GtkCheckVersion(4));
- gtk_container_add(
- GlibCast<GtkContainer>(fake_window_, gtk_container_get_type()), handler_);
- }
- GtkKeyBindingsHandler::~GtkKeyBindingsHandler() {
- gtk_widget_destroy(handler_);
- gtk_widget_destroy(fake_window_);
- }
- bool GtkKeyBindingsHandler::MatchEvent(
- const ui::Event& event,
- std::vector<ui::TextEditCommandAuraLinux>* edit_commands) {
- CHECK(event.IsKeyEvent());
- const ui::KeyEvent& key_event = static_cast<const ui::KeyEvent&>(event);
- if (key_event.is_char())
- return false;
- GdkEvent* gdk_event = GdkEventFromKeyEvent(key_event);
- if (!gdk_event)
- return false;
- edit_commands_.clear();
- // If this key event matches a predefined key binding, corresponding signal
- // will be emitted.
- auto* key = reinterpret_cast<GdkEventKey*>(gdk_event);
- DCHECK(key->type == GdkKeyPress() || key->type == GdkKeyRelease());
- gtk_bindings_activate_event(G_OBJECT(handler_), key);
- gdk_event_free(gdk_event);
- bool matched = !edit_commands_.empty();
- if (edit_commands)
- edit_commands->swap(edit_commands_);
- return matched;
- }
- GtkWidget* GtkKeyBindingsHandler::CreateNewHandler() {
- Handler* handler =
- static_cast<Handler*>(g_object_new(HandlerGetType(), nullptr));
- handler->owner = this;
- // We don't need to show the |handler| object on screen, so set its size to
- // zero.
- gtk_widget_set_size_request(GTK_WIDGET(handler), 0, 0);
- // Prevents it from handling any events by itself.
- gtk_widget_set_sensitive(GTK_WIDGET(handler), FALSE);
- gtk_widget_set_events(GTK_WIDGET(handler), 0);
- gtk_widget_set_can_focus(GTK_WIDGET(handler), TRUE);
- return GTK_WIDGET(handler);
- }
- void GtkKeyBindingsHandler::EditCommandMatched(TextEditCommand command,
- const std::string& value) {
- edit_commands_.emplace_back(command, value);
- }
- void GtkKeyBindingsHandler::HandlerInit(Handler* self) {
- self->owner = nullptr;
- }
- void GtkKeyBindingsHandler::HandlerClassInit(HandlerClass* klass) {
- // Overrides all virtual methods related to editor key bindings.
- klass->backspace = BackSpace;
- klass->copy_clipboard = CopyClipboard;
- klass->cut_clipboard = CutClipboard;
- klass->delete_from_cursor = DeleteFromCursor;
- klass->insert_at_cursor = InsertAtCursor;
- klass->move_cursor = MoveCursor;
- klass->paste_clipboard = PasteClipboard;
- klass->set_anchor = SetAnchor;
- klass->toggle_overwrite = ToggleOverwrite;
- // "move-focus", "move-viewport", "select-all" and "toggle-cursor-visible"
- // have no corresponding virtual methods. Since glib 2.18 (gtk 2.14),
- // g_signal_override_class_handler() is introduced to override a signal
- // handler.
- g_signal_override_class_handler("move-focus", G_TYPE_FROM_CLASS(klass),
- G_CALLBACK(MoveFocus));
- g_signal_override_class_handler("move-viewport", G_TYPE_FROM_CLASS(klass),
- G_CALLBACK(MoveViewport));
- g_signal_override_class_handler("select-all", G_TYPE_FROM_CLASS(klass),
- G_CALLBACK(SelectAll));
- g_signal_override_class_handler("toggle-cursor-visible",
- G_TYPE_FROM_CLASS(klass),
- G_CALLBACK(ToggleCursorVisible));
- g_signal_override_class_handler("show-help", G_TYPE_FROM_CLASS(klass),
- G_CALLBACK(ShowHelp));
- }
- GType GtkKeyBindingsHandler::HandlerGetType() {
- static volatile gsize type_id_volatile = 0;
- if (g_once_init_enter(&type_id_volatile)) {
- GType type_id = g_type_register_static_simple(
- GTK_TYPE_TEXT_VIEW, g_intern_static_string("GtkKeyBindingsHandler"),
- sizeof(HandlerClass),
- reinterpret_cast<GClassInitFunc>(HandlerClassInit), sizeof(Handler),
- reinterpret_cast<GInstanceInitFunc>(HandlerInit),
- static_cast<GTypeFlags>(0));
- g_once_init_leave(&type_id_volatile, type_id);
- }
- return type_id_volatile;
- }
- GtkKeyBindingsHandler* GtkKeyBindingsHandler::GetHandlerOwner(
- GtkTextView* text_view) {
- Handler* handler =
- G_TYPE_CHECK_INSTANCE_CAST(text_view, HandlerGetType(), Handler);
- DCHECK(handler);
- return handler->owner;
- }
- void GtkKeyBindingsHandler::BackSpace(GtkTextView* text_view) {
- GetHandlerOwner(text_view)->EditCommandMatched(
- TextEditCommand::DELETE_BACKWARD, std::string());
- }
- void GtkKeyBindingsHandler::CopyClipboard(GtkTextView* text_view) {
- GetHandlerOwner(text_view)->EditCommandMatched(TextEditCommand::COPY,
- std::string());
- }
- void GtkKeyBindingsHandler::CutClipboard(GtkTextView* text_view) {
- GetHandlerOwner(text_view)->EditCommandMatched(TextEditCommand::CUT,
- std::string());
- }
- void GtkKeyBindingsHandler::DeleteFromCursor(GtkTextView* text_view,
- GtkDeleteType type,
- gint count) {
- if (!count)
- return;
- TextEditCommand commands[2] = {
- TextEditCommand::INVALID_COMMAND,
- TextEditCommand::INVALID_COMMAND,
- };
- switch (type) {
- case GTK_DELETE_CHARS:
- commands[0] = (count > 0 ? TextEditCommand::DELETE_FORWARD
- : TextEditCommand::DELETE_BACKWARD);
- break;
- case GTK_DELETE_WORD_ENDS:
- commands[0] = (count > 0 ? TextEditCommand::DELETE_WORD_FORWARD
- : TextEditCommand::DELETE_WORD_BACKWARD);
- break;
- case GTK_DELETE_WORDS:
- if (count > 0) {
- commands[0] = TextEditCommand::MOVE_WORD_FORWARD;
- commands[1] = TextEditCommand::DELETE_WORD_BACKWARD;
- } else {
- commands[0] = TextEditCommand::MOVE_WORD_BACKWARD;
- commands[1] = TextEditCommand::DELETE_WORD_FORWARD;
- }
- break;
- case GTK_DELETE_DISPLAY_LINES:
- commands[0] = TextEditCommand::MOVE_TO_BEGINNING_OF_LINE;
- commands[1] = TextEditCommand::DELETE_TO_END_OF_LINE;
- break;
- case GTK_DELETE_DISPLAY_LINE_ENDS:
- commands[0] = (count > 0 ? TextEditCommand::DELETE_TO_END_OF_LINE
- : TextEditCommand::DELETE_TO_BEGINNING_OF_LINE);
- break;
- case GTK_DELETE_PARAGRAPH_ENDS:
- commands[0] =
- (count > 0 ? TextEditCommand::DELETE_TO_END_OF_PARAGRAPH
- : TextEditCommand::DELETE_TO_BEGINNING_OF_PARAGRAPH);
- break;
- case GTK_DELETE_PARAGRAPHS:
- commands[0] = TextEditCommand::MOVE_TO_BEGINNING_OF_PARAGRAPH;
- commands[1] = TextEditCommand::DELETE_TO_END_OF_PARAGRAPH;
- break;
- default:
- // GTK_DELETE_WHITESPACE has no corresponding editor command.
- return;
- }
- GtkKeyBindingsHandler* owner = GetHandlerOwner(text_view);
- if (count < 0)
- count = -count;
- for (; count > 0; --count) {
- for (auto& command : commands) {
- if (command != TextEditCommand::INVALID_COMMAND)
- owner->EditCommandMatched(command, std::string());
- }
- }
- }
- void GtkKeyBindingsHandler::InsertAtCursor(GtkTextView* text_view,
- const gchar* str) {
- if (str && *str) {
- GetHandlerOwner(text_view)->EditCommandMatched(TextEditCommand::INSERT_TEXT,
- str);
- }
- }
- void GtkKeyBindingsHandler::MoveCursor(GtkTextView* text_view,
- GtkMovementStep step,
- gint count,
- gboolean extend_selection) {
- if (!count)
- return;
- TextEditCommand command;
- switch (step) {
- case GTK_MOVEMENT_LOGICAL_POSITIONS:
- if (extend_selection) {
- command =
- (count > 0 ? TextEditCommand::MOVE_FORWARD_AND_MODIFY_SELECTION
- : TextEditCommand::MOVE_BACKWARD_AND_MODIFY_SELECTION);
- } else {
- command = (count > 0 ? TextEditCommand::MOVE_FORWARD
- : TextEditCommand::MOVE_BACKWARD);
- }
- break;
- case GTK_MOVEMENT_VISUAL_POSITIONS:
- if (extend_selection) {
- command = (count > 0 ? TextEditCommand::MOVE_RIGHT_AND_MODIFY_SELECTION
- : TextEditCommand::MOVE_LEFT_AND_MODIFY_SELECTION);
- } else {
- command = (count > 0 ? TextEditCommand::MOVE_RIGHT
- : TextEditCommand::MOVE_LEFT);
- }
- break;
- case GTK_MOVEMENT_WORDS:
- if (extend_selection) {
- command =
- (count > 0 ? TextEditCommand::MOVE_WORD_RIGHT_AND_MODIFY_SELECTION
- : TextEditCommand::MOVE_WORD_LEFT_AND_MODIFY_SELECTION);
- } else {
- command = (count > 0 ? TextEditCommand::MOVE_WORD_RIGHT
- : TextEditCommand::MOVE_WORD_LEFT);
- }
- break;
- case GTK_MOVEMENT_DISPLAY_LINES:
- if (extend_selection) {
- command = (count > 0 ? TextEditCommand::MOVE_DOWN_AND_MODIFY_SELECTION
- : TextEditCommand::MOVE_UP_AND_MODIFY_SELECTION);
- } else {
- command =
- (count > 0 ? TextEditCommand::MOVE_DOWN : TextEditCommand::MOVE_UP);
- }
- break;
- case GTK_MOVEMENT_DISPLAY_LINE_ENDS:
- if (extend_selection) {
- command =
- (count > 0
- ? TextEditCommand::MOVE_TO_END_OF_LINE_AND_MODIFY_SELECTION
- : TextEditCommand::
- MOVE_TO_BEGINNING_OF_LINE_AND_MODIFY_SELECTION);
- } else {
- command = (count > 0 ? TextEditCommand::MOVE_TO_END_OF_LINE
- : TextEditCommand::MOVE_TO_BEGINNING_OF_LINE);
- }
- break;
- case GTK_MOVEMENT_PARAGRAPH_ENDS:
- if (extend_selection) {
- command =
- (count > 0
- ? TextEditCommand::
- MOVE_TO_END_OF_PARAGRAPH_AND_MODIFY_SELECTION
- : TextEditCommand::
- MOVE_TO_BEGINNING_OF_PARAGRAPH_AND_MODIFY_SELECTION);
- } else {
- command = (count > 0 ? TextEditCommand::MOVE_TO_END_OF_PARAGRAPH
- : TextEditCommand::MOVE_TO_BEGINNING_OF_PARAGRAPH);
- }
- break;
- case GTK_MOVEMENT_PAGES:
- if (extend_selection) {
- command =
- (count > 0 ? TextEditCommand::MOVE_PAGE_DOWN_AND_MODIFY_SELECTION
- : TextEditCommand::MOVE_PAGE_UP_AND_MODIFY_SELECTION);
- } else {
- command = (count > 0 ? TextEditCommand::MOVE_PAGE_DOWN
- : TextEditCommand::MOVE_PAGE_UP);
- }
- break;
- case GTK_MOVEMENT_BUFFER_ENDS:
- if (extend_selection) {
- command =
- (count > 0
- ? TextEditCommand::MOVE_TO_END_OF_DOCUMENT_AND_MODIFY_SELECTION
- : TextEditCommand::
- MOVE_TO_BEGINNING_OF_DOCUMENT_AND_MODIFY_SELECTION);
- } else {
- command = (count > 0 ? TextEditCommand::MOVE_TO_END_OF_DOCUMENT
- : TextEditCommand::MOVE_TO_BEGINNING_OF_DOCUMENT);
- }
- break;
- default:
- // GTK_MOVEMENT_PARAGRAPHS and GTK_MOVEMENT_HORIZONTAL_PAGES have
- // no corresponding editor commands.
- return;
- }
- GtkKeyBindingsHandler* owner = GetHandlerOwner(text_view);
- if (count < 0)
- count = -count;
- for (; count > 0; --count)
- owner->EditCommandMatched(command, std::string());
- }
- void GtkKeyBindingsHandler::MoveViewport(GtkTextView* text_view,
- GtkScrollStep step,
- gint count) {
- // Not supported by Blink.
- }
- void GtkKeyBindingsHandler::PasteClipboard(GtkTextView* text_view) {
- GetHandlerOwner(text_view)->EditCommandMatched(TextEditCommand::PASTE,
- std::string());
- }
- void GtkKeyBindingsHandler::SelectAll(GtkTextView* text_view, gboolean select) {
- GetHandlerOwner(text_view)->EditCommandMatched(
- select ? TextEditCommand::SELECT_ALL : TextEditCommand::UNSELECT,
- std::string());
- }
- void GtkKeyBindingsHandler::SetAnchor(GtkTextView* text_view) {
- GetHandlerOwner(text_view)->EditCommandMatched(TextEditCommand::SET_MARK,
- std::string());
- }
- void GtkKeyBindingsHandler::ToggleCursorVisible(GtkTextView* text_view) {
- // Not supported by Blink.
- }
- void GtkKeyBindingsHandler::ToggleOverwrite(GtkTextView* text_view) {
- // Not supported by Blink.
- }
- gboolean GtkKeyBindingsHandler::ShowHelp(GtkWidget* widget,
- GtkWidgetHelpType arg1) {
- // Just for disabling the default handler.
- return TRUE;
- }
- void GtkKeyBindingsHandler::MoveFocus(GtkWidget* widget,
- GtkDirectionType arg1) {
- // Just for disabling the default handler.
- }
- } // namespace gtk
|