1 /* 2 * Copyright (c) 2011, 2015, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 package sun.lwawt.macosx; 27 28 import sun.awt.SunToolkit; 29 import sun.lwawt.LWWindowPeer; 30 import sun.lwawt.PlatformEventNotifier; 31 32 import java.awt.Toolkit; 33 import java.awt.event.MouseEvent; 34 import java.awt.event.InputEvent; 35 import java.awt.event.MouseWheelEvent; 36 import java.awt.event.KeyEvent; 37 38 /** 39 * Translates NSEvents/NPCocoaEvents into AWT events. 40 */ 41 final class CPlatformResponder { 42 43 private final PlatformEventNotifier eventNotifier; 44 private final boolean isNpapiCallback; 45 private int lastKeyPressCode = KeyEvent.VK_UNDEFINED; 46 47 CPlatformResponder(final PlatformEventNotifier eventNotifier, 48 final boolean isNpapiCallback) { 49 this.eventNotifier = eventNotifier; 50 this.isNpapiCallback = isNpapiCallback; 51 } 52 53 /** 54 * Handles mouse events. 55 */ 56 void handleMouseEvent(int eventType, int modifierFlags, int buttonNumber, 57 int clickCount, int x, int y, int absX, int absY) { 58 final SunToolkit tk = (SunToolkit)Toolkit.getDefaultToolkit(); 59 if ((buttonNumber > 2 && !tk.areExtraMouseButtonsEnabled()) 60 || buttonNumber > tk.getNumberOfButtons() - 1) { 61 return; 62 } 63 64 int jeventType = isNpapiCallback ? NSEvent.npToJavaEventType(eventType) : 65 NSEvent.nsToJavaEventType(eventType); 66 67 int jbuttonNumber = MouseEvent.NOBUTTON; 68 int jclickCount = 0; 69 70 if (jeventType != MouseEvent.MOUSE_MOVED && 71 jeventType != MouseEvent.MOUSE_ENTERED && 72 jeventType != MouseEvent.MOUSE_EXITED) 73 { 74 jbuttonNumber = NSEvent.nsToJavaButton(buttonNumber); 75 jclickCount = clickCount; 76 } 77 78 int jmodifiers = NSEvent.nsToJavaModifiers(modifierFlags); 79 boolean jpopupTrigger = NSEvent.isPopupTrigger(jmodifiers); 80 81 eventNotifier.notifyMouseEvent(jeventType, System.currentTimeMillis(), jbuttonNumber, 82 x, y, absX, absY, jmodifiers, jclickCount, 83 jpopupTrigger, null); 84 } 85 86 /** 87 * Handles scroll events. 88 */ 89 void handleScrollEvent(final int x, final int y, final int absX, 90 final int absY, final int modifierFlags, 91 final double deltaX, final double deltaY) { 92 int jmodifiers = NSEvent.nsToJavaModifiers(modifierFlags); 93 final boolean isShift = (jmodifiers & InputEvent.SHIFT_DOWN_MASK) != 0; 94 95 // Vertical scroll. 96 if (!isShift && deltaY != 0.0) { 97 dispatchScrollEvent(x, y, absX, absY, jmodifiers, deltaY); 98 } 99 // Horizontal scroll or shirt+vertical scroll. 100 final double delta = isShift && deltaY != 0.0 ? deltaY : deltaX; 101 if (delta != 0.0) { 102 jmodifiers |= InputEvent.SHIFT_DOWN_MASK; 103 dispatchScrollEvent(x, y, absX, absY, jmodifiers, delta); 104 } 105 } 106 107 private void dispatchScrollEvent(final int x, final int y, final int absX, 108 final int absY, final int modifiers, 109 final double delta) { 110 final long when = System.currentTimeMillis(); 111 final int scrollType = MouseWheelEvent.WHEEL_UNIT_SCROLL; 112 final int scrollAmount = 1; 113 int wheelRotation = (int) delta; 114 int signum = (int) Math.signum(delta); 115 if (signum * delta < 1) { 116 wheelRotation = signum; 117 } 118 // invert the wheelRotation for the peer 119 eventNotifier.notifyMouseWheelEvent(when, x, y, absX, absY, modifiers, 120 scrollType, scrollAmount, 121 -wheelRotation, -delta, null); 122 } 123 124 /** 125 * Handles key events. 126 */ 127 void handleKeyEvent(int eventType, int modifierFlags, String chars, String charsIgnoringModifiers, 128 short keyCode, boolean needsKeyTyped, boolean needsKeyReleased) { 129 boolean isFlagsChangedEvent = 130 isNpapiCallback ? (eventType == CocoaConstants.NPCocoaEventFlagsChanged) : 131 (eventType == CocoaConstants.NSFlagsChanged); 132 133 int jeventType = KeyEvent.KEY_PRESSED; 134 int jkeyCode = KeyEvent.VK_UNDEFINED; 135 int jkeyLocation = KeyEvent.KEY_LOCATION_UNKNOWN; 136 boolean postsTyped = false; 137 138 char testChar = KeyEvent.CHAR_UNDEFINED; 139 boolean isDeadChar = (chars!= null && chars.length() == 0); 140 141 if (isFlagsChangedEvent) { 142 int[] in = new int[] {modifierFlags, keyCode}; 143 int[] out = new int[3]; // [jkeyCode, jkeyLocation, jkeyType] 144 145 NSEvent.nsKeyModifiersToJavaKeyInfo(in, out); 146 147 jkeyCode = out[0]; 148 jkeyLocation = out[1]; 149 jeventType = out[2]; 150 } else { 151 if (chars != null && chars.length() > 0) { 152 testChar = chars.charAt(0); 153 } 154 155 char testCharIgnoringModifiers = charsIgnoringModifiers != null && charsIgnoringModifiers.length() > 0 ? 156 charsIgnoringModifiers.charAt(0) : KeyEvent.CHAR_UNDEFINED; 157 158 int[] in = new int[] {testCharIgnoringModifiers, isDeadChar ? 1 : 0, modifierFlags, keyCode}; 159 int[] out = new int[3]; // [jkeyCode, jkeyLocation, deadChar] 160 161 postsTyped = NSEvent.nsToJavaKeyInfo(in, out); 162 if (!postsTyped) { 163 testChar = KeyEvent.CHAR_UNDEFINED; 164 } 165 166 if(isDeadChar){ 167 testChar = (char) out[2]; 168 if(testChar == 0){ 169 return; 170 } 171 } 172 173 jkeyCode = out[0]; 174 jkeyLocation = out[1]; 175 jeventType = isNpapiCallback ? NSEvent.npToJavaEventType(eventType) : 176 NSEvent.nsToJavaEventType(eventType); 177 } 178 179 char javaChar = NSEvent.nsToJavaChar(testChar, modifierFlags); 180 // Some keys may generate a KEY_TYPED, but we can't determine 181 // what that character is. That's likely a bug, but for now we 182 // just check for CHAR_UNDEFINED. 183 if (javaChar == KeyEvent.CHAR_UNDEFINED) { 184 postsTyped = false; 185 } 186 187 int jmodifiers = NSEvent.nsToJavaModifiers(modifierFlags); 188 long when = System.currentTimeMillis(); 189 190 if (jeventType == KeyEvent.KEY_PRESSED) { 191 lastKeyPressCode = jkeyCode; 192 } 193 eventNotifier.notifyKeyEvent(jeventType, when, jmodifiers, 194 jkeyCode, javaChar, jkeyLocation); 195 196 // Current browser may be sending input events, so don't 197 // post the KEY_TYPED here. 198 postsTyped &= needsKeyTyped; 199 200 // That's the reaction on the PRESSED (not RELEASED) event as it comes to 201 // appear in MacOSX. 202 // Modifier keys (shift, etc) don't want to send TYPED events. 203 // On the other hand we don't want to generate keyTyped events 204 // for clipboard related shortcuts like Meta + [CVX] 205 if (jeventType == KeyEvent.KEY_PRESSED && postsTyped && 206 (jmodifiers & KeyEvent.META_DOWN_MASK) == 0) { 207 // Enter and Space keys finish the input method processing, 208 // KEY_TYPED and KEY_RELEASED events for them are synthesized in handleInputEvent. 209 if (needsKeyReleased && (jkeyCode == KeyEvent.VK_ENTER || jkeyCode == KeyEvent.VK_SPACE)) { 210 return; 211 } 212 eventNotifier.notifyKeyEvent(KeyEvent.KEY_TYPED, when, jmodifiers, 213 KeyEvent.VK_UNDEFINED, javaChar, 214 KeyEvent.KEY_LOCATION_UNKNOWN); 215 //If events come from Firefox, released events should also be generated. 216 if (needsKeyReleased) { 217 eventNotifier.notifyKeyEvent(KeyEvent.KEY_RELEASED, when, jmodifiers, 218 jkeyCode, javaChar, 219 KeyEvent.KEY_LOCATION_UNKNOWN); 220 } 221 } 222 } 223 224 void handleInputEvent(String text) { 225 if (text != null) { 226 int index = 0, length = text.length(); 227 char c = 0; 228 while (index < length) { 229 c = text.charAt(index); 230 eventNotifier.notifyKeyEvent(KeyEvent.KEY_TYPED, 231 System.currentTimeMillis(), 232 0, KeyEvent.VK_UNDEFINED, c, 233 KeyEvent.KEY_LOCATION_UNKNOWN); 234 index++; 235 } 236 eventNotifier.notifyKeyEvent(KeyEvent.KEY_RELEASED, 237 System.currentTimeMillis(), 238 0, lastKeyPressCode, c, 239 KeyEvent.KEY_LOCATION_UNKNOWN); 240 } 241 } 242 243 void handleWindowFocusEvent(boolean gained, LWWindowPeer opposite) { 244 eventNotifier.notifyActivation(gained, opposite); 245 } 246 }