1 /* 2 * Copyright (c) 2011, 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 #include <X11/Xlib.h> 26 #include <X11/Xutil.h> 27 #include <X11/extensions/XTest.h> 28 #include <assert.h> 29 #include <stdlib.h> 30 #include <gdk/gdk.h> 31 #include <gdk/gdkx.h> 32 33 #include <com_sun_glass_ui_gtk_GtkRobot.h> 34 #include <com_sun_glass_events_MouseEvent.h> 35 #include "glass_general.h" 36 #include "glass_key.h" 37 38 39 static void checkXTest(JNIEnv* env) { 40 int32_t major_opcode, first_event, first_error; 41 int32_t event_basep, error_basep, majorp, minorp; 42 static int32_t isXTestAvailable; 43 static gboolean checkDone = FALSE; 44 if (!checkDone) { 45 /* check if XTest is available */ 46 isXTestAvailable = XQueryExtension(gdk_x11_get_default_xdisplay(), XTestExtensionName, &major_opcode, &first_event, &first_error); 47 if (isXTestAvailable) { 48 /* check if XTest version is OK */ 49 XTestQueryExtension(gdk_x11_get_default_xdisplay(), &event_basep, &error_basep, &majorp, &minorp); 50 if (majorp < 2 || (majorp == 2 && minorp < 2)) { 51 isXTestAvailable = False; 52 } else { 53 XTestGrabControl(gdk_x11_get_default_xdisplay(), True); 54 } 55 } 56 checkDone = TRUE; 57 } 58 if (!isXTestAvailable) { 59 jclass cls = env->FindClass("java/lang/UnsupportedOperationException"); 60 if (env->ExceptionCheck()) return; 61 env->ThrowNew(cls, "Glass Robot needs XTest extension to work"); 62 } 63 } 64 65 static void keyButton(jint code, gboolean press) 66 { 67 Display *xdisplay = gdk_x11_get_default_xdisplay(); 68 gint gdk_keyval = find_gdk_keyval_for_glass_keycode(code); 69 GdkKeymapKey *keys; 70 gint n_keys; 71 if (gdk_keyval == -1) { 72 return; 73 } 74 gdk_keymap_get_entries_for_keyval(gdk_keymap_get_default(), 75 gdk_keyval, &keys, &n_keys); 76 if (n_keys < 1) { 77 return; 78 } 79 80 XTestFakeKeyEvent(xdisplay, 81 keys[0].keycode, 82 press ? True : False, 83 CurrentTime); 84 g_free(keys); 85 XSync(xdisplay, False); 86 } 87 88 extern "C" { 89 90 /* 91 * Class: com_sun_glass_ui_gtk_GtkRobot 92 * Method: _keyPress 93 * Signature: (I)V 94 */ 95 JNIEXPORT void JNICALL Java_com_sun_glass_ui_gtk_GtkRobot__1keyPress 96 (JNIEnv *env, jobject obj, jint code) 97 { 98 (void)obj; 99 100 checkXTest(env); 101 keyButton(code, TRUE); 102 } 103 104 /* 105 * Class: com_sun_glass_ui_gtk_GtkRobot 106 * Method: _keyRelease 107 * Signature: (I)V 108 */ 109 JNIEXPORT void JNICALL Java_com_sun_glass_ui_gtk_GtkRobot__1keyRelease 110 (JNIEnv *env, jobject obj, jint code) 111 { 112 (void)obj; 113 114 checkXTest(env); 115 keyButton(code, FALSE); 116 } 117 118 /* 119 * Class: com_sun_glass_ui_gtk_GtkRobot 120 * Method: _mouseMove 121 * Signature: (II)V 122 */ 123 JNIEXPORT void JNICALL Java_com_sun_glass_ui_gtk_GtkRobot__1mouseMove 124 (JNIEnv *env, jobject obj, jint x, jint y) 125 { 126 (void)obj; 127 128 Display *xdisplay = gdk_x11_get_default_xdisplay(); 129 checkXTest(env); 130 XWarpPointer(xdisplay, 131 None, 132 XRootWindow(xdisplay,gdk_x11_get_default_screen()), 133 0, 0, 0, 0, x, y); 134 XSync(xdisplay, False); 135 } 136 137 static void mouseButtons(jint buttons, gboolean press) 138 { 139 Display *xdisplay = gdk_x11_get_default_xdisplay(); 140 if (buttons & com_sun_glass_ui_gtk_GtkRobot_MOUSE_LEFT_BTN) { 141 XTestFakeButtonEvent(xdisplay, 1, press, CurrentTime); 142 } 143 if (buttons & com_sun_glass_ui_gtk_GtkRobot_MOUSE_MIDDLE_BTN) { 144 XTestFakeButtonEvent(xdisplay, 2, press, CurrentTime); 145 } 146 if (buttons & com_sun_glass_ui_gtk_GtkRobot_MOUSE_RIGHT_BTN) { 147 XTestFakeButtonEvent(xdisplay, 3, press, CurrentTime); 148 } 149 150 XSync(xdisplay, False); 151 } 152 153 /* 154 * Class: com_sun_glass_ui_gtk_GtkRobot 155 * Method: _mousePress 156 * Signature: (I)V 157 */ 158 JNIEXPORT void JNICALL Java_com_sun_glass_ui_gtk_GtkRobot__1mousePress 159 (JNIEnv *env, jobject obj, jint buttons) 160 { 161 (void)obj; 162 163 checkXTest(env); 164 mouseButtons(buttons, TRUE); 165 } 166 167 /* 168 * Class: com_sun_glass_ui_gtk_GtkRobot 169 * Method: _mouseRelease 170 * Signature: (I)V 171 */ 172 JNIEXPORT void JNICALL Java_com_sun_glass_ui_gtk_GtkRobot__1mouseRelease 173 (JNIEnv *env, jobject obj, jint buttons) 174 { 175 (void)obj; 176 177 checkXTest(env); 178 mouseButtons(buttons, FALSE); 179 } 180 181 /* 182 * Class: com_sun_glass_ui_gtk_GtkRobot 183 * Method: _mouseWheel 184 * Signature: (I)V 185 */ 186 JNIEXPORT void JNICALL Java_com_sun_glass_ui_gtk_GtkRobot__1mouseWheel 187 (JNIEnv *env, jobject obj, jint amt) 188 { 189 (void)obj; 190 191 Display *xdisplay = gdk_x11_get_default_xdisplay(); 192 int repeat = abs(amt); 193 int button = amt < 0 ? 5 : 4; 194 int i; 195 196 checkXTest(env); 197 for (i = 0; i < repeat; i++) { 198 XTestFakeButtonEvent(xdisplay, button, True, CurrentTime); 199 XTestFakeButtonEvent(xdisplay, button, False, CurrentTime); 200 } 201 XSync(xdisplay, False); 202 } 203 204 /* 205 * Class: com_sun_glass_ui_gtk_GtkRobot 206 * Method: _getMouseX 207 * Signature: ()I 208 */ 209 JNIEXPORT jint JNICALL Java_com_sun_glass_ui_gtk_GtkRobot__1getMouseX 210 (JNIEnv *env, jobject obj) 211 { 212 (void)env; 213 (void)obj; 214 215 jint x; 216 glass_gdk_display_get_pointer(gdk_display_get_default(), &x, NULL); 217 return x; 218 } 219 220 /* 221 * Class: com_sun_glass_ui_gtk_GtkRobot 222 * Method: _getMouseY 223 * Signature: ()I 224 */ 225 JNIEXPORT jint JNICALL Java_com_sun_glass_ui_gtk_GtkRobot__1getMouseY 226 (JNIEnv *env, jobject obj) 227 { 228 (void)env; 229 (void)obj; 230 231 jint y; 232 glass_gdk_display_get_pointer(gdk_display_get_default(), NULL, &y); 233 return y; 234 } 235 236 /* 237 * Class: com_sun_glass_ui_gtk_GtkRobot 238 * Method: _getScreenCapture 239 * Signature: (IIII[I)V 240 */ 241 JNIEXPORT void JNICALL Java_com_sun_glass_ui_gtk_GtkRobot__1getScreenCapture 242 (JNIEnv * env, jobject obj, jint x, jint y, jint width, jint height, jintArray data) 243 { 244 (void)obj; 245 246 GdkPixbuf *screenshot, *tmp; 247 GdkWindow *root_window = gdk_get_default_root_window(); 248 249 tmp = glass_pixbuf_from_window(root_window, x, y, width, height); 250 screenshot = gdk_pixbuf_add_alpha(tmp, FALSE, 0, 0, 0); 251 g_object_unref(tmp); 252 253 jint *pixels = (jint *)convert_BGRA_to_RGBA((int*)gdk_pixbuf_get_pixels(screenshot), width * 4, height); 254 env->SetIntArrayRegion(data, 0, height * width, pixels); 255 g_free(pixels); 256 257 g_object_unref(screenshot); 258 } 259 260 } // extern "C"