KHtml

dom2_eventsimpl.cpp
1 /**
2  * This file is part of the DOM implementation for KDE.
3  *
4  * Copyright (C) 2001 Peter Kelly ([email protected])
5  * (C) 2001 Tobias Anton ([email protected])
6  * (C) 2003 Apple Computer, Inc.
7  * (C) 2006, 2010 Maksim Orlovich ([email protected])
8  *
9  * This library is free software; you can redistribute it and/or
10  * modify it under the terms of the GNU Library General Public
11  * License as published by the Free Software Foundation; either
12  * version 2 of the License, or (at your option) any later version.
13  *
14  * This library is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17  * Library General Public License for more details.
18  *
19  * You should have received a copy of the GNU Library General Public License
20  * along with this library; see the file COPYING.LIB. If not, write to
21  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
22  * Boston, MA 02110-1301, USA.
23 
24  */
25 
26 #include "dom2_eventsimpl.h"
27 
28 #include <dom/dom2_views.h>
29 
30 #include "dom_stringimpl.h"
31 #include "dom_nodeimpl.h"
32 #include "dom_docimpl.h"
33 #include "misc/translator.h"
34 #include <rendering/render_layer.h>
35 #include <khtmlview.h>
36 #include <khtml_part.h>
37 
38 #include <QActionEvent>
39 #include "khtml_debug.h"
40 
41 using namespace DOM;
42 using namespace khtml;
43 
44 void EventTargetImpl::handleLocalEvents(EventImpl *evt, bool useCapture)
45 {
46  if (!m_regdListeners.listeners) {
47  return;
48  }
49 
50  Event ev = evt;
51  // removeEventListener (e.g. called from a JS event listener) might
52  // invalidate the item after the current iterator (which "it" is pointing to).
53  // So we make a copy of the list.
54  QList<RegisteredEventListener> listeners = *m_regdListeners.listeners;
56  for (it = listeners.begin(); it != listeners.end(); ++it) {
57  //Check whether this got removed... TODO: use Java-style iterators
58  if (!m_regdListeners.stillContainsListener(*it)) {
59  continue;
60  }
61 
62  RegisteredEventListener &current = (*it);
63  if (current.eventName == evt->name() && current.useCapture == useCapture) {
64  current.listener->handleEvent(ev);
65  }
66 
67  // ECMA legacy hack
68  if (current.useCapture == useCapture && evt->id() == EventImpl::CLICK_EVENT) {
69  MouseEventImpl *me = static_cast<MouseEventImpl *>(evt);
70  if (me->button() == 0) {
71  // To find whether to call onclick or ondblclick, we can't
72  // * use me->detail(), it's 2 when clicking twice w/o moving, even very slowly
73  // * use me->qEvent(), it's not available when using initMouseEvent/dispatchEvent
74  // So we currently store a bool in MouseEventImpl. If anyone needs to trigger
75  // dblclicks from the DOM API, we'll need a timer here (well in the doc).
76  if ((!me->isDoubleClick() && current.eventName.id() == EventImpl::KHTML_ECMA_CLICK_EVENT) ||
77  (me->isDoubleClick() && current.eventName.id() == EventImpl::KHTML_ECMA_DBLCLICK_EVENT)) {
78  current.listener->handleEvent(ev);
79  }
80  }
81  }
82  }
83 }
84 
85 void EventTargetImpl::defaultEventHandler(EventImpl *)
86 {}
87 
88 DocumentImpl *EventTargetImpl::eventTargetDocument()
89 {
90  return nullptr;
91 }
92 
93 void EventTargetImpl::setDocListenerFlag(unsigned flag)
94 {
95  DocumentImpl *doc = eventTargetDocument();
96  if (doc) {
97  doc->addListenerType(DocumentImpl::ListenerType(flag));
98  }
99 }
100 
101 void EventTargetImpl::addEventListener(EventName id, EventListener *listener, const bool useCapture)
102 {
103  switch (id.id()) {
104  case EventImpl::DOMSUBTREEMODIFIED_EVENT:
105  setDocListenerFlag(DocumentImpl::DOMSUBTREEMODIFIED_LISTENER);
106  break;
107  case EventImpl::DOMNODEINSERTED_EVENT:
108  setDocListenerFlag(DocumentImpl::DOMNODEINSERTED_LISTENER);
109  break;
110  case EventImpl::DOMNODEREMOVED_EVENT:
111  setDocListenerFlag(DocumentImpl::DOMNODEREMOVED_LISTENER);
112  break;
113  case EventImpl::DOMNODEREMOVEDFROMDOCUMENT_EVENT:
114  setDocListenerFlag(DocumentImpl::DOMNODEREMOVEDFROMDOCUMENT_LISTENER);
115  break;
116  case EventImpl::DOMNODEINSERTEDINTODOCUMENT_EVENT:
117  setDocListenerFlag(DocumentImpl::DOMNODEINSERTEDINTODOCUMENT_LISTENER);
118  break;
119  case EventImpl::DOMATTRMODIFIED_EVENT:
120  setDocListenerFlag(DocumentImpl::DOMATTRMODIFIED_LISTENER);
121  break;
122  case EventImpl::DOMCHARACTERDATAMODIFIED_EVENT:
123  setDocListenerFlag(DocumentImpl::DOMCHARACTERDATAMODIFIED_LISTENER);
124  break;
125  default:
126  break;
127  }
128 
129  m_regdListeners.addEventListener(id, listener, useCapture);
130 }
131 
132 void EventTargetImpl::removeEventListener(EventName id, EventListener *listener, bool useCapture)
133 {
134  m_regdListeners.removeEventListener(id, listener, useCapture);
135 }
136 
137 void EventTargetImpl::setHTMLEventListener(EventName id, EventListener *listener)
138 {
139  m_regdListeners.setHTMLEventListener(id, listener);
140 }
141 
142 void EventTargetImpl::setHTMLEventListener(unsigned id, EventListener *listener)
143 {
144  m_regdListeners.setHTMLEventListener(EventName::fromId(id), listener);
145 }
146 
147 EventListener *EventTargetImpl::getHTMLEventListener(EventName id)
148 {
149  return m_regdListeners.getHTMLEventListener(id);
150 }
151 
152 EventListener *EventTargetImpl::getHTMLEventListener(unsigned id)
153 {
154  return m_regdListeners.getHTMLEventListener(EventName::fromId(id));
155 }
156 // -----------------------------------------------------------------------------
157 
158 void RegisteredListenerList::addEventListener(EventName id, EventListener *listener, const bool useCapture)
159 {
160  if (!listener) {
161  return;
162  }
163  RegisteredEventListener rl(id, listener, useCapture);
164  if (!listeners) {
165  listeners = new QList<RegisteredEventListener>;
166  }
167 
168  // if this id/listener/useCapture combination is already registered, do nothing.
169  // the DOM2 spec says that "duplicate instances are discarded", and this keeps
170  // the listener order intact.
172  for (it = listeners->begin(); it != listeners->end(); ++it)
173  if (*it == rl) {
174  return;
175  }
176 
177  listeners->append(rl);
178 }
179 
180 void RegisteredListenerList::removeEventListener(EventName id, EventListener *listener, bool useCapture)
181 {
182  if (!listeners) { // nothing to remove
183  return;
184  }
185 
186  RegisteredEventListener rl(id, listener, useCapture);
187 
189  for (it = listeners->begin(); it != listeners->end(); ++it)
190  if (*it == rl) {
191  listeners->erase(it);
192  return;
193  }
194 }
195 
196 bool RegisteredListenerList::isHTMLEventListener(EventListener *listener)
197 {
198  return (listener->eventListenerType() == "_khtml_HTMLEventListener");
199 }
200 
201 void RegisteredListenerList::setHTMLEventListener(EventName name, EventListener *listener)
202 {
203  if (!listeners) {
204  listeners = new QList<RegisteredEventListener>;
205  }
206 
208  if (!listener) {
209  for (it = listeners->begin(); it != listeners->end(); ++it) {
210  if ((*it).eventName == name && isHTMLEventListener((*it).listener)) {
211  listeners->erase(it);
212  break;
213  }
214  }
215  return;
216  }
217 
218  // if this event already has a registered handler, insert the new one in
219  // place of the old one, to preserve the order.
220  RegisteredEventListener rl(name, listener, false);
221 
222  for (int i = 0; i < listeners->size(); ++i) {
223  const RegisteredEventListener &listener = listeners->at(i);
224  if (listener.eventName == name && isHTMLEventListener(listener.listener)) {
225  listeners->replace(i, rl);
226  return;
227  }
228  }
229 
230  listeners->append(rl);
231 }
232 
233 EventListener *RegisteredListenerList::getHTMLEventListener(EventName name)
234 {
235  if (!listeners) {
236  return nullptr;
237  }
238 
240  for (it = listeners->begin(); it != listeners->end(); ++it)
241  if ((*it).eventName == name && isHTMLEventListener((*it).listener)) {
242  return (*it).listener;
243  }
244  return nullptr;
245 }
246 
247 bool RegisteredListenerList::hasEventListener(EventName name)
248 {
249  if (!listeners) {
250  return false;
251  }
252 
254  for (it = listeners->begin(); it != listeners->end(); ++it)
255  if ((*it).eventName == name) {
256  return true;
257  }
258 
259  return false;
260 }
261 
262 void RegisteredListenerList::clear()
263 {
264  delete listeners;
265  listeners = nullptr;
266 }
267 
268 bool RegisteredListenerList::stillContainsListener(const RegisteredEventListener &listener)
269 {
270  if (!listeners) {
271  return false;
272  }
273  return listeners->contains(listener);
274 }
275 
276 RegisteredListenerList::~RegisteredListenerList()
277 {
278  delete listeners; listeners = nullptr;
279 }
280 
281 // -----------------------------------------------------------------------------
282 
283 EventImpl::EventImpl()
284 {
285  m_canBubble = false;
286  m_cancelable = false;
287 
288  m_propagationStopped = false;
289  m_defaultPrevented = false;
290  m_currentTarget = nullptr;
291  m_eventPhase = 0;
292  m_target = nullptr;
293  m_createTime = QDateTime::currentDateTime();
294  m_defaultHandled = false;
295 }
296 
297 EventImpl::EventImpl(EventId _id, bool canBubbleArg, bool cancelableArg)
298 {
299  m_eventName = EventName::fromId(_id);
300  m_canBubble = canBubbleArg;
301  m_cancelable = cancelableArg;
302 
303  m_propagationStopped = false;
304  m_defaultPrevented = false;
305  m_currentTarget = nullptr;
306  m_eventPhase = 0;
307  m_target = nullptr;
308  m_createTime = QDateTime::currentDateTime();
309  m_defaultHandled = false;
310 }
311 
312 EventImpl::~EventImpl()
313 {
314  if (m_target) {
315  m_target->deref();
316  }
317 }
318 
319 void EventImpl::setTarget(EventTargetImpl *_target)
320 {
321  if (m_target) {
322  m_target->deref();
323  }
324  m_target = _target;
325  if (m_target) {
326  m_target->ref();
327  }
328 }
329 
330 DOMTimeStamp EventImpl::timeStamp()
331 {
332  QDateTime epoch(QDate(1970, 1, 1), QTime(0, 0));
333  // ### kjs does not yet support long long (?) so the value wraps around
334  return epoch.secsTo(m_createTime) * 1000 + m_createTime.time().msec();
335 }
336 
337 void EventImpl::initEvent(const DOMString &eventTypeArg, bool canBubbleArg, bool cancelableArg)
338 {
339  // ### ensure this is not called after we have been dispatched (also for subclasses)
340 
341  m_eventName = EventName::fromString(eventTypeArg);
342 
343  m_canBubble = canBubbleArg;
344  m_cancelable = cancelableArg;
345 }
346 
347 khtml::IDTable<EventImpl> *EventImpl::s_idTable;
348 
349 khtml::IDTable<EventImpl> *EventImpl::initIdTable()
350 {
351  s_idTable = new khtml::IDTable<EventImpl>();
352  s_idTable->addStaticMapping(DOMFOCUSIN_EVENT, "DOMFocusIn");
353  s_idTable->addStaticMapping(DOMFOCUSOUT_EVENT, "DOMFocusOut");
354  s_idTable->addStaticMapping(DOMACTIVATE_EVENT, "DOMActivate");
355  s_idTable->addStaticMapping(CLICK_EVENT, "click");
356  s_idTable->addStaticMapping(MOUSEDOWN_EVENT, "mousedown");
357  s_idTable->addStaticMapping(MOUSEUP_EVENT, "mouseup");
358  s_idTable->addStaticMapping(MOUSEOVER_EVENT, "mouseover");
359  s_idTable->addStaticMapping(MOUSEMOVE_EVENT, "mousemove");
360  s_idTable->addStaticMapping(MOUSEOUT_EVENT, "mouseout");
361  s_idTable->addStaticMapping(DOMSUBTREEMODIFIED_EVENT, "DOMSubtreeModified");
362  s_idTable->addStaticMapping(DOMNODEINSERTED_EVENT, "DOMNodeInserted");
363  s_idTable->addStaticMapping(DOMNODEREMOVED_EVENT, "DOMNodeRemoved");
364  s_idTable->addStaticMapping(DOMNODEREMOVEDFROMDOCUMENT_EVENT, "DOMNodeRemovedFromDocument");
365  s_idTable->addStaticMapping(DOMNODEINSERTEDINTODOCUMENT_EVENT, "DOMNodeInsertedIntoDocument");
366  s_idTable->addStaticMapping(DOMATTRMODIFIED_EVENT, "DOMAttrModified");
367  s_idTable->addStaticMapping(DOMCHARACTERDATAMODIFIED_EVENT, "DOMCharacterDataModified");
368  s_idTable->addStaticMapping(LOAD_EVENT, "load");
369  s_idTable->addStaticMapping(UNLOAD_EVENT, "unload");
370  s_idTable->addStaticMapping(ABORT_EVENT, "abort");
371  s_idTable->addStaticMapping(ERROR_EVENT, "error");
372  s_idTable->addStaticMapping(SELECT_EVENT, "select");
373  s_idTable->addStaticMapping(CHANGE_EVENT, "change");
374  s_idTable->addStaticMapping(SUBMIT_EVENT, "submit");
375  s_idTable->addStaticMapping(RESET_EVENT, "reset");
376  s_idTable->addStaticMapping(FOCUS_EVENT, "focus");
377  s_idTable->addStaticMapping(BLUR_EVENT, "blur");
378  s_idTable->addStaticMapping(RESIZE_EVENT, "resize");
379  s_idTable->addStaticMapping(SCROLL_EVENT, "scroll");
380  s_idTable->addStaticMapping(KEYDOWN_EVENT, "keydown");
381  s_idTable->addStaticMapping(KEYUP_EVENT, "keyup");
382  s_idTable->addStaticMapping(KEYPRESS_EVENT, "keypress");
383  //DOM3 ev. suggests textInput, but it's better for compat this way
384  s_idTable->addStaticMapping(HASHCHANGE_EVENT, "hashchange");
385 
386  //khtml extensions
387  s_idTable->addStaticMapping(KHTML_ECMA_DBLCLICK_EVENT, "dblclick");
388  s_idTable->addHiddenMapping(KHTML_ECMA_CLICK_EVENT, "click");
389  s_idTable->addStaticMapping(KHTML_DRAGDROP_EVENT, "khtml_dragdrop");
390  s_idTable->addStaticMapping(KHTML_MOVE_EVENT, "khtml_move");
391  s_idTable->addStaticMapping(KHTML_MOUSEWHEEL_EVENT, "DOMMouseScroll");
392  // adopt the mozilla name for compatibility
393  s_idTable->addStaticMapping(KHTML_CONTENTLOADED_EVENT, "DOMContentLoaded");
394  // idem
395  s_idTable->addStaticMapping(KHTML_READYSTATECHANGE_EVENT, "readystatechange");
396 
397  s_idTable->addStaticMapping(MESSAGE_EVENT, "message");
398 
399  return s_idTable;
400 }
401 
402 bool EventImpl::isUIEvent() const
403 {
404  return false;
405 }
406 
407 bool EventImpl::isMouseEvent() const
408 {
409  return false;
410 }
411 
412 bool EventImpl::isMutationEvent() const
413 {
414  return false;
415 }
416 
417 bool EventImpl::isTextInputEvent() const
418 {
419  return false;
420 }
421 
422 bool EventImpl::isKeyboardEvent() const
423 {
424  return false;
425 }
426 
427 bool EventImpl::isMessageEvent() const
428 {
429  return false;
430 }
431 
432 bool EventImpl::isHashChangeEvent() const
433 {
434  return false;
435 }
436 
437 // -----------------------------------------------------------------------------
438 
439 UIEventImpl::UIEventImpl(EventId _id, bool canBubbleArg, bool cancelableArg,
440  AbstractViewImpl *viewArg, long detailArg)
441  : EventImpl(_id, canBubbleArg, cancelableArg)
442 {
443  m_view = viewArg;
444  if (m_view) {
445  m_view->ref();
446  }
447  m_detail = detailArg;
448 }
449 
450 UIEventImpl::~UIEventImpl()
451 {
452  if (m_view) {
453  m_view->deref();
454  }
455 }
456 
457 void UIEventImpl::initUIEvent(const DOMString &typeArg,
458  bool canBubbleArg,
459  bool cancelableArg,
460  AbstractViewImpl *viewArg,
461  long detailArg)
462 {
463  EventImpl::initEvent(typeArg, canBubbleArg, cancelableArg);
464 
465  if (viewArg) {
466  viewArg->ref();
467  }
468 
469  if (m_view) {
470  m_view->deref();
471  }
472 
473  m_view = viewArg;
474 
475  m_detail = detailArg;
476 }
477 
478 bool UIEventImpl::isUIEvent() const
479 {
480  return true;
481 }
482 
483 // -----------------------------------------------------------------------------
484 
485 MouseEventImpl::MouseEventImpl()
486 {
487  m_screenX = 0;
488  m_screenY = 0;
489  m_clientX = 0;
490  m_clientY = 0;
491  m_pageX = 0;
492  m_pageY = 0;
493  m_ctrlKey = false;
494  m_altKey = false;
495  m_shiftKey = false;
496  m_metaKey = false;
497  m_button = 0;
498  m_relatedTarget = nullptr;
499  m_qevent = nullptr;
500  m_isDoubleClick = false;
501 }
502 
503 MouseEventImpl::MouseEventImpl(EventId _id,
504  bool canBubbleArg,
505  bool cancelableArg,
506  AbstractViewImpl *viewArg,
507  long detailArg,
508  long screenXArg,
509  long screenYArg,
510  long clientXArg,
511  long clientYArg,
512  long pageXArg,
513  long pageYArg,
514  bool ctrlKeyArg,
515  bool altKeyArg,
516  bool shiftKeyArg,
517  bool metaKeyArg,
518  unsigned short buttonArg,
519  NodeImpl *relatedTargetArg,
520  QMouseEvent *qe,
521  bool isDoubleClick,
522  Orientation orient)
523  : UIEventImpl(_id, canBubbleArg, cancelableArg, viewArg, detailArg)
524 {
525  m_screenX = screenXArg;
526  m_screenY = screenYArg;
527  m_clientX = clientXArg;
528  m_clientY = clientYArg;
529  m_pageX = pageXArg;
530  m_pageY = pageYArg;
531  m_ctrlKey = ctrlKeyArg;
532  m_altKey = altKeyArg;
533  m_shiftKey = shiftKeyArg;
534  m_metaKey = metaKeyArg;
535  m_button = buttonArg;
536  m_relatedTarget = relatedTargetArg;
537  if (m_relatedTarget) {
538  m_relatedTarget->ref();
539  }
540  computeLayerPos();
541  m_qevent = qe;
542  m_isDoubleClick = isDoubleClick;
543  m_orientation = orient;
544 }
545 
546 MouseEventImpl::~MouseEventImpl()
547 {
548  if (m_relatedTarget) {
549  m_relatedTarget->deref();
550  }
551 }
552 
553 void MouseEventImpl::computeLayerPos()
554 {
555  m_layerX = m_pageX;
556  m_layerY = m_pageY;
557 
558  DocumentImpl *doc = view() ? view()->document() : nullptr;
559  if (doc && doc->renderer()) {
560  khtml::RenderObject::NodeInfo renderInfo(true, false);
561  doc->renderer()->layer()->nodeAtPoint(renderInfo, m_pageX, m_pageY);
562 
563  NodeImpl *node = renderInfo.innerNonSharedNode();
564  while (node && !node->renderer()) {
565  node = node->parent();
566  }
567 
568  if (node) {
569  RenderLayer *layer = node->renderer()->enclosingLayer();
570  if (layer) {
571  layer->updateLayerPosition();
572  }
573 
574  while (layer) {
575  m_layerX -= layer->xPos();
576  m_layerY -= layer->yPos();
577  layer = layer->parent();
578  }
579  }
580  }
581 }
582 
583 void MouseEventImpl::initMouseEvent(const DOMString &typeArg,
584  bool canBubbleArg,
585  bool cancelableArg,
586  AbstractViewImpl *viewArg,
587  long detailArg,
588  long screenXArg,
589  long screenYArg,
590  long clientXArg,
591  long clientYArg,
592  bool ctrlKeyArg,
593  bool altKeyArg,
594  bool shiftKeyArg,
595  bool metaKeyArg,
596  unsigned short buttonArg,
597  const Node &relatedTargetArg,
598  Orientation orient)
599 {
600  UIEventImpl::initUIEvent(typeArg, canBubbleArg, cancelableArg, viewArg, detailArg);
601 
602  if (m_relatedTarget) {
603  m_relatedTarget->deref();
604  }
605 
606  m_screenX = screenXArg;
607  m_screenY = screenYArg;
608  m_clientX = clientXArg;
609  m_clientY = clientYArg;
610  m_pageX = clientXArg;
611  m_pageY = clientYArg;
612  KHTMLView *v;
613  if (view() && view()->document() && (v = view()->document()->view())) {
614  m_pageX += v->contentsX();
615  m_pageY += v->contentsY();
616  }
617  m_ctrlKey = ctrlKeyArg;
618  m_altKey = altKeyArg;
619  m_shiftKey = shiftKeyArg;
620  m_metaKey = metaKeyArg;
621  m_button = buttonArg;
622  m_relatedTarget = relatedTargetArg.handle();
623  if (m_relatedTarget) {
624  m_relatedTarget->ref();
625  }
626  m_orientation = orient;
627 
628  // ### make this on-demand. it is soo sloooow
629  computeLayerPos();
630  m_qevent = nullptr;
631 }
632 
633 bool MouseEventImpl::isMouseEvent() const
634 {
635  return true;
636 }
637 
638 //---------------------------------------------------------------------------------------------
639 
640 /* Mapping between special Qt keycodes and virtual DOM codes */
641 IDTranslator<unsigned, unsigned, unsigned>::Info virtKeyToQtKeyTable[] = {
642  {KeyEventBaseImpl::DOM_VK_BACK_SPACE, Qt::Key_Backspace},
643  {KeyEventBaseImpl::DOM_VK_ENTER, Qt::Key_Enter},
644  {KeyEventBaseImpl::DOM_VK_ENTER, Qt::Key_Return},
645  {KeyEventBaseImpl::DOM_VK_NUM_LOCK, Qt::Key_NumLock},
646  {KeyEventBaseImpl::DOM_VK_RIGHT_ALT, Qt::Key_Alt},
647  {KeyEventBaseImpl::DOM_VK_LEFT_CONTROL, Qt::Key_Control},
648  {KeyEventBaseImpl::DOM_VK_LEFT_SHIFT, Qt::Key_Shift},
649  {KeyEventBaseImpl::DOM_VK_META, Qt::Key_Meta},
650  {KeyEventBaseImpl::DOM_VK_CAPS_LOCK, Qt::Key_CapsLock},
651  {KeyEventBaseImpl::DOM_VK_DELETE, Qt::Key_Delete},
652  {KeyEventBaseImpl::DOM_VK_INSERT, Qt::Key_Insert},
653  {KeyEventBaseImpl::DOM_VK_END, Qt::Key_End},
654  {KeyEventBaseImpl::DOM_VK_ESCAPE, Qt::Key_Escape},
655  {KeyEventBaseImpl::DOM_VK_HOME, Qt::Key_Home},
656  {KeyEventBaseImpl::DOM_VK_PAUSE, Qt::Key_Pause},
657  {KeyEventBaseImpl::DOM_VK_PRINTSCREEN, Qt::Key_Print},
658  {KeyEventBaseImpl::DOM_VK_SCROLL_LOCK, Qt::Key_ScrollLock},
659  {KeyEventBaseImpl::DOM_VK_LEFT, Qt::Key_Left},
660  {KeyEventBaseImpl::DOM_VK_RIGHT, Qt::Key_Right},
661  {KeyEventBaseImpl::DOM_VK_UP, Qt::Key_Up},
662  {KeyEventBaseImpl::DOM_VK_DOWN, Qt::Key_Down},
663  {KeyEventBaseImpl::DOM_VK_PAGE_DOWN, Qt::Key_PageDown},
664  {KeyEventBaseImpl::DOM_VK_PAGE_UP, Qt::Key_PageUp},
665  {KeyEventBaseImpl::DOM_VK_F1, Qt::Key_F1},
666  {KeyEventBaseImpl::DOM_VK_F2, Qt::Key_F2},
667  {KeyEventBaseImpl::DOM_VK_F3, Qt::Key_F3},
668  {KeyEventBaseImpl::DOM_VK_F4, Qt::Key_F4},
669  {KeyEventBaseImpl::DOM_VK_F5, Qt::Key_F5},
670  {KeyEventBaseImpl::DOM_VK_F6, Qt::Key_F6},
671  {KeyEventBaseImpl::DOM_VK_F7, Qt::Key_F7},
672  {KeyEventBaseImpl::DOM_VK_F8, Qt::Key_F8},
673  {KeyEventBaseImpl::DOM_VK_F9, Qt::Key_F9},
674  {KeyEventBaseImpl::DOM_VK_F10, Qt::Key_F10},
675  {KeyEventBaseImpl::DOM_VK_F11, Qt::Key_F11},
676  {KeyEventBaseImpl::DOM_VK_F12, Qt::Key_F12},
677  {KeyEventBaseImpl::DOM_VK_F13, Qt::Key_F13},
678  {KeyEventBaseImpl::DOM_VK_F14, Qt::Key_F14},
679  {KeyEventBaseImpl::DOM_VK_F15, Qt::Key_F15},
680  {KeyEventBaseImpl::DOM_VK_F16, Qt::Key_F16},
681  {KeyEventBaseImpl::DOM_VK_F17, Qt::Key_F17},
682  {KeyEventBaseImpl::DOM_VK_F18, Qt::Key_F18},
683  {KeyEventBaseImpl::DOM_VK_F19, Qt::Key_F19},
684  {KeyEventBaseImpl::DOM_VK_F20, Qt::Key_F20},
685  {KeyEventBaseImpl::DOM_VK_F21, Qt::Key_F21},
686  {KeyEventBaseImpl::DOM_VK_F22, Qt::Key_F22},
687  {KeyEventBaseImpl::DOM_VK_F23, Qt::Key_F23},
688  {KeyEventBaseImpl::DOM_VK_F24, Qt::Key_F24},
689  {0, 0}
690 };
691 
692 MAKE_TRANSLATOR(virtKeyToQtKey, unsigned, unsigned, unsigned, virtKeyToQtKeyTable)
693 
694 KeyEventBaseImpl::KeyEventBaseImpl(EventId id, bool canBubbleArg, bool cancelableArg, AbstractViewImpl *viewArg,
695  QKeyEvent *key) :
696  UIEventImpl(id, canBubbleArg, cancelableArg, viewArg, 0)
697 {
698  m_synthetic = false;
699 
700  m_keyEvent = new QKeyEvent(key->type(), key->key(), key->modifiers(), key->text(), key->isAutoRepeat(), key->count());
701 
702  //Here, we need to map Qt's internal info to browser-style info.
703  m_detail = key->count();
704  m_keyVal = 0; // Set below unless virtual...
705  m_virtKeyVal = virtKeyToQtKey()->toLeft(key->key());
706 
707  // m_keyVal should contain the unicode value
708  // of the pressed key if available, including case distinction
709  if (m_virtKeyVal == DOM_VK_UNDEFINED && !key->text().isEmpty()) {
710  // ... unfortunately, this value is useless if ctrl+ or alt+ are used.
711  if (key->modifiers() & (Qt::ControlModifier | Qt::AltModifier | Qt::MetaModifier)) {
712  // Try to recover the case... Not quite right with caps lock involved, hence proving again its evilness
713  if (key->modifiers() & (Qt::ShiftModifier)) {
714  m_keyVal = key->key(); // The original is upper case anyway
715  } else {
716  m_keyVal = QChar(key->key()).toLower().unicode();
717  }
718  } else {
719  m_keyVal = key->text().unicode()[0].unicode();
720  }
721  }
722 
723  // key->state returns enum ButtonState, which is ShiftButton, ControlButton and AltButton or'ed together.
724  m_modifier = key->modifiers();
725 }
726 
727 KeyEventBaseImpl::~KeyEventBaseImpl()
728 {
729  delete m_keyEvent;
730 }
731 
732 void KeyEventBaseImpl::initKeyBaseEvent(const DOMString &typeArg,
733  bool canBubbleArg,
734  bool cancelableArg,
735  AbstractViewImpl *viewArg,
736  unsigned long keyValArg,
737  unsigned long virtKeyValArg,
738  unsigned long modifiersArg)
739 {
740  m_synthetic = true;
741  delete m_keyEvent;
742  m_keyEvent = nullptr;
743  initUIEvent(typeArg, canBubbleArg, cancelableArg, viewArg, 1);
744  m_virtKeyVal = virtKeyValArg;
745  m_keyVal = keyValArg;
746  m_modifier = modifiersArg;
747 }
748 
749 bool KeyEventBaseImpl::checkModifier(unsigned long modifierArg)
750 {
751  return ((m_modifier & modifierArg) == modifierArg);
752 }
753 
754 void KeyEventBaseImpl::buildQKeyEvent() const
755 {
756  delete m_keyEvent;
757 
758  assert(m_synthetic);
759  //IMPORTANT: we ignore modifers on purpose.
760  //this is to prevent a website from synthesizing something
761  //like Ctrl-V or Shift-Insert and stealing contents of the user's clipboard.
762  Qt::KeyboardModifiers modifiers = nullptr;
763 
764  if (m_modifier & Qt::KeypadModifier) {
765  modifiers |= Qt::KeypadModifier;
766  }
767 
768  int key = 0;
769  QString text;
770  if (m_virtKeyVal) {
771  key = virtKeyToQtKey()->toRight(m_virtKeyVal);
772  }
773  if (!key) {
774  key = m_keyVal;
775  text = QChar(key);
776  }
777 
778  //Neuter F keys as well.
779  if (key >= Qt::Key_F1 && key <= Qt::Key_F35) {
780  key = Qt::Key_ScrollLock;
781  }
782 
783  m_keyEvent = new QKeyEvent(id() == KEYUP_EVENT ? QEvent::KeyRelease : QEvent::KeyPress,
784  key, modifiers, text);
785 }
786 
787 //------------------------------------------------------------------------------
788 
789 static const IDTranslator<QByteArray, unsigned, const char *>::Info keyIdentifiersToVirtKeysTable[] = {
790  {"Alt", KeyEventBaseImpl::DOM_VK_LEFT_ALT},
791  {"Control", KeyEventBaseImpl::DOM_VK_LEFT_CONTROL},
792  {"Shift", KeyEventBaseImpl::DOM_VK_LEFT_SHIFT},
793  {"Meta", KeyEventBaseImpl::DOM_VK_META},
794  {"\0x08", KeyEventBaseImpl::DOM_VK_SPACE}, //1-char virt!
795  {"CapsLock", KeyEventBaseImpl::DOM_VK_CAPS_LOCK},
796  {"\x7F", KeyEventBaseImpl::DOM_VK_DELETE}, //1-char virt!
797  {"End", KeyEventBaseImpl::DOM_VK_END},
798  {"Enter", KeyEventBaseImpl::DOM_VK_ENTER},
799  {"\x1b", KeyEventBaseImpl::DOM_VK_ESCAPE}, //1-char virt!
800  {"Home", KeyEventBaseImpl::DOM_VK_HOME},
801  {"NumLock", KeyEventBaseImpl::DOM_VK_NUM_LOCK},
802  {"Pause", KeyEventBaseImpl::DOM_VK_PAUSE},
803  {"PrintScreen", KeyEventBaseImpl::DOM_VK_PRINTSCREEN},
804  {"Scroll", KeyEventBaseImpl::DOM_VK_SCROLL_LOCK},
805  {" ", KeyEventBaseImpl::DOM_VK_SPACE}, //1-char virt!
806  {"\t", KeyEventBaseImpl::DOM_VK_TAB}, //1-char virt!
807  {"Left", KeyEventBaseImpl::DOM_VK_LEFT},
808  {"Left", KeyEventBaseImpl::DOM_VK_LEFT},
809  {"Right", KeyEventBaseImpl::DOM_VK_RIGHT},
810  {"Up", KeyEventBaseImpl::DOM_VK_UP},
811  {"Down", KeyEventBaseImpl::DOM_VK_DOWN},
812  {"PageDown", KeyEventBaseImpl::DOM_VK_PAGE_DOWN},
813  {"PageUp", KeyEventBaseImpl::DOM_VK_PAGE_UP},
814  {"F1", KeyEventBaseImpl::DOM_VK_F1},
815  {"F2", KeyEventBaseImpl::DOM_VK_F2},
816  {"F3", KeyEventBaseImpl::DOM_VK_F3},
817  {"F4", KeyEventBaseImpl::DOM_VK_F4},
818  {"F5", KeyEventBaseImpl::DOM_VK_F5},
819  {"F6", KeyEventBaseImpl::DOM_VK_F6},
820  {"F7", KeyEventBaseImpl::DOM_VK_F7},
821  {"F8", KeyEventBaseImpl::DOM_VK_F8},
822  {"F9", KeyEventBaseImpl::DOM_VK_F9},
823  {"F10", KeyEventBaseImpl::DOM_VK_F10},
824  {"F11", KeyEventBaseImpl::DOM_VK_F11},
825  {"F12", KeyEventBaseImpl::DOM_VK_F12},
826  {"F13", KeyEventBaseImpl::DOM_VK_F13},
827  {"F14", KeyEventBaseImpl::DOM_VK_F14},
828  {"F15", KeyEventBaseImpl::DOM_VK_F15},
829  {"F16", KeyEventBaseImpl::DOM_VK_F16},
830  {"F17", KeyEventBaseImpl::DOM_VK_F17},
831  {"F18", KeyEventBaseImpl::DOM_VK_F18},
832  {"F19", KeyEventBaseImpl::DOM_VK_F19},
833  {"F20", KeyEventBaseImpl::DOM_VK_F20},
834  {"F21", KeyEventBaseImpl::DOM_VK_F21},
835  {"F22", KeyEventBaseImpl::DOM_VK_F22},
836  {"F23", KeyEventBaseImpl::DOM_VK_F23},
837  {"F24", KeyEventBaseImpl::DOM_VK_F24},
838  {nullptr, 0}
839 };
840 
841 MAKE_TRANSLATOR(keyIdentifiersToVirtKeys, QByteArray, unsigned, const char *, keyIdentifiersToVirtKeysTable)
842 
843 /** These are the modifiers we currently support */
844 static const IDTranslator<QByteArray, unsigned, const char *>::Info keyModifiersToCodeTable[] = {
845  {"Alt", Qt::AltModifier},
846  {"Control", Qt::ControlModifier},
847  {"Shift", Qt::ShiftModifier},
848  {"Meta", Qt::MetaModifier},
849  {nullptr, 0}
850 };
851 
852 MAKE_TRANSLATOR(keyModifiersToCode, QByteArray, unsigned, const char *, keyModifiersToCodeTable)
853 
854 KeyboardEventImpl::KeyboardEventImpl() : m_keyLocation(KeyboardEvent::DOM_KEY_LOCATION_STANDARD)
855 {}
856 
857 DOMString KeyboardEventImpl::keyIdentifier() const
858 {
859  if (unsigned special = virtKeyVal())
860  if (const char *id = keyIdentifiersToVirtKeys()->toLeft(special)) {
861  return QString::fromLatin1(id);
862  }
863 
864  if (unsigned unicode = keyVal()) {
865  return QString(QChar(unicode));
866  }
867 
868  return "Unidentified";
869 }
870 
871 bool KeyboardEventImpl::getModifierState(const DOMString &keyIdentifierArg) const
872 {
873  unsigned mask = keyModifiersToCode()->toRight(keyIdentifierArg.string().toLatin1());
874  return m_modifier & mask;
875 }
876 
877 bool KeyboardEventImpl::isKeyboardEvent() const
878 {
879  return true;
880 }
881 
882 void KeyboardEventImpl::initKeyboardEvent(const DOMString &typeArg,
883  bool canBubbleArg,
884  bool cancelableArg,
885  AbstractViewImpl *viewArg,
886  const DOMString &keyIdentifierArg,
887  unsigned long keyLocationArg,
888  const DOMString &modifiersList)
889 {
890  unsigned keyVal = 0;
891  unsigned virtKeyVal = 0;
892 
893  m_keyLocation = keyLocationArg;
894 
895  //Figure out the code information from the key identifier.
896  if (keyIdentifierArg.length() == 1) {
897  //Likely to be normal unicode id, unless it's one of the few
898  //special values.
899  unsigned short code = keyIdentifierArg.unicode()[0].unicode();
900  if (code > 0x20 && code != 0x7F) {
901  keyVal = code;
902  }
903  }
904 
905  if (!keyVal) { //One of special keys, likely.
906  virtKeyVal = keyIdentifiersToVirtKeys()->toRight(keyIdentifierArg.string().toLatin1());
907  }
908 
909  //Process modifier list.
910  const QStringList mods = modifiersList.string().trimmed().simplified().split(' ');
911 
912  unsigned modifiers = 0;
913  for (QStringList::ConstIterator i = mods.begin(); i != mods.end(); ++i)
914  if (unsigned mask = keyModifiersToCode()->toRight((*i).toLatin1())) {
915  modifiers |= mask;
916  }
917 
918  initKeyBaseEvent(typeArg, canBubbleArg, cancelableArg, viewArg,
919  keyVal, virtKeyVal, modifiers);
920 }
921 
922 KeyboardEventImpl::KeyboardEventImpl(QKeyEvent *key, DOM::AbstractViewImpl *view) :
923  KeyEventBaseImpl(key->type() == QEvent::KeyRelease ? KEYUP_EVENT : KEYDOWN_EVENT, true, true, view, key)
924 {
925  if (key->modifiers() & Qt::KeypadModifier) {
927  } else {
928  //It's generally standard, but for the modifiers,
929  //it should be left/right, so guess left.
931  switch (m_virtKeyVal) {
932  case DOM_VK_LEFT_ALT:
933  case DOM_VK_LEFT_SHIFT:
934  case DOM_VK_LEFT_CONTROL:
935  case DOM_VK_META:
936  m_keyLocation = KeyboardEvent::DOM_KEY_LOCATION_LEFT;
937  }
938  }
939 }
940 
941 int KeyboardEventImpl::keyCode() const
942 {
943  //Keycode on key events always identifies the -key- and not the input,
944  //so e.g. 'a' will get 'A'
945  if (m_virtKeyVal != DOM_VK_UNDEFINED) {
946  return m_virtKeyVal;
947  } else {
948  unsigned char code = QChar((unsigned short)m_keyVal).toUpper().unicode();
949  // Some codes we get from Qt are things like ( which conflict with
950  // browser scancodes. Remap them to what's on their keycaps in a US
951  // layout.
952  if (virtKeyToQtKey()->hasLeft(code)) {
953  switch (code) {
954  case '!': return '1';
955  case '@': return '2';
956  case '#': return '3';
957  case '$': return '4';
958  case '%': return '5';
959  case '^': return '6';
960  case '&': return '7';
961  case '*': return '8';
962  case '(': return '9';
963  case ')': return '0';
964  default:
965  qCWarning(KHTML_LOG) << "Don't know how resolve conflict of code:" << code
966  << " with a virtKey";
967  }
968  }
969  return code;
970  }
971 }
972 
973 int KeyboardEventImpl::charCode() const
974 {
975  //IE doesn't support charCode at all, and mozilla returns 0
976  //on key events. So return 0 here
977  return 0;
978 }
979 
980 // -----------------------------------------------------------------------------
981 TextEventImpl::TextEventImpl()
982 {}
983 
984 bool TextEventImpl::isTextInputEvent() const
985 {
986  return true;
987 }
988 
989 TextEventImpl::TextEventImpl(QKeyEvent *key, DOM::AbstractViewImpl *view) :
990  KeyEventBaseImpl(KEYPRESS_EVENT, true, true, view, key)
991 {
992  m_outputString = key->text();
993 }
994 
995 void TextEventImpl::initTextEvent(const DOMString &typeArg,
996  bool canBubbleArg,
997  bool cancelableArg,
998  AbstractViewImpl *viewArg,
999  const DOMString &text)
1000 {
1001  m_outputString = text;
1002 
1003  //See whether we can get a key out of this.
1004  unsigned keyCode = 0;
1005  if (text.length() == 1) {
1006  keyCode = text.unicode()[0].unicode();
1007  }
1008  initKeyBaseEvent(typeArg, canBubbleArg, cancelableArg, viewArg,
1009  keyCode, 0, 0);
1010 }
1011 
1012 int TextEventImpl::keyCode() const
1013 {
1014  //Mozilla returns 0 here unless this is a non-unicode key.
1015  //IE stuffs everything here, and so we try to match it..
1016  if (m_keyVal) {
1017  return m_keyVal;
1018  }
1019  return m_virtKeyVal;
1020 }
1021 
1022 int TextEventImpl::charCode() const
1023 {
1024  //On text events, in Mozilla charCode is 0 for non-unicode keys,
1025  //and the unicode key otherwise... IE doesn't support this.
1026  if (m_virtKeyVal) {
1027  return 0;
1028  }
1029  return m_keyVal;
1030 }
1031 
1032 // -----------------------------------------------------------------------------
1033 MutationEventImpl::MutationEventImpl()
1034 {
1035  m_relatedNode = nullptr;
1036  m_prevValue = nullptr;
1037  m_newValue = nullptr;
1038  m_attrName = nullptr;
1039  m_attrChange = 0;
1040 }
1041 
1042 MutationEventImpl::MutationEventImpl(EventId _id,
1043  bool canBubbleArg,
1044  bool cancelableArg,
1045  const Node &relatedNodeArg,
1046  const DOMString &prevValueArg,
1047  const DOMString &newValueArg,
1048  const DOMString &attrNameArg,
1049  unsigned short attrChangeArg)
1050  : EventImpl(_id, canBubbleArg, cancelableArg)
1051 {
1052  m_relatedNode = relatedNodeArg.handle();
1053  if (m_relatedNode) {
1054  m_relatedNode->ref();
1055  }
1056  m_prevValue = prevValueArg.implementation();
1057  if (m_prevValue) {
1058  m_prevValue->ref();
1059  }
1060  m_newValue = newValueArg.implementation();
1061  if (m_newValue) {
1062  m_newValue->ref();
1063  }
1064  m_attrName = attrNameArg.implementation();
1065  if (m_attrName) {
1066  m_attrName->ref();
1067  }
1068  m_attrChange = attrChangeArg;
1069 }
1070 
1071 MutationEventImpl::~MutationEventImpl()
1072 {
1073  if (m_relatedNode) {
1074  m_relatedNode->deref();
1075  }
1076  if (m_prevValue) {
1077  m_prevValue->deref();
1078  }
1079  if (m_newValue) {
1080  m_newValue->deref();
1081  }
1082  if (m_attrName) {
1083  m_attrName->deref();
1084  }
1085 }
1086 
1087 void MutationEventImpl::initMutationEvent(const DOMString &typeArg,
1088  bool canBubbleArg,
1089  bool cancelableArg,
1090  const Node &relatedNodeArg,
1091  const DOMString &prevValueArg,
1092  const DOMString &newValueArg,
1093  const DOMString &attrNameArg,
1094  unsigned short attrChangeArg)
1095 {
1096  EventImpl::initEvent(typeArg, canBubbleArg, cancelableArg);
1097 
1098  if (m_relatedNode) {
1099  m_relatedNode->deref();
1100  }
1101  if (m_prevValue) {
1102  m_prevValue->deref();
1103  }
1104  if (m_newValue) {
1105  m_newValue->deref();
1106  }
1107  if (m_attrName) {
1108  m_attrName->deref();
1109  }
1110 
1111  m_relatedNode = relatedNodeArg.handle();
1112  if (m_relatedNode) {
1113  m_relatedNode->ref();
1114  }
1115  m_prevValue = prevValueArg.implementation();
1116  if (m_prevValue) {
1117  m_prevValue->ref();
1118  }
1119  m_newValue = newValueArg.implementation();
1120  if (m_newValue) {
1121  m_newValue->ref();
1122  }
1123  m_attrName = attrNameArg.implementation();
1124  if (m_newValue) {
1125  m_newValue->ref();
1126  }
1127  m_attrChange = attrChangeArg;
1128 }
1129 
1130 bool MutationEventImpl::isMutationEvent() const
1131 {
1132  return true;
1133 }
1134 
1135 // -----------------------------------------------------------------------------
1136 
1137 MessageEventImpl::MessageEventImpl()
1138 {}
1139 
1140 bool MessageEventImpl::isMessageEvent() const
1141 {
1142  return true;
1143 }
1144 
1145 void MessageEventImpl::initMessageEvent(const DOMString &typeArg,
1146  bool canBubbleArg,
1147  bool cancelableArg,
1148  const RefPtr<Data> &dataArg,
1149  const DOMString &originArg,
1150  const DOMString &lastEventIdArg,
1151  KHTMLPart *sourceArg)
1152 {
1153  EventImpl::initEvent(typeArg, canBubbleArg, cancelableArg);
1154  m_data = dataArg;
1155  m_origin = originArg;
1156  m_lastEventId = lastEventIdArg;
1157  m_source = sourceArg;
1158 }
1159 
1160 // -----------------------------------------------------------------------------
1161 
1162 HashChangeEventImpl::HashChangeEventImpl()
1163 {
1164 }
1165 
1166 bool HashChangeEventImpl::isHashChangeEvent() const
1167 {
1168  return true;
1169 }
1170 
1171 void HashChangeEventImpl::initHashChangeEvent(const DOMString &eventTypeArg, bool canBubbleArg, bool cancelableArg, const DOMString &oldUrl, const DOMString &newUrl)
1172 {
1173  EventImpl::initEvent(eventTypeArg, canBubbleArg, cancelableArg);
1174  m_oldUrl = oldUrl;
1175  m_newUrl = newUrl;
1176 }
ControlModifier
Qt::KeyboardModifiers modifiers() const const
DOMString type() const
The name of the event (case-insensitive).
Definition: dom2_events.cpp:91
The Node interface is the primary datatype for the entire Document Object Model.
Definition: dom_node.h:278
int count() const const
This file is part of the HTML rendering engine for KDE.
int contentsY() const
Returns the y coordinate of the contents area point that is currently located at the top left in the ...
Definition: khtmlview.cpp:714
const T & at(int i) const const
QString simplified() const const
This class is khtml&#39;s main class.
Definition: khtml_part.h:208
Renders and displays HTML in a QScrollArea.
Definition: khtmlview.h:97
QList::iterator erase(QList::iterator pos)
int size() const const
void append(const T &value)
Introduced in DOM Level 3.
Definition: dom2_events.h:627
This file is part of the KHTML renderer for KDE.
Definition: translator.h:31
QString trimmed() const const
QString text() const const
QStringList split(const QString &sep, QString::SplitBehavior behavior, Qt::CaseSensitivity cs) const const
This class implements the basic string we use in the DOM.
Definition: dom_string.h:44
virtual DOMString eventListenerType()
Definition: dom2_events.cpp:42
The key activation originated on the numeric keypad or with a virtual key corresponding to the numeri...
Definition: dom2_events.h:670
The key activated is in the left key location (there is more than one possible location for this key)...
Definition: dom2_events.h:654
ushort unicode() const const
QList::iterator end()
bool contains(const T &value) const const
Introduced in DOM Level 2.
Definition: dom2_events.h:69
This library provides a full-featured HTML parser and widget.
The key activation is not distinguished as the left or right version of the key, and did not originat...
Definition: dom2_events.h:645
QDateTime currentDateTime()
QByteArray toLatin1() const const
Introduced in DOM Level 2.
Definition: dom2_events.h:116
QChar toUpper() const const
int contentsX() const
Returns the x coordinate of the contents area point that is currently located at the top left in the ...
Definition: khtmlview.cpp:709
typedef ConstIterator
DOMStringImpl * implementation() const
Definition: dom_string.h:145
QString fromLatin1(const char *str, int size)
unsigned long long DOMTimeStamp
NodeImpl * handle() const
Definition: dom_node.h:936
QObject * parent() const const
QList::iterator begin()
Key_Backspace
void replace(int i, const T &value)
This file is part of the KDE documentation.
Documentation copyright © 1996-2021 The KDE developers.
Generated on Tue Oct 26 2021 22:48:00 by doxygen 1.8.11 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.