1 /* 2 * Copyright (c) 2011, 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.macosx.event.NSEvent; 31 import java.awt.Toolkit; 32 import java.awt.event.MouseEvent; 33 import java.awt.event.InputEvent; 34 import java.awt.event.MouseWheelEvent; 35 import java.awt.event.KeyEvent; 36 37 /** 38 * Translates NSEvents/NPCocoaEvents into AWT events. 39 */ 40 final class CPlatformResponder { 41 42 private final LWWindowPeer peer; 43 private final boolean isNpapiCallback; 44 private int lastKeyPressCode = KeyEvent.VK_UNDEFINED; 45 46 CPlatformResponder(final LWWindowPeer peer, final boolean isNpapiCallback) { 47 this.peer = peer; 48 this.isNpapiCallback = isNpapiCallback; 49 } 50 51 /** 52 * Handles mouse events. 53 */ 54 void handleMouseEvent(int eventType, int modifierFlags, int buttonNumber, 55 int clickCount, int x, int y, int absoluteX, 56 int absoluteY) { 57 final SunToolkit tk = (SunToolkit)Toolkit.getDefaultToolkit(); 58 if ((buttonNumber > 2 && !tk.areExtraMouseButtonsEnabled()) 59 || buttonNumber > tk.getNumberOfButtons() - 1) { 60 return; 61 } 62 63 int jeventType = isNpapiCallback ? NSEvent.npToJavaEventType(eventType) : 64 NSEvent.nsToJavaEventType(eventType); 65 66 int jbuttonNumber = MouseEvent.NOBUTTON; 67 int jclickCount = 0; 68 69 if (jeventType != MouseEvent.MOUSE_MOVED && 70 jeventType != MouseEvent.MOUSE_ENTERED && 71 jeventType != MouseEvent.MOUSE_EXITED) 72 { 73 jbuttonNumber = NSEvent.nsToJavaButton(buttonNumber); 74 jclickCount = clickCount; 75 } 76 77 int jmodifiers = NSEvent.nsToJavaMouseModifiers(buttonNumber, 78 modifierFlags); 79 boolean jpopupTrigger = NSEvent.isPopupTrigger(jmodifiers); 80 81 peer.dispatchMouseEvent(jeventType, System.currentTimeMillis(), jbuttonNumber, 82 x, y, absoluteX, absoluteY, jmodifiers, jclickCount, 83 jpopupTrigger, null); 84 } 85 86 /** 87 * Handles scroll events. 88 */ 89 void handleScrollEvent(final int x, final int y, final int modifierFlags, 90 final double deltaX, final double deltaY) { 91 final int buttonNumber = CocoaConstants.kCGMouseButtonCenter; 92 int jmodifiers = NSEvent.nsToJavaMouseModifiers(buttonNumber, 93 modifierFlags); 94 final boolean isShift = (jmodifiers & InputEvent.SHIFT_DOWN_MASK) != 0; 95 96 // Vertical scroll. 97 if (!isShift && deltaY != 0.0) { 98 dispatchScrollEvent(x, y, jmodifiers, deltaY); 99 } 100 // Horizontal scroll or shirt+vertical scroll. 101 final double delta = isShift && deltaY != 0.0 ? deltaY : deltaX; 102 if (delta != 0.0) { 103 jmodifiers |= InputEvent.SHIFT_DOWN_MASK; 104 dispatchScrollEvent(x, y, jmodifiers, delta); 105 } 106 } 107 108 private void dispatchScrollEvent(final int x, final int y, 109 final int modifiers, 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 peer.dispatchMouseWheelEvent(when, x, y, modifiers, scrollType, 120 scrollAmount, -wheelRotation, -delta, null); 121 } 122 123 /** 124 * Handles key events. 125 */ 126 void handleKeyEvent(int eventType, int modifierFlags, String chars, 127 short keyCode, boolean needsKeyTyped) { 128 boolean isFlagsChangedEvent = 129 isNpapiCallback ? (eventType == CocoaConstants.NPCocoaEventFlagsChanged) : 130 (eventType == CocoaConstants.NSFlagsChanged); 131 132 int jeventType = KeyEvent.KEY_PRESSED; 133 int jkeyCode = KeyEvent.VK_UNDEFINED; 134 int jkeyLocation = KeyEvent.KEY_LOCATION_UNKNOWN; 135 boolean postsTyped = false; 136 137 char testChar = KeyEvent.CHAR_UNDEFINED; 138 boolean isDeadChar = (chars!= null && chars.length() == 0); 139 140 if (isFlagsChangedEvent) { 141 int[] in = new int[] {modifierFlags, keyCode}; 142 int[] out = new int[3]; // [jkeyCode, jkeyLocation, jkeyType] 143 144 NSEvent.nsKeyModifiersToJavaKeyInfo(in, out); 145 146 jkeyCode = out[0]; 147 jkeyLocation = out[1]; 148 jeventType = out[2]; 149 } else { 150 if (chars != null && chars.length() > 0) { 151 testChar = chars.charAt(0); 152 } 153 154 int[] in = new int[] {testChar, isDeadChar ? 1 : 0, modifierFlags, keyCode}; 155 int[] out = new int[3]; // [jkeyCode, jkeyLocation, deadChar] 156 157 postsTyped = NSEvent.nsToJavaKeyInfo(in, out); 158 if (!postsTyped) { 159 testChar = KeyEvent.CHAR_UNDEFINED; 160 } 161 162 if(isDeadChar){ 163 testChar = (char) out[2]; 164 if(testChar == 0){ 165 return; 166 } 167 } 168 169 jkeyCode = out[0]; 170 jkeyLocation = out[1]; 171 jeventType = isNpapiCallback ? NSEvent.npToJavaEventType(eventType) : 172 NSEvent.nsToJavaEventType(eventType); 173 } 174 175 char javaChar = NSEvent.nsToJavaChar(testChar, modifierFlags); 176 // Some keys may generate a KEY_TYPED, but we can't determine 177 // what that character is. That's likely a bug, but for now we 178 // just check for CHAR_UNDEFINED. 179 if (javaChar == KeyEvent.CHAR_UNDEFINED) { 180 postsTyped = false; 181 } 182 183 184 int jmodifiers = NSEvent.nsToJavaKeyModifiers(modifierFlags); 185 long when = System.currentTimeMillis(); 186 187 if (jeventType == KeyEvent.KEY_PRESSED) { 188 lastKeyPressCode = jkeyCode; 189 } 190 peer.dispatchKeyEvent(jeventType, when, jmodifiers, 191 jkeyCode, javaChar, jkeyLocation); 192 193 // Current browser may be sending input events, so don't 194 // post the KEY_TYPED here. 195 postsTyped &= needsKeyTyped; 196 197 // That's the reaction on the PRESSED (not RELEASED) event as it comes to 198 // appear in MacOSX. 199 // Modifier keys (shift, etc) don't want to send TYPED events. 200 // On the other hand we don't want to generate keyTyped events 201 // for clipboard related shortcuts like Meta + [CVX] 202 boolean isMetaDown = (jmodifiers & KeyEvent.META_DOWN_MASK) != 0; 203 if (jeventType == KeyEvent.KEY_PRESSED && postsTyped && !isMetaDown) { 204 peer.dispatchKeyEvent(KeyEvent.KEY_TYPED, when, jmodifiers, 205 KeyEvent.VK_UNDEFINED, javaChar, 206 KeyEvent.KEY_LOCATION_UNKNOWN); 207 } 208 } 209 210 void handleInputEvent(String text) { 211 if (text != null) { 212 int index = 0, length = text.length(); 213 char c; 214 while (index < length) { 215 c = text.charAt(index); 216 peer.dispatchKeyEvent(KeyEvent.KEY_TYPED, 217 System.currentTimeMillis(), 218 0, KeyEvent.VK_UNDEFINED, c, 219 KeyEvent.KEY_LOCATION_UNKNOWN); 220 peer.dispatchKeyEvent(KeyEvent.KEY_RELEASED, 221 System.currentTimeMillis(), 222 0, lastKeyPressCode, c, 223 KeyEvent.KEY_LOCATION_UNKNOWN); 224 index++; 225 } 226 } 227 } 228 229 void handleWindowFocusEvent(boolean gained, LWWindowPeer opposite) { 230 peer.notifyActivation(gained, opposite); 231 } 232 }