1 /* 2 * Copyright (c) 2011, 2017, 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 java.awt.*; 29 import java.awt.peer.*; 30 31 import sun.awt.CGraphicsDevice; 32 33 class CRobot implements RobotPeer { 34 private static final int MOUSE_LOCATION_UNKNOWN = -1; 35 36 private final CGraphicsDevice fDevice; 37 private int mouseLastX = MOUSE_LOCATION_UNKNOWN; 38 private int mouseLastY = MOUSE_LOCATION_UNKNOWN; 39 40 // OS X doesn't generate dragged event as a result of button press and 41 // mouse move events. This means that we have to track buttons state 42 // in order to generate dragged events ourselves. 43 private int mouseButtonsState = 0; 44 45 /** 46 * Uses the given GraphicsDevice as the coordinate system for subsequent 47 * coordinate calls. 48 */ 49 public CRobot(Robot r, CGraphicsDevice d) { 50 fDevice = d; 51 initRobot(); 52 } 53 54 @Override 55 public void dispose() { 56 } 57 58 /** 59 * Moves mouse pointer to given screen coordinates. 60 * @param x X position 61 * @param y Y position 62 */ 63 @Override 64 public void mouseMove(int x, int y) { 65 mouseLastX = x; 66 mouseLastY = y; 67 68 mouseEvent(fDevice.getCGDisplayID(), mouseLastX, mouseLastY, 69 mouseButtonsState, true, true); 70 } 71 72 /** 73 * Presses one or more mouse buttons. 74 * 75 * @param buttons the button mask (combination of 76 * {@code InputEvent.BUTTON1/2/3_MASK}) 77 */ 78 @Override 79 public void mousePress(int buttons) { 80 mouseButtonsState |= buttons; 81 checkMousePos(); 82 mouseEvent(fDevice.getCGDisplayID(), mouseLastX, mouseLastY, 83 buttons, true, false); 84 } 85 86 /** 87 * Releases one or more mouse buttons. 88 * 89 * @param buttons the button mask (combination of 90 * {@code InputEvent.BUTTON1/2/3_MASK}) 91 */ 92 @Override 93 public void mouseRelease(int buttons) { 94 mouseButtonsState &= ~buttons; 95 checkMousePos(); 96 mouseEvent(fDevice.getCGDisplayID(), mouseLastX, mouseLastY, 97 buttons, false, false); 98 } 99 100 /** 101 * Set unknown mouse location, if needed. 102 */ 103 private void checkMousePos() { 104 if (mouseLastX == MOUSE_LOCATION_UNKNOWN || 105 mouseLastY == MOUSE_LOCATION_UNKNOWN) { 106 107 Rectangle deviceBounds = fDevice.getDefaultConfiguration().getBounds(); 108 Point mousePos = CCursorManager.getInstance().getCursorPosition(); 109 110 if (mousePos.x < deviceBounds.x) { 111 mousePos.x = deviceBounds.x; 112 } 113 else if (mousePos.x > deviceBounds.x + deviceBounds.width) { 114 mousePos.x = deviceBounds.x + deviceBounds.width; 115 } 116 117 if (mousePos.y < deviceBounds.y) { 118 mousePos.y = deviceBounds.y; 119 } 120 else if (mousePos.y > deviceBounds.y + deviceBounds.height) { 121 mousePos.y = deviceBounds.y + deviceBounds.height; 122 } 123 124 mouseLastX = mousePos.x; 125 mouseLastY = mousePos.y; 126 } 127 } 128 129 @Override 130 public native void mouseWheel(int wheelAmt); 131 132 /** 133 * Presses a given key. 134 * <p> 135 * Key codes that have more than one physical key associated with them 136 * (e.g. {@code KeyEvent.VK_SHIFT} could mean either the 137 * left or right shift key) will map to the left key. 138 * <p> 139 * Assumes that the 140 * peer implementations will throw an exception for other bogus 141 * values e.g. -1, 999999 142 * 143 * @param keycode the key to press (e.g. {@code KeyEvent.VK_A}) 144 */ 145 @Override 146 public void keyPress(final int keycode) { 147 keyEvent(keycode, true); 148 } 149 150 /** 151 * Releases a given key. 152 * <p> 153 * Key codes that have more than one physical key associated with them 154 * (e.g. {@code KeyEvent.VK_SHIFT} could mean either the 155 * left or right shift key) will map to the left key. 156 * <p> 157 * Assumes that the 158 * peer implementations will throw an exception for other bogus 159 * values e.g. -1, 999999 160 * 161 * @param keycode the key to release (e.g. {@code KeyEvent.VK_A}) 162 */ 163 @Override 164 public void keyRelease(final int keycode) { 165 keyEvent(keycode, false); 166 } 167 168 /** 169 * Returns the color of a pixel at the given screen coordinates. 170 * @param x X position of pixel 171 * @param y Y position of pixel 172 * @return color of the pixel 173 */ 174 @Override 175 public int getRGBPixel(int x, int y) { 176 int c[] = new int[1]; 177 double scale = fDevice.getScaleFactor(); 178 getScreenPixels(new Rectangle(x, y, (int) scale, (int) scale), c); 179 return c[0]; 180 } 181 182 /** 183 * Creates an image containing pixels read from the screen. 184 * @param bounds the rect to capture in screen coordinates 185 * @return the array of pixels 186 */ 187 @Override 188 public int [] getRGBPixels(final Rectangle bounds) { 189 int c[] = new int[bounds.width * bounds.height]; 190 getScreenPixels(bounds, c); 191 192 return c; 193 } 194 195 private native void initRobot(); 196 private native void mouseEvent(int displayID, int lastX, int lastY, 197 int buttonsState, 198 boolean isButtonsDownState, 199 boolean isMouseMove); 200 private native void keyEvent(int javaKeyCode, boolean keydown); 201 private void getScreenPixels(Rectangle r, int[] pixels){ 202 double scale = fDevice.getScaleFactor(); 203 nativeGetScreenPixels(r.x, r.y, r.width, r.height, scale, pixels); 204 } 205 private native void nativeGetScreenPixels(int x, int y, int width, int height, double scale, int[] pixels); 206 }