1 /*
   2  * Copyright (c) 2014, 2018, 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 com.sun.glass.ui.monocle;
  27 
  28 import java.nio.ByteBuffer;
  29 import java.nio.IntBuffer;
  30 import java.nio.ShortBuffer;
  31 
  32 import javafx.scene.input.KeyCode;
  33 import javafx.scene.input.MouseButton;
  34 import javafx.scene.paint.Color;
  35 
  36 import com.sun.glass.events.MouseEvent;
  37 import com.sun.glass.ui.Application;
  38 import com.sun.glass.ui.GlassRobot;
  39 
  40 class MonocleRobot extends GlassRobot {
  41     @Override
  42     public void create() {
  43         // no-op
  44     }
  45 
  46     @Override
  47     public void destroy() {
  48         // no-op
  49     }
  50 
  51     @Override
  52     public void keyPress(KeyCode code) {
  53         Application.checkEventThread();
  54         KeyState state = new KeyState();
  55         KeyInput.getInstance().getState(state);
  56         state.pressKey(code.getCode());
  57         KeyInput.getInstance().setState(state);
  58     }
  59 
  60     @Override
  61     public void keyRelease(KeyCode code) {
  62         Application.checkEventThread();
  63         KeyState state = new KeyState();
  64         KeyInput.getInstance().getState(state);
  65         state.releaseKey(code.getCode());
  66         KeyInput.getInstance().setState(state);
  67     }
  68 
  69     @Override
  70     public void mouseMove(double x, double y) {
  71         Application.checkEventThread();
  72         MouseState state = new MouseState();
  73         MouseInput.getInstance().getState(state);
  74         state.setX((int) x);
  75         state.setY((int) y);
  76         MouseInput.getInstance().setState(state, false);
  77     }
  78 
  79     private static MouseState convertToMouseState(boolean press, MouseState state, MouseButton... buttons) {
  80         for (MouseButton button : buttons) {
  81             switch (button) {
  82                 case PRIMARY:
  83                     if (press) {
  84                         state.pressButton(MouseEvent.BUTTON_LEFT);
  85                     } else {
  86                         state.releaseButton(MouseEvent.BUTTON_LEFT);
  87                     }
  88                     break;
  89                 case SECONDARY:
  90                     if (press) {
  91                         state.pressButton(MouseEvent.BUTTON_RIGHT);
  92                     } else {
  93                         state.releaseButton(MouseEvent.BUTTON_RIGHT);
  94                     }
  95                     break;
  96                 case MIDDLE:
  97                     if (press) {
  98                         state.pressButton(MouseEvent.BUTTON_OTHER);
  99                     } else {
 100                         state.releaseButton(MouseEvent.BUTTON_OTHER);
 101                     }
 102                     break;
 103                 default: throw new IllegalArgumentException("MouseButton: " + button +
 104                         " not supported by Monocle Robot");
 105             }
 106         }
 107         return state;
 108     }
 109 
 110     @Override
 111     public void mousePress(MouseButton... buttons) {
 112         Application.checkEventThread();
 113         MouseState state = new MouseState();
 114         MouseInput.getInstance().getState(state);
 115         MouseInput.getInstance().setState(convertToMouseState(true, state, buttons), false);
 116     }
 117 
 118     @Override
 119     public void mouseRelease(MouseButton... buttons) {
 120         Application.checkEventThread();
 121         MouseState state = new MouseState();
 122         MouseInput.getInstance().getState(state);
 123         MouseInput.getInstance().setState(convertToMouseState(false, state, buttons), false);
 124     }
 125 
 126     @Override
 127     public void mouseWheel(int wheelAmt) {
 128         Application.checkEventThread();
 129         MouseState state = new MouseState();
 130         MouseInput mouse = MouseInput.getInstance();
 131         mouse.getState(state);
 132         int direction = wheelAmt < 0
 133                         ? MouseState.WHEEL_DOWN
 134                         : MouseState.WHEEL_UP;
 135         for (int i = 0; i < Math.abs(wheelAmt); i++) {
 136             state.setWheel(direction);
 137             mouse.setState(state, false);
 138             state.setWheel(MouseState.WHEEL_NONE);
 139             mouse.setState(state, false);
 140         }
 141     }
 142 
 143     @Override
 144     public double getMouseX() {
 145         Application.checkEventThread();
 146         MouseState state = new MouseState();
 147         MouseInput.getInstance().getState(state);
 148         return state.getX();
 149     }
 150 
 151     @Override
 152     public double getMouseY() {
 153         Application.checkEventThread();
 154         MouseState state = new MouseState();
 155         MouseInput.getInstance().getState(state);
 156         return state.getY();
 157     }
 158 
 159     @Override
 160     public Color getPixelColor(double x, double y) {
 161         Application.checkEventThread();
 162         NativeScreen screen = NativePlatformFactory.getNativePlatform().getScreen();
 163         final int byteDepth = screen.getDepth() >>> 3;
 164         final int bwidth = screen.getWidth();
 165         final int bheight = screen.getHeight();
 166 
 167         if (x < 0 || x > bwidth || y < 0 || y > bheight) {
 168             return GlassRobot.convertFromIntArgb(0);
 169         }
 170 
 171         synchronized (NativeScreen.framebufferSwapLock) {
 172 
 173             ByteBuffer buffer = screen.getScreenCapture();
 174 
 175             if (byteDepth == 2) {
 176                 ShortBuffer shortbuf = buffer.asShortBuffer();
 177 
 178                 int v = shortbuf.get((int) (y * bwidth) + (int) x);
 179                 int red = (v & 0xF800) >> 11 << 3;
 180                 int green = (v & 0x7E0) >> 5 << 2;
 181                 int blue = (v & 0x1F) << 3;
 182 
 183                 int p = (0xff000000
 184                         | (red << 16)
 185                         | (green << 8)
 186                         | blue);
 187                 return GlassRobot.convertFromIntArgb(p);
 188             } else if (byteDepth >= 4) {
 189                 IntBuffer intbuf = buffer.asIntBuffer();
 190                 return GlassRobot.convertFromIntArgb(intbuf.get((int) (y * bwidth) + (int) x));
 191             } else {
 192                 throw new RuntimeException("Unknown bit depth: " + byteDepth);
 193             }
 194         }
 195     }
 196 
 197     @Override
 198     public void getScreenCapture(int x, int y, int width, int height, int[] data, boolean scaleToFit) {
 199         Application.checkEventThread();
 200         NativeScreen screen = NativePlatformFactory.getNativePlatform().getScreen();
 201         final int scrWidth = screen.getWidth();
 202         final int scrHeight = screen.getHeight();
 203 
 204         synchronized (NativeScreen.framebufferSwapLock) {
 205             IntBuffer buffer = screen.getScreenCapture().asIntBuffer();
 206 
 207             if (x == 0 && y == 0 && width == scrWidth && height == scrHeight) {
 208                 // Easy case, the entire screen is being captured.
 209                 System.arraycopy(buffer.array(), 0, data, 0, buffer.array().length);
 210                 return;
 211             }
 212 
 213             int rowStop = Math.min(y + height, scrHeight);
 214             int colStop = Math.min(x + width, scrWidth);
 215             for (int row = y; row < rowStop; row++) {
 216                 for (int col = x; col < colStop; col++) {
 217                     data[row * scrWidth + col] = buffer.get(row * scrWidth + col);
 218                 }
 219             }
 220         }
 221     }
 222 }