FireBreath  1.4.0
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Pages
PluginEventMacCarbon.mm
1 /**********************************************************\
2  Original Author: Eric Herrmann
3 
4  Created: 2011
5  License: Dual license model; choose one of two:
6  New BSD License
7  http://www.opensource.org/licenses/bsd-license.php
8  - or -
9  GNU Lesser General Public License, version 2.1
10  http://www.gnu.org/licenses/lgpl-2.1.html
11 
12  Copyright 2010 Eric Herrmann, Firebreath development team
13 \**********************************************************/
14 
15 #include <boost/type_traits.hpp>
16 #import <AppKit/AppKit.h>
17 
18 #include "ConstructDefaultPluginWindows.h"
19 #include "KeyCodesCarbon.h"
20 #include "PluginEvents/MacEventCarbon.h"
21 #include "PluginEvents/GeneralEvents.h"
22 #include "PluginEvents/DrawingEvents.h"
23 #include "PluginEvents/MouseEvents.h"
24 #include "PluginEvents/KeyboardEvents.h"
25 
26 #include "PluginWindowMac.h"
27 #include "PluginEventMacCarbon.h"
28 
29 using namespace FB;
30 
31 #ifndef NP_NO_CARBON
32 
33 static uint32_t modifiersForEvent(const EventRecord *event)
34 {
35  uint32_t rval = 0;
36  if (event->modifiers & cmdKey)
37  rval |= NSCommandKeyMask;
38  if (event->modifiers & shiftKey)
39  rval |= NSShiftKeyMask;
40  if (event->modifiers & alphaLock)
41  rval |= NSAlphaShiftKeyMask;
42  if (event->modifiers & optionKey)
43  rval |= NSAlternateKeyMask;
44  if (event->modifiers & controlKey)
45  rval |= NSControlKeyMask;
46  return rval;
47 }
48 
49 /*
50 typedef enum {
51 √ NPCocoaEventDrawRect = 1, // updateEvt
52 √ NPCocoaEventMouseDown, // mouseDown
53 √ NPCocoaEventMouseUp, // mouseUp
54 √ NPCocoaEventMouseMoved, // NPEventType_AdjustCursorEvent
55 √ NPCocoaEventMouseEntered, // NPEventType_AdjustCursorEvent
56 √ NPCocoaEventMouseExited, // NPEventType_AdjustCursorEvent
57 √ NPCocoaEventMouseDragged, // NPEventType_AdjustCursorEvent
58  NPCocoaEventKeyDown, // NPCocoaEventKeyDown
59  NPCocoaEventKeyUp, // NPCocoaEventKeyUp
60 √ NPCocoaEventFlagsChanged, // nullEvent
61 √ NPCocoaEventFocusChanged, // NPEventType_GetFocusEvent/NPEventType_LoseFocusEvent
62 √ NPCocoaEventWindowFocusChanged, // activateEvt
63  NPCocoaEventScrollWheel, // Not Supported
64  NPCocoaEventTextInput // Not Supported
65 } NPCocoaEventType;
66 
67 enum NPEventType {
68 √ nullEvent = 0, // NPCocoaEventFlagsChanged
69 √ mouseDown = 1, // NPCocoaEventMouseDown
70 √ mouseUp = 2, // NPCocoaEventMouseUp
71  keyDown = 3, // NPCocoaEventKeyDown
72  keyUp = 4, // NPCocoaEventKeyUp
73 √ autoKey = 5, // NPCocoaEventKeyUp
74 √ updateEvt = 6, // NPCocoaEventDrawRect
75  diskEvt = 7, // Not Supported
76 √ activateEvt = 8, // NPCocoaEventWindowFocusChanged
77  osEvt = 15, // Not Supported
78  kHighLevelEvent = 23 // Not Supported
79 √ NPEventType_GetFocusEvent = (osEvt + 16),// NPCocoaEventFocusChanged
80 √ NPEventType_LoseFocusEvent, // NPCocoaEventFocusChanged
81 √ NPEventType_AdjustCursorEvent, // NPCocoaEventMouseEntered/NPCocoaEventMouseExited, and NPCocoaEventMouseMoved/NPCocoaEventMouseDragged
82  NPEventType_MenuCommandEvent, // No Implementation in Mozilla or WebKit
83  NPEventType_ClippingChangedEvent, // No Implementation in Mozilla or WebKit
84  NPEventType_ScrollingBeginsEvent = 1000, // No Implementation in Mozilla or WebKit
85  NPEventType_ScrollingEndsEvent // No Implementation in Mozilla or WebKit
86 };
87 */
88 
89 void PluginEventMacCarbon::CarbonToNPCocoaEvent(const EventRecord* evt, NPCocoaEvent& rval)
90 {
91  memset(&rval, 0, sizeof(NPCocoaEvent));
92  switch (evt->what) {
93  case nullEvent:
94  {
95  rval.type = NPCocoaEventFlagsChanged;
96  rval.data.key.modifierFlags = modifiersForEvent(evt);
97  rval.data.key.characters = NULL;
98  rval.data.key.charactersIgnoringModifiers = NULL;
99  rval.data.key.isARepeat = false;
100  rval.data.key.keyCode = 0;
101  } break;
102  case mouseDown:
103  {
104  Point local = GlobalToLocal(evt->where);
105  rval.type = NPCocoaEventMouseDown;
106  rval.data.mouse.modifierFlags = modifiersForEvent(evt);
107  rval.data.mouse.pluginX = local.h;
108  rval.data.mouse.pluginY = local.v;
109  rval.data.mouse.buttonNumber = (evt->modifiers & controlKey) ? kCGMouseButtonRight : kCGMouseButtonLeft;
110  rval.data.mouse.clickCount = 1;
111  rval.data.mouse.deltaX = 0;
112  rval.data.mouse.deltaY = 0;
113  rval.data.mouse.deltaZ = 0;
114  } break;
115  case mouseUp:
116  {
117  Point local = GlobalToLocal(evt->where);
118  rval.type = NPCocoaEventMouseUp;
119  rval.data.mouse.modifierFlags = modifiersForEvent(evt);
120  rval.data.mouse.pluginX = local.h;
121  rval.data.mouse.pluginY = local.v;
122  rval.data.mouse.buttonNumber = (evt->modifiers & controlKey) ? kCGMouseButtonRight : kCGMouseButtonLeft;
123  rval.data.mouse.clickCount = 1;
124  rval.data.mouse.deltaX = 0;
125  rval.data.mouse.deltaY = 0;
126  rval.data.mouse.deltaZ = 0;
127  } break;
128  case keyDown:
129  {
130  NPNSString* characters = TranslateKeyEventRecord(evt);
131  if (characters) {
132  rval.type = NPCocoaEventKeyDown;
133  rval.data.key.modifierFlags = modifiersForEvent(evt);
134  rval.data.key.characters = characters;
135  rval.data.key.charactersIgnoringModifiers = rval.data.key.characters;
136  rval.data.key.isARepeat = false;
137  rval.data.key.keyCode = (evt->message & keyCodeMask) >> 8;
138  }
139  } break;
140  case keyUp:
141  case autoKey:
142  {
143  NPNSString* characters = TranslateKeyEventRecord(evt);
144  if (characters) {
145  rval.type = NPCocoaEventKeyUp;
146  rval.data.key.modifierFlags = modifiersForEvent(evt);
147  rval.data.key.characters = characters;
148  rval.data.key.charactersIgnoringModifiers = rval.data.key.characters;
149  rval.data.key.isARepeat = (autoKey == evt->what);
150  rval.data.key.keyCode = (evt->message & keyCodeMask) >> 8;
151  }
152  } break;
153  case updateEvt:
154  {
155  PluginWindowMacPtr pluginWindow = m_PluginWindow.lock();
156  if (pluginWindow && PluginWindowMac::DrawingModelCoreGraphics == pluginWindow->getDrawingModel()) {
157  FB::Rect bounds = pluginWindow->getWindowPosition();
158  rval.type = NPCocoaEventDrawRect;
159  rval.data.draw.context = (CGContextRef)pluginWindow->getDrawingPrimitive();
160  rval.data.draw.x = bounds.left;
161  rval.data.draw.y = bounds.top;
162  rval.data.draw.width = bounds.right - bounds.left;
163  rval.data.draw.height = bounds.bottom - bounds.top;
164  }
165  } break;
166  case activateEvt:
167  {
168  rval.type = NPCocoaEventWindowFocusChanged;
169  rval.data.focus.hasFocus = (evt->modifiers & activeFlag) ? true : false;
170  } break;
171  case NPEventType_GetFocusEvent:
172  {
173  rval.type = NPCocoaEventFocusChanged;
174  rval.data.focus.hasFocus = true;
175  } break;
176  case NPEventType_LoseFocusEvent:
177  {
178  rval.type = NPCocoaEventFocusChanged;
179  rval.data.focus.hasFocus = false;
180  } break;
181  case NPEventType_AdjustCursorEvent:
182  {
183  Point local = GlobalToLocal(evt->where);
184  bool mouseOver = isMouseOver(local);
185  if (mouseOver && !m_mouseEntered) {
186  rval.type = NPCocoaEventMouseEntered;
187  m_mouseEntered = true;
188  } else if (!mouseOver && m_mouseEntered) {
189  rval.type = NPCocoaEventMouseExited;
190  m_mouseEntered = false;
191  } else
192  rval.type = (evt->modifiers & btnState) ? NPCocoaEventMouseDragged : NPCocoaEventMouseMoved;
193  rval.data.mouse.modifierFlags = modifiersForEvent(evt);
194  rval.data.mouse.pluginX = local.h;
195  rval.data.mouse.pluginY = local.v;
196  rval.data.mouse.buttonNumber = (evt->modifiers & controlKey) ? kCGMouseButtonRight : kCGMouseButtonLeft;
197  rval.data.mouse.clickCount = 0;
198  rval.data.mouse.deltaX = 0;
199  rval.data.mouse.deltaY = 0;
200  rval.data.mouse.deltaZ = 0;
201  } break;
202  default: {
203  } break;
204  }
205 }
206 
207 /*
208  // This might work better. Firefox/WebKit probably already ran through this process to generate a UnicodeString and
209  // now is feeding us a keycode at a time and then we're recreating it again. Oh well.
210  // This will generate NPCocoaEventTextInput events.
211  // Since we seem to be getting modifier keys as events, we can use CGEventCreateKeyboardEvent and feed those through
212  // NPCocoaEventKeyDown and NPCocoaEventKeyUp
213  From Firefox nsChildView.cpp
214 
215  static const EventTypeSpec sTSMEvents[] = { { kEventClassTextInput, kEventTextInputUnicodeForKeyEvent } };
216  ::InstallEventHandler(::GetEventDispatcherTarget(),
217  ::NewEventHandlerUPP(PluginKeyEventsHandler),
218  GetEventTypeCount(sTSMEvents),
219  sTSMEvents,
220  NULL,
221  &gPluginKeyEventsHandler);
222 
223  InterfaceTypeList supportedServices;
224  supportedServices[0] = kTextServiceDocumentInterfaceType;
225  supportedServices[1] = kUnicodeDocumentInterfaceType;
226  ::NewTSMDocument(2, supportedServices, &mPluginTSMDoc, 0);
227  // We'll need to use the "input window".
228  ::UseInputWindow(mPluginTSMDoc, YES);
229  ::ActivateTSMDocument(mPluginTSMDoc);
230 
231  ::TSMSetDocumentProperty(mPluginTSMDoc, kFocusedChildViewTSMDocPropertyTag, sizeof(ChildView *), &self);
232  ::TSMProcessRawKeyEvent([theEvent _eventRef]);
233  ::TSMRemoveDocumentProperty(mPluginTSMDoc, kFocusedChildViewTSMDocPropertyTag);
234 
235  ::DeleteTSMDocument(mPluginTSMDoc);
236 
237  ::RemoveEventHandler(gPluginKeyEventsHandler);
238 */
239 
240 NPNSString* PluginEventMacCarbon::TranslateKeyEventRecord(const EventRecord *event) {
241  NPNSString* rval = NULL;
242 #if 1
243  // Nothing fancy, just covert the character to a unicode string.
244  UniChar unicodeString = (event->message & charCodeMask);
245  rval = (NPNSString*) [NSString stringWithCharacters:&unicodeString length:1];
246 #else
247  // Is the TISInputSource still selected? If not update the layout data.
248  if (!m_tisInputSource || (kCFBooleanFalse == (CFBooleanRef) TISGetInputSourceProperty(m_tisInputSource, kTISPropertyInputSourceIsSelected))) {
249  if (m_tisInputSource) CFRelease(m_tisInputSource);
250  m_tisInputSource = TISCopyCurrentKeyboardInputSource();
251  m_tisKeyLayoutData = (CFDataRef) TISGetInputSourceProperty(m_tisInputSource, kTISPropertyUnicodeKeyLayoutData);
252  }
253 
254  OSStatus status = paramErr;
255  if (m_tisKeyLayoutData) {
256  const UCKeyboardLayout *keyLayoutPtr = (const UCKeyboardLayout*) CFDataGetBytePtr(m_tisKeyLayoutData);
257  UInt16 virtualKeyCode = (event->message & keyCodeMask) >> 8;
258  UInt16 keyAction = (keyDown == event->what) ? kUCKeyActionDown : (keyUp == event->what) ? kUCKeyActionUp : kUCKeyActionAutoKey;
259  UInt32 modifierKeyState = (event->modifiers & keyCodeMask) >> 8;
260  UInt32 keyboardType = LMGetKbdType();
261  OptionBits keyTranslateOptions = 0;
262  UniCharCount maxStringLength = 255;
263  UniCharCount actualStringLength = 0;
264  UniChar unicodeString[255];
265 
266  status = UCKeyTranslate(keyLayoutPtr, virtualKeyCode, keyAction, modifierKeyState, keyboardType, keyTranslateOptions, &m_deadKeyState,
267  maxStringLength, &actualStringLength, unicodeString);
268  if (noErr == status) {
269  NSString* temp = [NSString stringWithCharacters:unicodeString length:actualStringLength];
270  NSLog(@"%s action=%d keyCode=%d modifiers=%d \"%@\"", __func__, keyAction, virtualKeyCode, modifierKeyState, temp);
271  rval = (NPNSString*) temp;
272  } else {
273  NSLog(@"%s action=%d keyCode=%d modifiers=%d err=%d", __func__, keyAction, virtualKeyCode, modifierKeyState, status);
274  }
275 
276  } else
277  NSLog(@"%s No KeyLayoutData", __func__);
278 #endif
279  return rval;
280 }
281 
282 #endif
283