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.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 */ CRobot(Robot r, CGraphicsDevice d)52 public CRobot(Robot r, CGraphicsDevice d) { 53 fDevice = d; 54 initRobot(); 55 } 56 57 @Override dispose()58 public void dispose() { 59 } 60 61 /** 62 * Moves mouse pointer to given screen coordinates. 63 * @param x X position 64 * @param y Y position 65 */ 66 @Override mouseMove(int x, int y)67 public void mouseMove(int x, int y) { 68 mouseLastX = x; 69 mouseLastY = y; 70 71 mouseEvent(mouseLastX, mouseLastY, mouseButtonsState, true, true); 72 } 73 74 /** 75 * Presses one or more mouse buttons. 76 * 77 * @param buttons the button mask (combination of 78 * {@code InputEvent.BUTTON1/2/3_MASK}) 79 */ 80 @Override mousePress(int buttons)81 public void mousePress(int buttons) { 82 mouseButtonsState |= buttons; 83 checkMousePos(); 84 mouseEvent(mouseLastX, mouseLastY, buttons, true, false); 85 } 86 87 /** 88 * Releases one or more mouse buttons. 89 * 90 * @param buttons the button mask (combination of 91 * {@code InputEvent.BUTTON1/2/3_MASK}) 92 */ 93 @Override mouseRelease(int buttons)94 public void mouseRelease(int buttons) { 95 mouseButtonsState &= ~buttons; 96 checkMousePos(); 97 mouseEvent(mouseLastX, mouseLastY, buttons, false, false); 98 } 99 100 /** 101 * Set unknown mouse location, if needed. 102 */ checkMousePos()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 mouseWheel(int wheelAmt)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 keyPress(final int keycode)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 keyRelease(final int keycode)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 getRGBPixel(int x, int y)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 getRGBPixels(final Rectangle bounds)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 initRobot()195 private native void initRobot(); mouseEvent(int lastX, int lastY, int buttonsState, boolean isButtonsDownState, boolean isMouseMove)196 private native void mouseEvent(int lastX, int lastY, int buttonsState, 197 boolean isButtonsDownState, 198 boolean isMouseMove); keyEvent(int javaKeyCode, boolean keydown)199 private native void keyEvent(int javaKeyCode, boolean keydown); getScreenPixels(Rectangle r, int[] pixels)200 private void getScreenPixels(Rectangle r, int[] pixels){ 201 double scale = fDevice.getScaleFactor(); 202 nativeGetScreenPixels(r.x, r.y, r.width, r.height, scale, pixels); 203 } nativeGetScreenPixels(int x, int y, int width, int height, double scale, int[] pixels)204 private native void nativeGetScreenPixels(int x, int y, int width, int height, double scale, int[] pixels); 205 } 206