1 /* 2 * Copyright (C) 2007 Kevin Ollivier <kevino (at) theolliviers.com> 3 * 4 * All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 15 * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY 16 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 18 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR 19 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 20 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 21 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 22 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY 23 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 25 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 */ 27 #include "config.h" 28 #include "EditorClientWx.h" 29 30 #include "EditCommand.h" 31 #include "Editor.h" 32 #include "FocusController.h" 33 #include "Frame.h" 34 #include "FrameView.h" 35 #include "HostWindow.h" 36 #include "KeyboardEvent.h" 37 #include "NotImplemented.h" 38 #include "Page.h" 39 #include "PlatformKeyboardEvent.h" 40 #include "PlatformString.h" 41 #include "SelectionController.h" 42 #include "WebFrame.h" 43 #include "WebFramePrivate.h" 44 #include "WebView.h" 45 #include "WebViewPrivate.h" 46 #include "WindowsKeyboardCodes.h" 47 48 #include <stdio.h> 49 50 namespace WebCore { 51 52 static const unsigned CtrlKey = 1 << 0; 53 static const unsigned AltKey = 1 << 1; 54 static const unsigned ShiftKey = 1 << 2; 55 56 struct KeyDownEntry { 57 unsigned virtualKey; 58 unsigned modifiers; 59 const char* name; 60 }; 61 62 struct KeyPressEntry { 63 unsigned charCode; 64 unsigned modifiers; 65 const char* name; 66 }; 67 68 static const KeyDownEntry keyDownEntries[] = { 69 { VK_LEFT, 0, "MoveLeft" }, 70 { VK_LEFT, ShiftKey, "MoveLeftAndModifySelection" }, 71 { VK_LEFT, CtrlKey, "MoveWordLeft" }, 72 { VK_LEFT, CtrlKey | ShiftKey, "MoveWordLeftAndModifySelection" }, 73 { VK_RIGHT, 0, "MoveRight" }, 74 { VK_RIGHT, ShiftKey, "MoveRightAndModifySelection" }, 75 { VK_RIGHT, CtrlKey, "MoveWordRight" }, 76 { VK_RIGHT, CtrlKey | ShiftKey, "MoveWordRightAndModifySelection" }, 77 { VK_UP, 0, "MoveUp" }, 78 { VK_UP, ShiftKey, "MoveUpAndModifySelection" }, 79 { VK_PRIOR, ShiftKey, "MovePageUpAndModifySelection" }, 80 { VK_DOWN, 0, "MoveDown" }, 81 { VK_DOWN, ShiftKey, "MoveDownAndModifySelection" }, 82 { VK_NEXT, ShiftKey, "MovePageDownAndModifySelection" }, 83 { VK_PRIOR, 0, "MovePageUp" }, 84 { VK_NEXT, 0, "MovePageDown" }, 85 { VK_HOME, 0, "MoveToBeginningOfLine" }, 86 { VK_HOME, ShiftKey, "MoveToBeginningOfLineAndModifySelection" }, 87 { VK_HOME, CtrlKey, "MoveToBeginningOfDocument" }, 88 { VK_HOME, CtrlKey | ShiftKey, "MoveToBeginningOfDocumentAndModifySelection" }, 89 90 { VK_END, 0, "MoveToEndOfLine" }, 91 { VK_END, ShiftKey, "MoveToEndOfLineAndModifySelection" }, 92 { VK_END, CtrlKey, "MoveToEndOfDocument" }, 93 { VK_END, CtrlKey | ShiftKey, "MoveToEndOfDocumentAndModifySelection" }, 94 95 { VK_BACK, 0, "DeleteBackward" }, 96 { VK_BACK, ShiftKey, "DeleteBackward" }, 97 { VK_DELETE, 0, "DeleteForward" }, 98 { VK_BACK, CtrlKey, "DeleteWordBackward" }, 99 { VK_DELETE, CtrlKey, "DeleteWordForward" }, 100 101 { 'B', CtrlKey, "ToggleBold" }, 102 { 'I', CtrlKey, "ToggleItalic" }, 103 104 { VK_ESCAPE, 0, "Cancel" }, 105 //FIXME: this'll never happen. We can trash it or make it a normal period 106 { VK_OEM_PERIOD, CtrlKey, "Cancel" }, 107 { VK_TAB, 0, "InsertTab" }, 108 { VK_TAB, ShiftKey, "InsertBacktab" }, 109 { VK_RETURN, 0, "InsertNewline" }, 110 { VK_RETURN, CtrlKey, "InsertNewline" }, 111 { VK_RETURN, AltKey, "InsertNewline" }, 112 { VK_RETURN, ShiftKey, "InsertLineBreak" }, 113 { 'A', CtrlKey, "SelectAll" }, 114 { 'Z', CtrlKey, "Undo" }, 115 { 'Z', CtrlKey | ShiftKey, "Redo" }, 116 }; 117 118 static const KeyPressEntry keyPressEntries[] = { 119 { '\t', 0, "InsertTab" }, 120 { '\t', ShiftKey, "InsertBacktab" }, 121 { '\r', 0, "InsertNewline" }, 122 { '\r', CtrlKey, "InsertNewline" }, 123 { '\r', AltKey, "InsertNewline" }, 124 { '\r', AltKey | ShiftKey, "InsertNewline" }, 125 }; 126 127 EditorClientWx::~EditorClientWx() 128 { 129 m_page = NULL; 130 } 131 132 void EditorClientWx::setPage(Page* page) 133 { 134 m_page = page; 135 } 136 137 void EditorClientWx::pageDestroyed() 138 { 139 delete this; 140 } 141 142 bool EditorClientWx::shouldDeleteRange(Range*) 143 { 144 notImplemented(); 145 return true; 146 } 147 148 bool EditorClientWx::shouldShowDeleteInterface(HTMLElement*) 149 { 150 notImplemented(); 151 return false; 152 } 153 154 bool EditorClientWx::smartInsertDeleteEnabled() 155 { 156 notImplemented(); 157 return false; 158 } 159 160 bool EditorClientWx::isSelectTrailingWhitespaceEnabled() 161 { 162 notImplemented(); 163 return false; 164 } 165 166 bool EditorClientWx::isContinuousSpellCheckingEnabled() 167 { 168 notImplemented(); 169 return false; 170 } 171 172 void EditorClientWx::toggleContinuousSpellChecking() 173 { 174 notImplemented(); 175 } 176 177 bool EditorClientWx::isGrammarCheckingEnabled() 178 { 179 notImplemented(); 180 return false; 181 } 182 183 void EditorClientWx::toggleGrammarChecking() 184 { 185 notImplemented(); 186 } 187 188 int EditorClientWx::spellCheckerDocumentTag() 189 { 190 notImplemented(); 191 return 0; 192 } 193 194 bool EditorClientWx::selectWordBeforeMenuEvent() 195 { 196 notImplemented(); 197 return false; 198 } 199 200 bool EditorClientWx::shouldBeginEditing(Range*) 201 { 202 notImplemented(); 203 return true; 204 } 205 206 bool EditorClientWx::shouldEndEditing(Range*) 207 { 208 notImplemented(); 209 return true; 210 } 211 212 bool EditorClientWx::shouldInsertNode(Node*, Range*, 213 EditorInsertAction) 214 { 215 notImplemented(); 216 return true; 217 } 218 219 bool EditorClientWx::shouldInsertText(const String&, Range*, 220 EditorInsertAction) 221 { 222 notImplemented(); 223 return true; 224 } 225 226 bool EditorClientWx::shouldApplyStyle(CSSStyleDeclaration*, 227 Range*) 228 { 229 notImplemented(); 230 return true; 231 } 232 233 bool EditorClientWx::shouldMoveRangeAfterDelete(Range*, Range*) 234 { 235 notImplemented(); 236 return true; 237 } 238 239 bool EditorClientWx::shouldChangeSelectedRange(Range* fromRange, Range* toRange, 240 EAffinity, bool stillSelecting) 241 { 242 notImplemented(); 243 return true; 244 } 245 246 void EditorClientWx::didBeginEditing() 247 { 248 notImplemented(); 249 } 250 251 void EditorClientWx::respondToChangedContents() 252 { 253 Frame* frame = m_page->focusController()->focusedOrMainFrame(); 254 255 if (frame) { 256 wxWebView* webKitWin = dynamic_cast<wxWebView*>(frame->view()->hostWindow()->platformPageClient()); 257 if (webKitWin) { 258 wxWebViewContentsChangedEvent wkEvent(webKitWin); 259 webKitWin->GetEventHandler()->ProcessEvent(wkEvent); 260 } 261 } 262 } 263 264 void EditorClientWx::didEndEditing() 265 { 266 notImplemented(); 267 } 268 269 void EditorClientWx::didWriteSelectionToPasteboard() 270 { 271 notImplemented(); 272 } 273 274 void EditorClientWx::didSetSelectionTypesForPasteboard() 275 { 276 notImplemented(); 277 } 278 279 void EditorClientWx::registerCommandForUndo(PassRefPtr<EditCommand> command) 280 { 281 Frame* frame = m_page->focusController()->focusedOrMainFrame(); 282 283 if (frame) { 284 wxWebView* webKitWin = dynamic_cast<wxWebView*>(frame->view()->hostWindow()->platformPageClient()); 285 if (webKitWin) { 286 webKitWin->m_impl->undoStack.append(EditCommandWx(command)); 287 } 288 } 289 } 290 291 void EditorClientWx::registerCommandForRedo(PassRefPtr<EditCommand> command) 292 { 293 Frame* frame = m_page->focusController()->focusedOrMainFrame(); 294 295 if (frame) { 296 wxWebView* webKitWin = dynamic_cast<wxWebView*>(frame->view()->hostWindow()->platformPageClient()); 297 if (webKitWin) { 298 webKitWin->m_impl->redoStack.insert(0, EditCommandWx(command)); 299 } 300 } 301 } 302 303 void EditorClientWx::clearUndoRedoOperations() 304 { 305 Frame* frame = m_page->focusController()->focusedOrMainFrame(); 306 307 if (frame) { 308 wxWebView* webKitWin = dynamic_cast<wxWebView*>(frame->view()->hostWindow()->platformPageClient()); 309 if (webKitWin) { 310 webKitWin->m_impl->redoStack.clear(); 311 webKitWin->m_impl->undoStack.clear(); 312 } 313 } 314 } 315 316 bool EditorClientWx::canCopyCut(bool defaultValue) const 317 { 318 return defaultValue; 319 } 320 321 bool EditorClientWx::canPaste(bool defaultValue) const 322 { 323 return defaultValue; 324 } 325 326 bool EditorClientWx::canUndo() const 327 { 328 Frame* frame = m_page->focusController()->focusedOrMainFrame(); 329 330 if (frame) { 331 wxWebView* webKitWin = dynamic_cast<wxWebView*>(frame->view()->hostWindow()->platformPageClient()); 332 if (webKitWin) { 333 return webKitWin->m_impl->undoStack.size() != 0; 334 } 335 } 336 return false; 337 } 338 339 bool EditorClientWx::canRedo() const 340 { 341 Frame* frame = m_page->focusController()->focusedOrMainFrame(); 342 343 if (frame) { 344 wxWebView* webKitWin = dynamic_cast<wxWebView*>(frame->view()->hostWindow()->platformPageClient()); 345 if (webKitWin && webKitWin) { 346 return webKitWin->m_impl->redoStack.size() != 0; 347 } 348 } 349 return false; 350 } 351 352 void EditorClientWx::undo() 353 { 354 Frame* frame = m_page->focusController()->focusedOrMainFrame(); 355 356 if (frame) { 357 wxWebView* webKitWin = dynamic_cast<wxWebView*>(frame->view()->hostWindow()->platformPageClient()); 358 if (webKitWin) { 359 webKitWin->m_impl->undoStack.last().editCommand()->unapply(); 360 webKitWin->m_impl->undoStack.removeLast(); 361 } 362 } 363 } 364 365 void EditorClientWx::redo() 366 { 367 Frame* frame = m_page->focusController()->focusedOrMainFrame(); 368 369 if (frame) { 370 wxWebView* webKitWin = dynamic_cast<wxWebView*>(frame->view()->hostWindow()->platformPageClient()); 371 if (webKitWin) { 372 webKitWin->m_impl->redoStack.last().editCommand()->reapply(); 373 webKitWin->m_impl->redoStack.removeLast(); 374 } 375 } 376 } 377 378 bool EditorClientWx::handleEditingKeyboardEvent(KeyboardEvent* event) 379 { 380 Node* node = event->target()->toNode(); 381 ASSERT(node); 382 Frame* frame = node->document()->frame(); 383 ASSERT(frame); 384 385 const PlatformKeyboardEvent* keyEvent = event->keyEvent(); 386 387 //NB: this is what windows does, but they also have a keypress event for Alt+Enter which clearly won't get hit with this 388 if (!keyEvent || keyEvent->altKey()) // do not treat this as text input if Alt is down 389 return false; 390 391 Editor::Command command = frame->editor()->command(interpretKeyEvent(event)); 392 393 if (keyEvent->type() == PlatformKeyboardEvent::RawKeyDown) { 394 // WebKit doesn't have enough information about mode to decide how commands that just insert text if executed via Editor should be treated, 395 // so we leave it upon WebCore to either handle them immediately (e.g. Tab that changes focus) or if not to let a CHAR event be generated 396 // (e.g. Tab that inserts a Tab character, or Enter). 397 return !command.isTextInsertion() && command.execute(event); 398 } 399 400 if (command.execute(event)) 401 return true; 402 403 // Don't insert null or control characters as they can result in unexpected behaviour 404 if (event->charCode() < ' ') 405 return false; 406 407 return frame->editor()->insertText(event->keyEvent()->text(), event); 408 } 409 410 const char* EditorClientWx::interpretKeyEvent(const KeyboardEvent* evt) 411 { 412 ASSERT(evt->keyEvent()->type() == PlatformKeyboardEvent::RawKeyDown || evt->keyEvent()->type() == PlatformKeyboardEvent::Char); 413 414 static HashMap<int, const char*>* keyDownCommandsMap = 0; 415 static HashMap<int, const char*>* keyPressCommandsMap = 0; 416 417 if (!keyDownCommandsMap) { 418 keyDownCommandsMap = new HashMap<int, const char*>; 419 keyPressCommandsMap = new HashMap<int, const char*>; 420 421 for (unsigned i = 0; i < WXSIZEOF(keyDownEntries); i++) 422 keyDownCommandsMap->set(keyDownEntries[i].modifiers << 16 | keyDownEntries[i].virtualKey, keyDownEntries[i].name); 423 424 for (unsigned i = 0; i < WXSIZEOF(keyPressEntries); i++) 425 keyPressCommandsMap->set(keyPressEntries[i].modifiers << 16 | keyPressEntries[i].charCode, keyPressEntries[i].name); 426 } 427 428 unsigned modifiers = 0; 429 if (evt->shiftKey()) 430 modifiers |= ShiftKey; 431 if (evt->altKey()) 432 modifiers |= AltKey; 433 if (evt->ctrlKey()) 434 modifiers |= CtrlKey; 435 436 if (evt->keyEvent()->type() == PlatformKeyboardEvent::RawKeyDown) { 437 int mapKey = modifiers << 16 | evt->keyCode(); 438 return mapKey ? keyDownCommandsMap->get(mapKey) : 0; 439 } 440 441 int mapKey = modifiers << 16 | evt->charCode(); 442 return mapKey ? keyPressCommandsMap->get(mapKey) : 0; 443 } 444 445 446 void EditorClientWx::handleInputMethodKeydown(KeyboardEvent* event) 447 { 448 // NOTE: we don't currently need to handle this. When key events occur, 449 // both this method and handleKeyboardEvent get a chance at handling them. 450 // We might use this method later on for IME-specific handling. 451 } 452 453 void EditorClientWx::handleKeyboardEvent(KeyboardEvent* event) 454 { 455 if (handleEditingKeyboardEvent(event)) 456 event->setDefaultHandled(); 457 } 458 459 void EditorClientWx::textFieldDidBeginEditing(Element*) 460 { 461 notImplemented(); 462 } 463 464 void EditorClientWx::textFieldDidEndEditing(Element*) 465 { 466 notImplemented(); 467 } 468 469 void EditorClientWx::textDidChangeInTextField(Element*) 470 { 471 notImplemented(); 472 } 473 474 bool EditorClientWx::doTextFieldCommandFromEvent(Element*, KeyboardEvent*) 475 { 476 notImplemented(); 477 return false; 478 } 479 480 void EditorClientWx::textWillBeDeletedInTextField(Element*) 481 { 482 notImplemented(); 483 } 484 485 void EditorClientWx::textDidChangeInTextArea(Element*) 486 { 487 notImplemented(); 488 } 489 490 void EditorClientWx::respondToChangedSelection() 491 { 492 Frame* frame = m_page->focusController()->focusedOrMainFrame(); 493 if (frame) { 494 wxWebView* webKitWin = dynamic_cast<wxWebView*>(frame->view()->hostWindow()->platformPageClient()); 495 if (webKitWin) { 496 wxWebViewSelectionChangedEvent wkEvent(webKitWin); 497 webKitWin->GetEventHandler()->ProcessEvent(wkEvent); 498 } 499 } 500 } 501 502 void EditorClientWx::ignoreWordInSpellDocument(const String&) 503 { 504 notImplemented(); 505 } 506 507 void EditorClientWx::learnWord(const String&) 508 { 509 notImplemented(); 510 } 511 512 void EditorClientWx::checkSpellingOfString(const UChar*, int length, int* misspellingLocation, int* misspellingLength) 513 { 514 notImplemented(); 515 } 516 517 void EditorClientWx::checkGrammarOfString(const UChar*, int length, Vector<GrammarDetail>&, int* badGrammarLocation, int* badGrammarLength) 518 { 519 notImplemented(); 520 } 521 522 void EditorClientWx::updateSpellingUIWithGrammarString(const String&, const GrammarDetail& detail) 523 { 524 notImplemented(); 525 } 526 527 void EditorClientWx::updateSpellingUIWithMisspelledWord(const String&) 528 { 529 notImplemented(); 530 } 531 532 void EditorClientWx::showSpellingUI(bool show) 533 { 534 notImplemented(); 535 } 536 537 bool EditorClientWx::spellingUIIsShowing() 538 { 539 notImplemented(); 540 return false; 541 } 542 543 void EditorClientWx::getGuessesForWord(const String& word, const String& context, Vector<String>& guesses) 544 { 545 notImplemented(); 546 } 547 548 String EditorClientWx::getAutoCorrectSuggestionForMisspelledWord(const WTF::String&) 549 { 550 notImplemented(); 551 return String(); 552 } 553 554 void EditorClientWx::willSetInputMethodState() 555 { 556 notImplemented(); 557 } 558 559 void EditorClientWx::setInputMethodState(bool enabled) 560 { 561 notImplemented(); 562 } 563 564 } 565