WebNetscapePluginEventHandlerCarbon.mm 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430
  1. /*
  2. * Copyright (C) 2008 Apple Inc. All Rights Reserved.
  3. *
  4. * Redistribution and use in source and binary forms, with or without
  5. * modification, are permitted provided that the following conditions
  6. * are met:
  7. * 1. Redistributions of source code must retain the above copyright
  8. * notice, this list of conditions and the following disclaimer.
  9. * 2. Redistributions in binary form must reproduce the above copyright
  10. * notice, this list of conditions and the following disclaimer in the
  11. * documentation and/or other materials provided with the distribution.
  12. *
  13. * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
  14. * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  15. * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
  16. * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
  17. * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
  18. * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
  19. * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
  20. * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
  21. * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  22. * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  23. * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  24. */
  25. #if ENABLE(NETSCAPE_PLUGIN_API) && !defined(__LP64__)
  26. #import "WebNetscapePluginEventHandlerCarbon.h"
  27. #import "WebNetscapePluginView.h"
  28. #import "WebKitLogging.h"
  29. #import "WebKitSystemInterface.h"
  30. // Send null events 50 times a second when active, so plug-ins like Flash get high frame rates.
  31. #define NullEventIntervalActive 0.02
  32. #define NullEventIntervalNotActive 0.25
  33. WebNetscapePluginEventHandlerCarbon::WebNetscapePluginEventHandlerCarbon(WebNetscapePluginView* pluginView)
  34. : WebNetscapePluginEventHandler(pluginView)
  35. , m_keyEventHandler(0)
  36. , m_suspendKeyUpEvents(false)
  37. {
  38. }
  39. static void getCarbonEvent(EventRecord* carbonEvent)
  40. {
  41. carbonEvent->what = nullEvent;
  42. carbonEvent->message = 0;
  43. carbonEvent->when = TickCount();
  44. GetGlobalMouse(&carbonEvent->where);
  45. carbonEvent->modifiers = GetCurrentKeyModifiers();
  46. if (!Button())
  47. carbonEvent->modifiers |= btnState;
  48. }
  49. static EventModifiers modifiersForEvent(NSEvent *event)
  50. {
  51. EventModifiers modifiers;
  52. unsigned int modifierFlags = [event modifierFlags];
  53. NSEventType eventType = [event type];
  54. modifiers = 0;
  55. if (eventType != NSLeftMouseDown && eventType != NSRightMouseDown)
  56. modifiers |= btnState;
  57. if (modifierFlags & NSCommandKeyMask)
  58. modifiers |= cmdKey;
  59. if (modifierFlags & NSShiftKeyMask)
  60. modifiers |= shiftKey;
  61. if (modifierFlags & NSAlphaShiftKeyMask)
  62. modifiers |= alphaLock;
  63. if (modifierFlags & NSAlternateKeyMask)
  64. modifiers |= optionKey;
  65. if (modifierFlags & NSControlKeyMask || eventType == NSRightMouseDown)
  66. modifiers |= controlKey;
  67. return modifiers;
  68. }
  69. static void getCarbonEvent(EventRecord *carbonEvent, NSEvent *cocoaEvent)
  70. {
  71. if (WKConvertNSEventToCarbonEvent(carbonEvent, cocoaEvent))
  72. return;
  73. NSPoint where = [[cocoaEvent window] convertBaseToScreen:[cocoaEvent locationInWindow]];
  74. carbonEvent->what = nullEvent;
  75. carbonEvent->message = 0;
  76. carbonEvent->when = (UInt32)([cocoaEvent timestamp] * 60); // seconds to ticks
  77. carbonEvent->where.h = (short)where.x;
  78. carbonEvent->where.v = (short)(NSMaxY([(NSScreen *)[[NSScreen screens] objectAtIndex:0] frame]) - where.y);
  79. carbonEvent->modifiers = modifiersForEvent(cocoaEvent);
  80. }
  81. void WebNetscapePluginEventHandlerCarbon::sendNullEvent()
  82. {
  83. EventRecord event;
  84. getCarbonEvent(&event);
  85. // Plug-in should not react to cursor position when not active or when a menu is down.
  86. MenuTrackingData trackingData;
  87. OSStatus error = GetMenuTrackingData(NULL, &trackingData);
  88. // Plug-in should not react to cursor position when the actual window is not key.
  89. if (![[m_pluginView window] isKeyWindow] || (error == noErr && trackingData.menu)) {
  90. // FIXME: Does passing a v and h of -1 really prevent it from reacting to the cursor position?
  91. event.where.v = -1;
  92. event.where.h = -1;
  93. }
  94. sendEvent(&event);
  95. }
  96. void WebNetscapePluginEventHandlerCarbon::drawRect(CGContextRef, const NSRect&)
  97. {
  98. EventRecord event;
  99. getCarbonEvent(&event);
  100. event.what = updateEvt;
  101. WindowRef windowRef = (WindowRef)[[m_pluginView window] windowRef];
  102. event.message = (unsigned long)windowRef;
  103. BOOL acceptedEvent;
  104. acceptedEvent = sendEvent(&event);
  105. LOG(PluginEvents, "NPP_HandleEvent(updateEvt): %d", acceptedEvent);
  106. }
  107. void WebNetscapePluginEventHandlerCarbon::mouseDown(NSEvent* theEvent)
  108. {
  109. EventRecord event;
  110. getCarbonEvent(&event, theEvent);
  111. event.what = ::mouseDown;
  112. BOOL acceptedEvent;
  113. acceptedEvent = sendEvent(&event);
  114. LOG(PluginEvents, "NPP_HandleEvent(mouseDown): %d pt.v=%d, pt.h=%d", acceptedEvent, event.where.v, event.where.h);
  115. }
  116. void WebNetscapePluginEventHandlerCarbon::mouseUp(NSEvent* theEvent)
  117. {
  118. EventRecord event;
  119. getCarbonEvent(&event, theEvent);
  120. event.what = ::mouseUp;
  121. BOOL acceptedEvent;
  122. acceptedEvent = sendEvent(&event);
  123. LOG(PluginEvents, "NPP_HandleEvent(mouseUp): %d pt.v=%d, pt.h=%d", acceptedEvent, event.where.v, event.where.h);
  124. }
  125. bool WebNetscapePluginEventHandlerCarbon::scrollWheel(NSEvent* theEvent)
  126. {
  127. return false;
  128. }
  129. void WebNetscapePluginEventHandlerCarbon::mouseEntered(NSEvent* theEvent)
  130. {
  131. EventRecord event;
  132. getCarbonEvent(&event, theEvent);
  133. event.what = NPEventType_AdjustCursorEvent;
  134. BOOL acceptedEvent;
  135. acceptedEvent = sendEvent(&event);
  136. LOG(PluginEvents, "NPP_HandleEvent(mouseEntered): %d", acceptedEvent);
  137. }
  138. void WebNetscapePluginEventHandlerCarbon::mouseExited(NSEvent* theEvent)
  139. {
  140. EventRecord event;
  141. getCarbonEvent(&event, theEvent);
  142. event.what = NPEventType_AdjustCursorEvent;
  143. BOOL acceptedEvent;
  144. acceptedEvent = sendEvent(&event);
  145. LOG(PluginEvents, "NPP_HandleEvent(mouseExited): %d", acceptedEvent);
  146. }
  147. void WebNetscapePluginEventHandlerCarbon::mouseDragged(NSEvent*)
  148. {
  149. }
  150. void WebNetscapePluginEventHandlerCarbon::mouseMoved(NSEvent* theEvent)
  151. {
  152. EventRecord event;
  153. getCarbonEvent(&event, theEvent);
  154. event.what = NPEventType_AdjustCursorEvent;
  155. BOOL acceptedEvent;
  156. acceptedEvent = sendEvent(&event);
  157. LOG(PluginEvents, "NPP_HandleEvent(mouseMoved): %d", acceptedEvent);
  158. }
  159. void WebNetscapePluginEventHandlerCarbon::keyDown(NSEvent *theEvent)
  160. {
  161. m_suspendKeyUpEvents = true;
  162. WKSendKeyEventToTSM(theEvent);
  163. }
  164. void WebNetscapePluginEventHandlerCarbon::syntheticKeyDownWithCommandModifier(int keyCode, char character)
  165. {
  166. EventRecord event;
  167. getCarbonEvent(&event);
  168. event.what = ::keyDown;
  169. event.modifiers |= cmdKey;
  170. event.message = keyCode << 8 | character;
  171. sendEvent(&event);
  172. }
  173. static UInt32 keyMessageForEvent(NSEvent *event)
  174. {
  175. NSData *data = [[event characters] dataUsingEncoding:CFStringConvertEncodingToNSStringEncoding(CFStringGetSystemEncoding())];
  176. if (!data)
  177. return 0;
  178. UInt8 characterCode;
  179. [data getBytes:&characterCode length:1];
  180. UInt16 keyCode = [event keyCode];
  181. return keyCode << 8 | characterCode;
  182. }
  183. void WebNetscapePluginEventHandlerCarbon::keyUp(NSEvent* theEvent)
  184. {
  185. WKSendKeyEventToTSM(theEvent);
  186. // TSM won't send keyUp events so we have to send them ourselves.
  187. // Only send keyUp events after we receive the TSM callback because this is what plug-in expect from OS 9.
  188. if (!m_suspendKeyUpEvents) {
  189. EventRecord event;
  190. getCarbonEvent(&event, theEvent);
  191. event.what = ::keyUp;
  192. if (event.message == 0)
  193. event.message = keyMessageForEvent(theEvent);
  194. sendEvent(&event);
  195. }
  196. }
  197. void WebNetscapePluginEventHandlerCarbon::flagsChanged(NSEvent*)
  198. {
  199. }
  200. void WebNetscapePluginEventHandlerCarbon::focusChanged(bool hasFocus)
  201. {
  202. EventRecord event;
  203. getCarbonEvent(&event);
  204. bool acceptedEvent;
  205. if (hasFocus) {
  206. event.what = NPEventType_GetFocusEvent;
  207. acceptedEvent = sendEvent(&event);
  208. LOG(PluginEvents, "NPP_HandleEvent(NPEventType_GetFocusEvent): %d", acceptedEvent);
  209. installKeyEventHandler();
  210. } else {
  211. event.what = NPEventType_LoseFocusEvent;
  212. acceptedEvent = sendEvent(&event);
  213. LOG(PluginEvents, "NPP_HandleEvent(NPEventType_LoseFocusEvent): %d", acceptedEvent);
  214. removeKeyEventHandler();
  215. }
  216. }
  217. void WebNetscapePluginEventHandlerCarbon::windowFocusChanged(bool hasFocus)
  218. {
  219. WindowRef windowRef = (WindowRef)[[m_pluginView window] windowRef];
  220. SetUserFocusWindow(windowRef);
  221. EventRecord event;
  222. getCarbonEvent(&event);
  223. event.what = activateEvt;
  224. event.message = (unsigned long)windowRef;
  225. if (hasFocus)
  226. event.modifiers |= activeFlag;
  227. BOOL acceptedEvent;
  228. acceptedEvent = sendEvent(&event);
  229. LOG(PluginEvents, "NPP_HandleEvent(activateEvent): %d isActive: %d", acceptedEvent, hasFocus);
  230. }
  231. OSStatus WebNetscapePluginEventHandlerCarbon::TSMEventHandler(EventHandlerCallRef inHandlerRef, EventRef inEvent, void *eventHandler)
  232. {
  233. EventRef rawKeyEventRef;
  234. OSStatus status = GetEventParameter(inEvent, kEventParamTextInputSendKeyboardEvent, typeEventRef, NULL, sizeof(EventRef), NULL, &rawKeyEventRef);
  235. if (status != noErr) {
  236. LOG_ERROR("GetEventParameter failed with error: %d", status);
  237. return noErr;
  238. }
  239. // Two-pass read to allocate/extract Mac charCodes
  240. ByteCount numBytes;
  241. status = GetEventParameter(rawKeyEventRef, kEventParamKeyMacCharCodes, typeChar, NULL, 0, &numBytes, NULL);
  242. if (status != noErr) {
  243. LOG_ERROR("GetEventParameter failed with error: %d", status);
  244. return noErr;
  245. }
  246. char *buffer = (char *)malloc(numBytes);
  247. status = GetEventParameter(rawKeyEventRef, kEventParamKeyMacCharCodes, typeChar, NULL, numBytes, NULL, buffer);
  248. if (status != noErr) {
  249. LOG_ERROR("GetEventParameter failed with error: %d", status);
  250. free(buffer);
  251. return noErr;
  252. }
  253. EventRef cloneEvent = CopyEvent(rawKeyEventRef);
  254. unsigned i;
  255. for (i = 0; i < numBytes; i++) {
  256. status = SetEventParameter(cloneEvent, kEventParamKeyMacCharCodes, typeChar, 1 /* one char code */, &buffer[i]);
  257. if (status != noErr) {
  258. LOG_ERROR("SetEventParameter failed with error: %d", status);
  259. free(buffer);
  260. return noErr;
  261. }
  262. EventRecord eventRec;
  263. if (ConvertEventRefToEventRecord(cloneEvent, &eventRec)) {
  264. BOOL acceptedEvent;
  265. acceptedEvent = static_cast<WebNetscapePluginEventHandlerCarbon*>(eventHandler)->sendEvent(&eventRec);
  266. LOG(PluginEvents, "NPP_HandleEvent(keyDown): %d charCode:%c keyCode:%lu",
  267. acceptedEvent, (char) (eventRec.message & charCodeMask), (eventRec.message & keyCodeMask));
  268. // We originally thought that if the plug-in didn't accept this event,
  269. // we should pass it along so that keyboard scrolling, for example, will work.
  270. // In practice, this is not a good idea, because plug-ins tend to eat the event but return false.
  271. // MacIE handles each key event twice because of this, but we will emulate the other browsers instead.
  272. }
  273. }
  274. ReleaseEvent(cloneEvent);
  275. free(buffer);
  276. return noErr;
  277. }
  278. void WebNetscapePluginEventHandlerCarbon::installKeyEventHandler()
  279. {
  280. static const EventTypeSpec sTSMEvents[] =
  281. {
  282. { kEventClassTextInput, kEventTextInputUnicodeForKeyEvent }
  283. };
  284. if (!m_keyEventHandler) {
  285. InstallEventHandler(GetWindowEventTarget((WindowRef)[[m_pluginView window] windowRef]),
  286. NewEventHandlerUPP(TSMEventHandler),
  287. GetEventTypeCount(sTSMEvents),
  288. sTSMEvents,
  289. this,
  290. &m_keyEventHandler);
  291. }
  292. }
  293. void WebNetscapePluginEventHandlerCarbon::removeKeyEventHandler()
  294. {
  295. if (m_keyEventHandler) {
  296. RemoveEventHandler(m_keyEventHandler);
  297. m_keyEventHandler = 0;
  298. }
  299. }
  300. void WebNetscapePluginEventHandlerCarbon::nullEventTimerFired(CFRunLoopTimerRef timerRef, void *context)
  301. {
  302. static_cast<WebNetscapePluginEventHandlerCarbon*>(context)->sendNullEvent();
  303. }
  304. void WebNetscapePluginEventHandlerCarbon::startTimers(bool throttleTimers)
  305. {
  306. ASSERT(!m_nullEventTimer);
  307. CFTimeInterval interval = !throttleTimers ? NullEventIntervalActive : NullEventIntervalNotActive;
  308. CFRunLoopTimerContext context = { 0, this, NULL, NULL, NULL };
  309. m_nullEventTimer = adoptCF(CFRunLoopTimerCreate(0, CFAbsoluteTimeGetCurrent() + interval, interval,
  310. 0, 0, nullEventTimerFired, &context));
  311. CFRunLoopAddTimer(CFRunLoopGetCurrent(), m_nullEventTimer.get(), kCFRunLoopDefaultMode);
  312. }
  313. void WebNetscapePluginEventHandlerCarbon::stopTimers()
  314. {
  315. if (!m_nullEventTimer)
  316. return;
  317. CFRunLoopTimerInvalidate(m_nullEventTimer.get());
  318. m_nullEventTimer = 0;
  319. }
  320. void* WebNetscapePluginEventHandlerCarbon::platformWindow(NSWindow* window)
  321. {
  322. return [window windowRef];
  323. }
  324. bool WebNetscapePluginEventHandlerCarbon::sendEvent(EventRecord* event)
  325. {
  326. // If at any point the user clicks or presses a key from within a plugin, set the
  327. // currentEventIsUserGesture flag to true. This is important to differentiate legitimate
  328. // window.open() calls; we still want to allow those. See rdar://problem/4010765
  329. if (event->what == ::mouseDown || event->what == ::keyDown || event->what == ::mouseUp || event->what == ::autoKey)
  330. m_currentEventIsUserGesture = true;
  331. m_suspendKeyUpEvents = false;
  332. bool result = [m_pluginView sendEvent:event isDrawRect:event->what == updateEvt];
  333. m_currentEventIsUserGesture = false;
  334. return result;
  335. }
  336. #endif // ENABLE(NETSCAPE_PLUGIN_API) && !defined(__LP64__)