1 /* 2 * Copyright (c) 2010, 2016, 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 package com.sun.glass.ui; 26 27 import static com.sun.javafx.FXPermissions.CREATE_ROBOT_PERMISSION; 28 import java.nio.IntBuffer; 29 30 public abstract class Robot { 31 32 final static public int MOUSE_LEFT_BTN = 1; 33 final static public int MOUSE_RIGHT_BTN = 2; 34 final static public int MOUSE_MIDDLE_BTN = 4; 35 36 protected abstract void _create(); 37 protected Robot() { 38 // Ensure proper permission 39 final SecurityManager sm = System.getSecurityManager(); 40 if (sm != null) { 41 sm.checkPermission(CREATE_ROBOT_PERMISSION); 42 } 43 Application.checkEventThread(); 44 _create(); 45 } 46 47 protected abstract void _destroy(); 48 public void destroy() { 49 Application.checkEventThread(); 50 _destroy(); 51 } 52 53 protected abstract void _keyPress(int code); 54 /** 55 * Generate a key pressed event. 56 * @param code key code for this event 57 */ 58 public void keyPress(int code) { 59 Application.checkEventThread(); 60 _keyPress(code); 61 } 62 63 protected abstract void _keyRelease(int code); 64 /** 65 * Generate a key released event. 66 * 67 * @param code key code for this event 68 */ 69 public void keyRelease(int code) { 70 Application.checkEventThread(); 71 _keyRelease(code); 72 } 73 74 protected abstract void _mouseMove(int x, int y); 75 /** 76 * Generate a mouse moved event. 77 * 78 * @param x screen coordinate x 79 * @param y screen coordinate y 80 */ 81 public void mouseMove(int x, int y) { 82 Application.checkEventThread(); 83 _mouseMove(x, y); 84 } 85 86 protected abstract void _mousePress(int buttons); 87 /** 88 * Generate a mouse press event with specified buttons mask. 89 * 90 * Up to 32-buttons mice are supported. Other buttons are inaccessible 91 * by the robot. Bits 0, 1, and 2 mean LEFT, RIGHT, and MIDDLE mouse buttons 92 * respectively. 93 * 94 * @param buttons buttons to have generated the event 95 */ 96 public void mousePress(int buttons) { 97 Application.checkEventThread(); 98 _mousePress(buttons); 99 } 100 101 protected abstract void _mouseRelease(int buttons); 102 /** 103 * Generate a mouse release event with specified buttons mask. 104 * 105 * @param buttons buttons to have generated the event 106 */ 107 public void mouseRelease(int buttons) { 108 Application.checkEventThread(); 109 _mouseRelease(buttons); 110 } 111 112 protected abstract void _mouseWheel(int wheelAmt); 113 /** 114 * Generate a mouse wheel event. 115 * 116 * @param wheelAmt amount the wheel has turned of wheel turning 117 */ 118 public void mouseWheel(int wheelAmt) { 119 Application.checkEventThread(); 120 _mouseWheel(wheelAmt); 121 } 122 123 protected abstract int _getMouseX(); 124 public int getMouseX() { 125 Application.checkEventThread(); 126 return _getMouseX(); 127 } 128 129 protected abstract int _getMouseY(); 130 public int getMouseY() { 131 Application.checkEventThread(); 132 return _getMouseY(); 133 } 134 135 protected abstract int _getPixelColor(int x, int y); 136 /** 137 * Returns pixel color at specified screen coordinates in IntARGB format. 138 */ 139 public int getPixelColor(int x, int y) { 140 Application.checkEventThread(); 141 return _getPixelColor(x, y); 142 } 143 144 // Subclasses must override and implement at least one of the following two 145 // _getScreenCapture methods 146 147 protected void _getScreenCapture(int x, int y, int width, int height, int[] data) { 148 throw new UnsupportedOperationException("Not implementated in the base class"); 149 } 150 151 protected Pixels _getScreenCapture(int x, int y, int width, int height, boolean isHiDPI) { 152 Screen mainScreen = Screen.getMainScreen(); 153 float uiScaleX = mainScreen.getPlatformScaleX(); 154 float uiScaleY = mainScreen.getPlatformScaleY(); 155 int data[]; 156 int dw, dh; 157 if (uiScaleX == 1.0f && uiScaleY == 1.0f) { 158 data = new int[width * height]; 159 _getScreenCapture(x, y, width, height, data); 160 dw = width; 161 dh = height; 162 } else { 163 int pminx = (int) Math.floor(x * uiScaleX); 164 int pminy = (int) Math.floor(y * uiScaleY); 165 int pmaxx = (int) Math.ceil((x + width) * uiScaleX); 166 int pmaxy = (int) Math.ceil((y + height) * uiScaleY); 167 int pwidth = pmaxx - pminx; 168 int pheight = pmaxy - pminy; 169 int tmpdata[] = new int[pwidth * pheight]; 170 _getScreenCapture(pminx, pminy, pwidth, pheight, tmpdata); 171 if (isHiDPI) { 172 data = tmpdata; 173 dw = pwidth; 174 dh = pheight; 175 } else { 176 data = new int[width * height]; 177 int index = 0; 178 for (int iy = 0; iy < height; iy++) { 179 float rely = ((y + iy + 0.5f) * uiScaleY) - (pminy + 0.5f); 180 int irely = (int) Math.floor(rely); 181 int fracty = (int) ((rely - irely) * 256); 182 for (int ix = 0; ix < width; ix++) { 183 float relx = ((x + ix + 0.5f) * uiScaleX) - (pminx + 0.5f); 184 int irelx = (int) Math.floor(relx); 185 int fractx = (int) ((relx - irelx) * 256); 186 data[index++] = 187 interp(tmpdata, irelx, irely, pwidth, pheight, fractx, fracty); 188 } 189 } 190 dw = width; 191 dh = height; 192 } 193 } 194 return Application.GetApplication().createPixels(dw, dh, IntBuffer.wrap(data)); 195 } 196 197 /** 198 * Returns a capture of the specified rectangular area of the screen. 199 * 200 * If {@code isHiDPI} argument is {@code true}, the returned Pixels object 201 * dimensions may differ from the requested {@code width} and {@code 202 * height} depending on how many physical pixels the area occupies on the 203 * screen. E.g. in HiDPI mode on the Mac (aka Retina display) the pixels 204 * are doubled, and thus a screen capture of an area of size (10x10) pixels 205 * will result in a Pixels object with dimensions (20x20). Calling code 206 * should use the returned objects's getWidth() and getHeight() methods 207 * to determine the image size. 208 * 209 * If (@code isHiDPI) is {@code false}, the returned Pixels object is of 210 * the requested size. Note that in this case the image may be scaled in 211 * order to fit to the requested dimensions if running on a HiDPI display. 212 */ 213 public Pixels getScreenCapture(int x, int y, int width, int height, boolean isHiDPI) { 214 Application.checkEventThread(); 215 return _getScreenCapture(x, y, width, height, isHiDPI); 216 } 217 218 /** 219 * Returns a capture of the specified area of the screen. 220 * It is equivalent to calling getScreenCapture(x, y, width, height, false), 221 * i.e. this method takes a "LowDPI" screen shot. 222 */ 223 public Pixels getScreenCapture(int x, int y, int width, int height) { 224 return getScreenCapture(x, y, width, height, false); 225 } 226 227 private static int interp(int pixels[], int x, int y, int w, int h, int fractx1, int fracty1) { 228 int fractx0 = 256 - fractx1; 229 int fracty0 = 256 - fracty1; 230 int i = y * w + x; 231 int rgb00 = (x < 0 || y < 0 || x >= w || y >= h) ? 0 : pixels[i]; 232 if (fracty1 == 0) { 233 // No interplation with pixels[y+1] 234 if (fractx1 == 0) { 235 // No interpolation with any neighbors 236 return rgb00; 237 } 238 int rgb10 = (y < 0 || x+1 >= w || y >= h) ? 0 : pixels[i+1]; 239 return interp(rgb00, rgb10, fractx0, fractx1); 240 } else if (fractx1 == 0) { 241 // No interpolation with pixels[x+1] 242 int rgb01 = (x < 0 || x >= w || y+1 >= h) ? 0 : pixels[i+w]; 243 return interp(rgb00, rgb01, fracty0, fracty1); 244 } else { 245 // All 4 neighbors must be interpolated 246 int rgb10 = (y < 0 || x+1 >= w || y >= h) ? 0 : pixels[i+1]; 247 int rgb01 = (x < 0 || x >= w || y+1 >= h) ? 0 : pixels[i+w]; 248 int rgb11 = (x+1 >= w || y+1 >= h) ? 0 : pixels[i+w+1]; 249 return interp(interp(rgb00, rgb10, fractx0, fractx1), 250 interp(rgb01, rgb11, fractx0, fractx1), 251 fracty0, fracty1); 252 } 253 } 254 255 private static int interp(int rgb0, int rgb1, int fract0, int fract1) { 256 int a0 = (rgb0 >> 24) & 0xff; 257 int r0 = (rgb0 >> 16) & 0xff; 258 int g0 = (rgb0 >> 8) & 0xff; 259 int b0 = (rgb0 ) & 0xff; 260 int a1 = (rgb1 >> 24) & 0xff; 261 int r1 = (rgb1 >> 16) & 0xff; 262 int g1 = (rgb1 >> 8) & 0xff; 263 int b1 = (rgb1 ) & 0xff; 264 int a = (a0 * fract0 + a1 * fract1) >> 8; 265 int r = (r0 * fract0 + r1 * fract1) >> 8; 266 int g = (g0 * fract0 + g1 * fract1) >> 8; 267 int b = (b0 * fract0 + b1 * fract1) >> 8; 268 return (a << 24) | (r << 16) | (g << 8) | b; 269 } 270 }