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