bool EditorClient::executePendingEditorCommands(Frame* frame, bool allowTextInsertion) { Vector<Editor::Command> commands; for (size_t i = 0; i < m_pendingEditorCommands.size(); i++) { Editor::Command command = frame->editor()->command(m_pendingEditorCommands.at(i).utf8().data()); if (command.isTextInsertion() && !allowTextInsertion) return false; commands.append(command); } bool success = true; for (size_t i = 0; i < commands.size(); i++) { if (!commands.at(i).execute()) { success = false; break; } } m_pendingEditorCommands.clear(); // If we successfully completed all editor commands, then // this signals a canceling of the composition. if (success) clearPendingComposition(); return success; }
bool EditorClient::shouldEndEditing(WebCore::Range*) { clearPendingComposition(); notImplemented(); return true; }
bool EditorClient::shouldEndEditing(WebCore::Range* range) { clearPendingComposition(); gboolean accept = TRUE; GRefPtr<WebKitDOMRange> kitRange(adoptGRef(kit(range))); g_signal_emit_by_name(m_webView, "should-end-editing", kitRange.get(), &accept); return accept; }
void EditorClient::handleInputMethodKeydown(KeyboardEvent* event) { Frame* targetFrame = core(m_webView)->focusController()->focusedOrMainFrame(); if (!targetFrame || !targetFrame->editor()->canEdit()) return; WebKitWebViewPrivate* priv = m_webView->priv; m_preventNextCompositionCommit = false; // Some IM contexts (e.g. 'simple') will act as if they filter every // keystroke and just issue a 'commit' signal during handling. In situations // where the 'commit' signal happens during filtering and there is no active // composition, act as if the keystroke was not filtered. The one exception to // this is when the keyval parameter of the GdkKeyEvent is 0, which is often // a key event sent by the IM context for committing the current composition. // Here is a typical sequence of events for the 'simple' context: // 1. GDK key press event -> webkit_web_view_key_press_event // 2. Keydown event -> EditorClient::handleInputMethodKeydown // gtk_im_context_filter_keypress returns true, but there is a pending // composition so event->preventDefault is not called (below). // 3. Keydown event bubbles through the DOM // 4. Keydown event -> EditorClient::handleKeyboardEvent // No action taken. // 4. GDK key release event -> webkit_web_view_key_release_event // 5. gtk_im_context_filter_keypress is called on the release event. // Simple does not filter most key releases, so the event continues. // 6. Keypress event bubbles through the DOM. // 7. Keypress event -> EditorClient::handleKeyboardEvent // pending composition is inserted. // 8. Keyup event bubbles through the DOM. // 9. Keyup event -> EditorClient::handleKeyboardEvent // No action taken. // There are two situations where we do filter the keystroke: // 1. The IMContext instructed us to filter and we have no pending composition. // 2. The IMContext did not instruct us to filter, but the keystroke caused a // composition in progress to finish. It seems that sometimes SCIM will finish // a composition and not mark the keystroke as filtered. m_treatContextCommitAsKeyEvent = (!targetFrame->editor()->hasComposition()) && event->keyEvent()->gdkEventKey()->keyval; clearPendingComposition(); if ((gtk_im_context_filter_keypress(priv->imContext.get(), event->keyEvent()->gdkEventKey()) && !m_pendingComposition) || (!m_treatContextCommitAsKeyEvent && !targetFrame->editor()->hasComposition())) event->preventDefault(); m_treatContextCommitAsKeyEvent = false; }
void EditorClient::handleKeyboardEvent(KeyboardEvent* event) { Node* node = event->target()->toNode(); ASSERT(node); Frame* frame = node->document()->frame(); ASSERT(frame); const PlatformKeyboardEvent* platformEvent = event->keyEvent(); if (!platformEvent) return; KeyBindingTranslator::EventType type = event->type() == eventNames().keydownEvent ? KeyBindingTranslator::KeyDown : KeyBindingTranslator::KeyPress; m_keyBindingTranslator.getEditorCommandsForKeyEvent(platformEvent->gdkEventKey(), type, m_pendingEditorCommands); if (m_pendingEditorCommands.size() > 0) { // During RawKeyDown events if an editor command will insert text, defer // the insertion until the keypress event. We want keydown to bubble up // through the DOM first. if (platformEvent->type() == PlatformKeyboardEvent::RawKeyDown) { if (executePendingEditorCommands(frame, false)) event->setDefaultHandled(); return; } // Only allow text insertion commands if the current node is editable. if (executePendingEditorCommands(frame, frame->editor()->canEdit())) { event->setDefaultHandled(); return; } } // Don't allow text insertion for nodes that cannot edit. if (!frame->editor()->canEdit()) return; // This is just a normal text insertion, so wait to execute the insertion // until a keypress event happens. This will ensure that the insertion will not // be reflected in the contents of the field until the keyup DOM event. if (event->type() == eventNames().keypressEvent) { // If we have a pending composition at this point, it happened while // filtering a keypress, so we treat it as a normal text insertion. // This will also ensure that if the keypress event handler changed the // currently focused node, the text is still inserted into the original // node (insertText() has this logic, but confirmComposition() does not). if (m_pendingComposition) { frame->editor()->insertText(String::fromUTF8(m_pendingComposition.get()), event); clearPendingComposition(); event->setDefaultHandled(); } else { // Don't insert null or control characters as they can result in unexpected behaviour if (event->charCode() < ' ') return; // Don't insert anything if a modifier is pressed if (platformEvent->ctrlKey() || platformEvent->altKey()) return; if (frame->editor()->insertText(platformEvent->text(), event)) event->setDefaultHandled(); } } }