1 /*
2 * Copyright (C) 2007 Kevin Ollivier <kevino@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
~EditorClientWx()127 EditorClientWx::~EditorClientWx()
128 {
129 m_page = NULL;
130 }
131
setPage(Page * page)132 void EditorClientWx::setPage(Page* page)
133 {
134 m_page = page;
135 }
136
pageDestroyed()137 void EditorClientWx::pageDestroyed()
138 {
139 delete this;
140 }
141
shouldDeleteRange(Range *)142 bool EditorClientWx::shouldDeleteRange(Range*)
143 {
144 notImplemented();
145 return true;
146 }
147
shouldShowDeleteInterface(HTMLElement *)148 bool EditorClientWx::shouldShowDeleteInterface(HTMLElement*)
149 {
150 notImplemented();
151 return false;
152 }
153
smartInsertDeleteEnabled()154 bool EditorClientWx::smartInsertDeleteEnabled()
155 {
156 notImplemented();
157 return false;
158 }
159
isSelectTrailingWhitespaceEnabled()160 bool EditorClientWx::isSelectTrailingWhitespaceEnabled()
161 {
162 notImplemented();
163 return false;
164 }
165
isContinuousSpellCheckingEnabled()166 bool EditorClientWx::isContinuousSpellCheckingEnabled()
167 {
168 notImplemented();
169 return false;
170 }
171
toggleContinuousSpellChecking()172 void EditorClientWx::toggleContinuousSpellChecking()
173 {
174 notImplemented();
175 }
176
isGrammarCheckingEnabled()177 bool EditorClientWx::isGrammarCheckingEnabled()
178 {
179 notImplemented();
180 return false;
181 }
182
toggleGrammarChecking()183 void EditorClientWx::toggleGrammarChecking()
184 {
185 notImplemented();
186 }
187
spellCheckerDocumentTag()188 int EditorClientWx::spellCheckerDocumentTag()
189 {
190 notImplemented();
191 return 0;
192 }
193
selectWordBeforeMenuEvent()194 bool EditorClientWx::selectWordBeforeMenuEvent()
195 {
196 notImplemented();
197 return false;
198 }
199
shouldBeginEditing(Range *)200 bool EditorClientWx::shouldBeginEditing(Range*)
201 {
202 notImplemented();
203 return true;
204 }
205
shouldEndEditing(Range *)206 bool EditorClientWx::shouldEndEditing(Range*)
207 {
208 notImplemented();
209 return true;
210 }
211
shouldInsertNode(Node *,Range *,EditorInsertAction)212 bool EditorClientWx::shouldInsertNode(Node*, Range*,
213 EditorInsertAction)
214 {
215 notImplemented();
216 return true;
217 }
218
shouldInsertText(const String &,Range *,EditorInsertAction)219 bool EditorClientWx::shouldInsertText(const String&, Range*,
220 EditorInsertAction)
221 {
222 notImplemented();
223 return true;
224 }
225
shouldApplyStyle(CSSStyleDeclaration *,Range *)226 bool EditorClientWx::shouldApplyStyle(CSSStyleDeclaration*,
227 Range*)
228 {
229 notImplemented();
230 return true;
231 }
232
shouldMoveRangeAfterDelete(Range *,Range *)233 bool EditorClientWx::shouldMoveRangeAfterDelete(Range*, Range*)
234 {
235 notImplemented();
236 return true;
237 }
238
shouldChangeSelectedRange(Range * fromRange,Range * toRange,EAffinity,bool stillSelecting)239 bool EditorClientWx::shouldChangeSelectedRange(Range* fromRange, Range* toRange,
240 EAffinity, bool stillSelecting)
241 {
242 notImplemented();
243 return true;
244 }
245
didBeginEditing()246 void EditorClientWx::didBeginEditing()
247 {
248 notImplemented();
249 }
250
respondToChangedContents()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
didEndEditing()264 void EditorClientWx::didEndEditing()
265 {
266 notImplemented();
267 }
268
didWriteSelectionToPasteboard()269 void EditorClientWx::didWriteSelectionToPasteboard()
270 {
271 notImplemented();
272 }
273
didSetSelectionTypesForPasteboard()274 void EditorClientWx::didSetSelectionTypesForPasteboard()
275 {
276 notImplemented();
277 }
278
registerCommandForUndo(PassRefPtr<EditCommand> command)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
registerCommandForRedo(PassRefPtr<EditCommand> command)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
clearUndoRedoOperations()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
canCopyCut(bool defaultValue) const316 bool EditorClientWx::canCopyCut(bool defaultValue) const
317 {
318 return defaultValue;
319 }
320
canPaste(bool defaultValue) const321 bool EditorClientWx::canPaste(bool defaultValue) const
322 {
323 return defaultValue;
324 }
325
canUndo() const326 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
canRedo() const339 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
undo()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
redo()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
handleEditingKeyboardEvent(KeyboardEvent * event)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
interpretKeyEvent(const KeyboardEvent * evt)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
handleInputMethodKeydown(KeyboardEvent * event)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
handleKeyboardEvent(KeyboardEvent * event)453 void EditorClientWx::handleKeyboardEvent(KeyboardEvent* event)
454 {
455 if (handleEditingKeyboardEvent(event))
456 event->setDefaultHandled();
457 }
458
textFieldDidBeginEditing(Element *)459 void EditorClientWx::textFieldDidBeginEditing(Element*)
460 {
461 notImplemented();
462 }
463
textFieldDidEndEditing(Element *)464 void EditorClientWx::textFieldDidEndEditing(Element*)
465 {
466 notImplemented();
467 }
468
textDidChangeInTextField(Element *)469 void EditorClientWx::textDidChangeInTextField(Element*)
470 {
471 notImplemented();
472 }
473
doTextFieldCommandFromEvent(Element *,KeyboardEvent *)474 bool EditorClientWx::doTextFieldCommandFromEvent(Element*, KeyboardEvent*)
475 {
476 notImplemented();
477 return false;
478 }
479
textWillBeDeletedInTextField(Element *)480 void EditorClientWx::textWillBeDeletedInTextField(Element*)
481 {
482 notImplemented();
483 }
484
textDidChangeInTextArea(Element *)485 void EditorClientWx::textDidChangeInTextArea(Element*)
486 {
487 notImplemented();
488 }
489
respondToChangedSelection()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
ignoreWordInSpellDocument(const String &)502 void EditorClientWx::ignoreWordInSpellDocument(const String&)
503 {
504 notImplemented();
505 }
506
learnWord(const String &)507 void EditorClientWx::learnWord(const String&)
508 {
509 notImplemented();
510 }
511
checkSpellingOfString(const UChar *,int length,int * misspellingLocation,int * misspellingLength)512 void EditorClientWx::checkSpellingOfString(const UChar*, int length, int* misspellingLocation, int* misspellingLength)
513 {
514 notImplemented();
515 }
516
checkGrammarOfString(const UChar *,int length,Vector<GrammarDetail> &,int * badGrammarLocation,int * badGrammarLength)517 void EditorClientWx::checkGrammarOfString(const UChar*, int length, Vector<GrammarDetail>&, int* badGrammarLocation, int* badGrammarLength)
518 {
519 notImplemented();
520 }
521
updateSpellingUIWithGrammarString(const String &,const GrammarDetail & detail)522 void EditorClientWx::updateSpellingUIWithGrammarString(const String&, const GrammarDetail& detail)
523 {
524 notImplemented();
525 }
526
updateSpellingUIWithMisspelledWord(const String &)527 void EditorClientWx::updateSpellingUIWithMisspelledWord(const String&)
528 {
529 notImplemented();
530 }
531
showSpellingUI(bool show)532 void EditorClientWx::showSpellingUI(bool show)
533 {
534 notImplemented();
535 }
536
spellingUIIsShowing()537 bool EditorClientWx::spellingUIIsShowing()
538 {
539 notImplemented();
540 return false;
541 }
542
getGuessesForWord(const String & word,const String & context,Vector<String> & guesses)543 void EditorClientWx::getGuessesForWord(const String& word, const String& context, Vector<String>& guesses)
544 {
545 notImplemented();
546 }
547
getAutoCorrectSuggestionForMisspelledWord(const WTF::String &)548 String EditorClientWx::getAutoCorrectSuggestionForMisspelledWord(const WTF::String&)
549 {
550 notImplemented();
551 return String();
552 }
553
willSetInputMethodState()554 void EditorClientWx::willSetInputMethodState()
555 {
556 notImplemented();
557 }
558
setInputMethodState(bool enabled)559 void EditorClientWx::setInputMethodState(bool enabled)
560 {
561 notImplemented();
562 }
563
564 }
565