aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNikita Tsarev <nikita.tsarev@jetbrains.com>2023-08-15 12:37:27 +0200
committerNikita Tsarev <nikita.tsarev@jetbrains.com>2023-08-15 12:37:27 +0200
commit77bccaf640d47710e14f52d9aaba010f7b922dc3 (patch)
tree45f24304f7f8f4ed97f3021f0c92fd8114182fa2
parent27bb9662b2d76535c55bea54e0d09fa0d13e718d (diff)
downloadJetBrainsRuntime-77bccaf640d47710e14f52d9aaba010f7b922dc3.tar.gz
JBR-5676: Support emulating input events in Wakefield
-rwxr-xr-xjb/generate-wakefield.sh6
-rw-r--r--src/java.desktop/share/native/libwakefield/protocol/wakefield.xml31
-rw-r--r--src/java.desktop/share/native/libwakefield/src/wakefield.c118
-rw-r--r--src/java.desktop/unix/classes/sun/awt/wl/WLRobotPeer.java40
-rw-r--r--src/java.desktop/unix/native/libawt_wlawt/WLRobotPeer.c227
-rw-r--r--src/java.desktop/unix/native/libawt_wlawt/wakefield-client-protocol.c20
-rw-r--r--src/java.desktop/unix/native/libawt_wlawt/wakefield-client-protocol.h94
-rw-r--r--test/jdk/java/awt/wakefield/RobotKeyboard.java288
-rw-r--r--test/jdk/java/awt/wakefield/ScreenCapture.java4
-rw-r--r--test/jdk/java/awt/wakefield/WakefieldTestDriver.java53
10 files changed, 835 insertions, 46 deletions
diff --git a/jb/generate-wakefield.sh b/jb/generate-wakefield.sh
new file mode 100755
index 00000000000..256871cd487
--- /dev/null
+++ b/jb/generate-wakefield.sh
@@ -0,0 +1,6 @@
+#!/bin/bash
+
+set -ex
+
+wayland-scanner client-header src/java.desktop/share/native/libwakefield/protocol/wakefield.xml src/java.desktop/unix/native/libawt_wlawt/wakefield-client-protocol.h
+wayland-scanner private-code src/java.desktop/share/native/libwakefield/protocol/wakefield.xml src/java.desktop/unix/native/libawt_wlawt/wakefield-client-protocol.c
diff --git a/src/java.desktop/share/native/libwakefield/protocol/wakefield.xml b/src/java.desktop/share/native/libwakefield/protocol/wakefield.xml
index 560adb42f28..cc9f310028e 100644
--- a/src/java.desktop/share/native/libwakefield/protocol/wakefield.xml
+++ b/src/java.desktop/share/native/libwakefield/protocol/wakefield.xml
@@ -84,6 +84,37 @@
<arg name="error_code" type="uint" enum="error"/>
</event>
+ <request name="send_key">
+ <description summary="facilitates implementation of Robot.keyPress/Robot.keyRelease">
+ This requests an emulation of a key press by its Linux event key code.
+ </description>
+ <arg name="key" type="uint" />
+ <arg name="state" type="uint" />
+ </request>
+
+ <request name="send_cursor">
+ <description summary="facilitates implementation of Robot.mouseMove">
+ This requests an emulation of the mouse cursor being moved to the specified screen coordinates.
+ </description>
+ <arg name="x" type="int" />
+ <arg name="y" type="int" />
+ </request>
+
+ <request name="send_button">
+ <description summary="facilitates implementation of Robot.mousePress/Robot.mouseRelease">
+ This requests an emulation of a mouse button press by its Linux event code.
+ </description>
+ <arg name="button" type="uint" />
+ <arg name="state" type="uint" />
+ </request>
+
+ <request name="send_wheel">
+ <description summary="facilitates implementation of Robot.mouseWheel">
+ This requests an emulation of a rotation of a mouse scroll wheel.
+ </description>
+ <arg name="amount" type="int" />
+ </request>
+
<enum name="error">
<entry name="no_error" value="0" summary="error code 0 reserved for the absence of error"/>
<entry name="invalid_coordinates" value="1" summary="supplied absolute coordinates point
diff --git a/src/java.desktop/share/native/libwakefield/src/wakefield.c b/src/java.desktop/share/native/libwakefield/src/wakefield.c
index a3da09a5375..1714535dbf4 100644
--- a/src/java.desktop/share/native/libwakefield/src/wakefield.c
+++ b/src/java.desktop/share/native/libwakefield/src/wakefield.c
@@ -44,6 +44,37 @@ struct wakefield {
struct weston_log_scope *log;
};
+#define DEFAULT_AXIS_STEP_DISTANCE 10
+
+// These functions are part of Weston's private backend API (libweston/backend.h)
+void
+notify_axis(struct weston_seat *seat, const struct timespec *time,
+ struct weston_pointer_axis_event *event);
+
+void
+notify_axis_source(struct weston_seat *seat, uint32_t source);
+
+void
+notify_button(struct weston_seat *seat, const struct timespec *time,
+ int32_t button, enum wl_pointer_button_state state);
+
+void
+notify_key(struct weston_seat *seat, const struct timespec *time, uint32_t key,
+ enum wl_keyboard_key_state state,
+ enum weston_key_state_update update_state);
+
+void
+notify_motion(struct weston_seat *seat, const struct timespec *time,
+ struct weston_pointer_motion_event *event);
+
+void
+notify_motion_absolute(struct weston_seat *seat, const struct timespec *time,
+ double x, double y);
+
+void
+notify_pointer_frame(struct weston_seat *seat);
+
+
static struct weston_output*
get_output_for_point(struct wakefield* wakefield, int32_t x, int32_t y)
{
@@ -482,11 +513,96 @@ wakefield_capture_create(struct wl_client *client,
wakefield_send_capture_ready(resource, buffer_resource, WAKEFIELD_ERROR_NO_ERROR);
}
+static void
+wakefield_send_key(struct wl_client *client,
+ struct wl_resource *resource,
+ uint32_t key,
+ uint32_t state)
+{
+ struct wakefield *wakefield = wl_resource_get_user_data(resource);
+ struct weston_compositor *compositor = wakefield->compositor;
+
+ struct timespec time;
+ weston_compositor_get_time(&time);
+
+ struct weston_seat *seat;
+ wl_list_for_each(seat, &compositor->seat_list, link) {
+ notify_key(seat, &time, key,
+ state ? WL_KEYBOARD_KEY_STATE_PRESSED : WL_KEYBOARD_KEY_STATE_RELEASED,
+ STATE_UPDATE_AUTOMATIC);
+
+ }
+}
+
+static void wakefield_send_cursor(struct wl_client* client,
+ struct wl_resource* resource,
+ int32_t x, int32_t y)
+{
+ struct wakefield *wakefield = wl_resource_get_user_data(resource);
+ struct weston_compositor *compositor = wakefield->compositor;
+
+ struct timespec time;
+ weston_compositor_get_time(&time);
+
+ struct weston_seat *seat;
+ wl_list_for_each(seat, &compositor->seat_list, link) {
+ notify_motion_absolute(seat, &time, (double)x, (double)y);
+ notify_pointer_frame(seat);
+ }
+}
+
+static void wakefield_send_button(struct wl_client* client,
+ struct wl_resource* resource,
+ uint32_t button,
+ uint32_t state)
+{
+ struct wakefield *wakefield = wl_resource_get_user_data(resource);
+ struct weston_compositor *compositor = wakefield->compositor;
+
+ struct timespec time;
+ weston_compositor_get_time(&time);
+
+ struct weston_seat *seat;
+ wl_list_for_each(seat, &compositor->seat_list, link) {
+ notify_button(seat, &time, (int32_t)button,
+ state ? WL_POINTER_BUTTON_STATE_PRESSED : WL_POINTER_BUTTON_STATE_RELEASED);
+ notify_pointer_frame(seat);
+ }
+}
+
+static void wakefield_send_wheel(struct wl_client* client,
+ struct wl_resource* resource,
+ int32_t amount)
+{
+ struct wakefield *wakefield = wl_resource_get_user_data(resource);
+ struct weston_compositor *compositor = wakefield->compositor;
+
+ struct timespec time;
+ weston_compositor_get_time(&time);
+
+ struct weston_pointer_axis_event event = {
+ .axis = WL_POINTER_AXIS_VERTICAL_SCROLL,
+ .value = DEFAULT_AXIS_STEP_DISTANCE * amount,
+ .has_discrete = true,
+ .discrete = amount
+ };
+
+ struct weston_seat *seat;
+ wl_list_for_each(seat, &compositor->seat_list, link) {
+ notify_axis(seat, &time, &event);
+ notify_pointer_frame(seat);
+ }
+}
+
static const struct wakefield_interface wakefield_implementation = {
.get_surface_location = wakefield_get_surface_location,
.move_surface = wakefield_move_surface,
.get_pixel_color = wakefield_get_pixel_color,
- .capture_create = wakefield_capture_create
+ .capture_create = wakefield_capture_create,
+ .send_key = wakefield_send_key,
+ .send_cursor = wakefield_send_cursor,
+ .send_button = wakefield_send_button,
+ .send_wheel = wakefield_send_wheel,
};
static void
diff --git a/src/java.desktop/unix/classes/sun/awt/wl/WLRobotPeer.java b/src/java.desktop/unix/classes/sun/awt/wl/WLRobotPeer.java
index 47f0c8ec2c8..9e1f5bd85be 100644
--- a/src/java.desktop/unix/classes/sun/awt/wl/WLRobotPeer.java
+++ b/src/java.desktop/unix/classes/sun/awt/wl/WLRobotPeer.java
@@ -42,32 +42,56 @@ public class WLRobotPeer implements RobotPeer {
@Override
public void mouseMove(int x, int y) {
- throw new UnsupportedOperationException("Not implemented: WLRobotPeer.mouseMove()");
+ checkExtensionPresent();
+
+ synchronized (WLRobotPeer.class) {
+ mouseMoveImpl(x, y);
+ }
}
@Override
public void mousePress(int buttons) {
- throw new UnsupportedOperationException("Not implemented: WLRobotPeer.mousePress()");
+ checkExtensionPresent();
+
+ synchronized (WLRobotPeer.class) {
+ sendMouseButtonImpl(buttons, true);
+ }
}
@Override
public void mouseRelease(int buttons) {
- throw new UnsupportedOperationException("Not implemented: WLRobotPeer.mouseRelease()");
+ checkExtensionPresent();
+
+ synchronized (WLRobotPeer.class) {
+ sendMouseButtonImpl(buttons, false);
+ }
}
@Override
public void mouseWheel(int wheelAmt) {
- throw new UnsupportedOperationException("Not implemented: WLRobotPeer.mouseWheel()");
+ checkExtensionPresent();
+
+ synchronized (WLRobotPeer.class) {
+ mouseWheelImpl(wheelAmt);
+ }
}
@Override
public void keyPress(int keycode) {
- throw new UnsupportedOperationException("Not implemented: WLRobotPeer.keyPress()");
+ checkExtensionPresent();
+
+ synchronized (WLRobotPeer.class) {
+ sendJavaKeyImpl(keycode, true);
+ }
}
@Override
public void keyRelease(int keycode) {
- throw new UnsupportedOperationException("Not implemented: WLRobotPeer.keyRelease()");
+ checkExtensionPresent();
+
+ synchronized (WLRobotPeer.class) {
+ sendJavaKeyImpl(keycode, false);
+ }
}
@Override
@@ -139,4 +163,8 @@ public class WLRobotPeer implements RobotPeer {
private static native int[] getRGBPixelsImpl(int x, int y, int width, int height);
private static native Point getLocationOfWLSurfaceImpl(long wlSurfacePtr);
private static native void setLocationOfWLSurfaceImpl(long wlSurfacePtr, int x, int y);
+ private static native void sendJavaKeyImpl(int javaKeyCode, boolean pressed);
+ private static native void mouseMoveImpl(int x, int y);
+ private static native void sendMouseButtonImpl(int buttons, boolean pressed);
+ private static native void mouseWheelImpl(int amount);
}
diff --git a/src/java.desktop/unix/native/libawt_wlawt/WLRobotPeer.c b/src/java.desktop/unix/native/libawt_wlawt/WLRobotPeer.c
index 10268d6bda6..817e69cdcf3 100644
--- a/src/java.desktop/unix/native/libawt_wlawt/WLRobotPeer.c
+++ b/src/java.desktop/unix/native/libawt_wlawt/WLRobotPeer.c
@@ -31,6 +31,8 @@
#include <Trace.h>
#include <jni_util.h>
+#include <java_awt_event_KeyEvent.h>
+#include <java_awt_event_InputEvent.h>
#include "sun_awt_wl_WLRobotPeer.h"
#include "WLToolkit.h"
@@ -116,6 +118,158 @@ init_mutex_and_cond(JNIEnv *env, pthread_mutex_t *mutex, pthread_cond_t *cond)
static void
handle_wakefield_error(JNIEnv *env, uint32_t error_code);
+
+struct wayland_keycode_map_item {
+ int java_key_code;
+ int wayland_key_code;
+};
+
+// Key codes correspond to the Linux event codes:
+// https://github.com/torvalds/linux/blob/master/include/uapi/linux/input-event-codes.h
+static struct wayland_keycode_map_item wayland_keycode_map[] = {
+ { java_awt_event_KeyEvent_VK_ESCAPE, 1 },
+ { java_awt_event_KeyEvent_VK_1, 2 },
+ { java_awt_event_KeyEvent_VK_2, 3 },
+ { java_awt_event_KeyEvent_VK_3, 4 },
+ { java_awt_event_KeyEvent_VK_4, 5 },
+ { java_awt_event_KeyEvent_VK_5, 6 },
+ { java_awt_event_KeyEvent_VK_6, 7 },
+ { java_awt_event_KeyEvent_VK_7, 8 },
+ { java_awt_event_KeyEvent_VK_8, 9 },
+ { java_awt_event_KeyEvent_VK_9, 10 },
+ { java_awt_event_KeyEvent_VK_0, 11 },
+ { java_awt_event_KeyEvent_VK_MINUS, 12 },
+ { java_awt_event_KeyEvent_VK_EQUALS, 13 },
+ { java_awt_event_KeyEvent_VK_BACK_SPACE, 14 },
+ { java_awt_event_KeyEvent_VK_TAB, 15 },
+ { java_awt_event_KeyEvent_VK_Q, 16 },
+ { java_awt_event_KeyEvent_VK_W, 17 },
+ { java_awt_event_KeyEvent_VK_E, 18 },
+ { java_awt_event_KeyEvent_VK_R, 19 },
+ { java_awt_event_KeyEvent_VK_T, 20 },
+ { java_awt_event_KeyEvent_VK_Y, 21 },
+ { java_awt_event_KeyEvent_VK_U, 22 },
+ { java_awt_event_KeyEvent_VK_I, 23 },
+ { java_awt_event_KeyEvent_VK_O, 24 },
+ { java_awt_event_KeyEvent_VK_P, 25 },
+ { java_awt_event_KeyEvent_VK_OPEN_BRACKET, 26 },
+ { java_awt_event_KeyEvent_VK_CLOSE_BRACKET, 27 },
+ { java_awt_event_KeyEvent_VK_ENTER, 28 },
+ { java_awt_event_KeyEvent_VK_CONTROL, 29 },
+ { java_awt_event_KeyEvent_VK_A, 30 },
+ { java_awt_event_KeyEvent_VK_S, 31 },
+ { java_awt_event_KeyEvent_VK_D, 32 },
+ { java_awt_event_KeyEvent_VK_F, 33 },
+ { java_awt_event_KeyEvent_VK_G, 34 },
+ { java_awt_event_KeyEvent_VK_H, 35 },
+ { java_awt_event_KeyEvent_VK_J, 36 },
+ { java_awt_event_KeyEvent_VK_K, 37 },
+ { java_awt_event_KeyEvent_VK_L, 38 },
+ { java_awt_event_KeyEvent_VK_SEMICOLON, 39 },
+ { java_awt_event_KeyEvent_VK_QUOTE, 40 },
+ { java_awt_event_KeyEvent_VK_BACK_QUOTE, 41 },
+ { java_awt_event_KeyEvent_VK_SHIFT, 42 },
+ { java_awt_event_KeyEvent_VK_BACK_SLASH, 43 },
+ { java_awt_event_KeyEvent_VK_Z, 44 },
+ { java_awt_event_KeyEvent_VK_X, 45 },
+ { java_awt_event_KeyEvent_VK_C, 46 },
+ { java_awt_event_KeyEvent_VK_V, 47 },
+ { java_awt_event_KeyEvent_VK_B, 48 },
+ { java_awt_event_KeyEvent_VK_N, 49 },
+ { java_awt_event_KeyEvent_VK_M, 50 },
+ { java_awt_event_KeyEvent_VK_COMMA, 51 },
+ { java_awt_event_KeyEvent_VK_PERIOD, 52 },
+ { java_awt_event_KeyEvent_VK_SLASH, 53 },
+ { java_awt_event_KeyEvent_VK_MULTIPLY, 55 },
+ { java_awt_event_KeyEvent_VK_ALT, 56 },
+ { java_awt_event_KeyEvent_VK_SPACE, 57 },
+ { java_awt_event_KeyEvent_VK_CAPS_LOCK, 58 },
+ { java_awt_event_KeyEvent_VK_F1, 59 },
+ { java_awt_event_KeyEvent_VK_F2, 60 },
+ { java_awt_event_KeyEvent_VK_F3, 61 },
+ { java_awt_event_KeyEvent_VK_F4, 62 },
+ { java_awt_event_KeyEvent_VK_F5, 63 },
+ { java_awt_event_KeyEvent_VK_F6, 64 },
+ { java_awt_event_KeyEvent_VK_F7, 65 },
+ { java_awt_event_KeyEvent_VK_F8, 66 },
+ { java_awt_event_KeyEvent_VK_F9, 67 },
+ { java_awt_event_KeyEvent_VK_F10, 68 },
+ { java_awt_event_KeyEvent_VK_NUM_LOCK, 69 },
+ { java_awt_event_KeyEvent_VK_SCROLL_LOCK, 70 },
+ { java_awt_event_KeyEvent_VK_NUMPAD7, 71 },
+ { java_awt_event_KeyEvent_VK_KP_UP, 72 },
+ { java_awt_event_KeyEvent_VK_NUMPAD8, 72 },
+ { java_awt_event_KeyEvent_VK_NUMPAD9, 73 },
+ { java_awt_event_KeyEvent_VK_SUBTRACT, 74 },
+ { java_awt_event_KeyEvent_VK_KP_LEFT, 75 },
+ { java_awt_event_KeyEvent_VK_NUMPAD4, 75 },
+ { java_awt_event_KeyEvent_VK_NUMPAD5, 76 },
+ { java_awt_event_KeyEvent_VK_KP_RIGHT, 77 },
+ { java_awt_event_KeyEvent_VK_NUMPAD6, 77 },
+ { java_awt_event_KeyEvent_VK_ADD, 78 },
+ { java_awt_event_KeyEvent_VK_NUMPAD1, 79 },
+ { java_awt_event_KeyEvent_VK_KP_DOWN, 80 },
+ { java_awt_event_KeyEvent_VK_NUMPAD2, 80 },
+ { java_awt_event_KeyEvent_VK_NUMPAD3, 81 },
+ { java_awt_event_KeyEvent_VK_NUMPAD0, 82 },
+ { java_awt_event_KeyEvent_VK_DECIMAL, 83 },
+ { java_awt_event_KeyEvent_VK_LESS, 86 },
+ { java_awt_event_KeyEvent_VK_F11, 87 },
+ { java_awt_event_KeyEvent_VK_F12, 88 },
+ { java_awt_event_KeyEvent_VK_KATAKANA, 90 },
+ { java_awt_event_KeyEvent_VK_HIRAGANA, 91 },
+ { java_awt_event_KeyEvent_VK_INPUT_METHOD_ON_OFF, 92 },
+ { java_awt_event_KeyEvent_VK_NONCONVERT, 94 },
+ { java_awt_event_KeyEvent_VK_DIVIDE, 98 },
+ { java_awt_event_KeyEvent_VK_PRINTSCREEN, 99 },
+ { java_awt_event_KeyEvent_VK_ALT_GRAPH, 100 },
+ { java_awt_event_KeyEvent_VK_HOME, 102 },
+ { java_awt_event_KeyEvent_VK_UP, 103 },
+ { java_awt_event_KeyEvent_VK_PAGE_UP, 104 },
+ { java_awt_event_KeyEvent_VK_LEFT, 105 },
+ { java_awt_event_KeyEvent_VK_RIGHT, 106 },
+ { java_awt_event_KeyEvent_VK_END, 107 },
+ { java_awt_event_KeyEvent_VK_DOWN, 108 },
+ { java_awt_event_KeyEvent_VK_PAGE_DOWN, 109 },
+ { java_awt_event_KeyEvent_VK_INSERT, 110 },
+ { java_awt_event_KeyEvent_VK_DELETE, 111 },
+ { java_awt_event_KeyEvent_VK_PAUSE, 119 },
+ { java_awt_event_KeyEvent_VK_DECIMAL, 121 },
+ { java_awt_event_KeyEvent_VK_META, 125 },
+ { java_awt_event_KeyEvent_VK_WINDOWS, 125 },
+ { java_awt_event_KeyEvent_VK_STOP, 128 },
+ { java_awt_event_KeyEvent_VK_AGAIN, 129 },
+ { java_awt_event_KeyEvent_VK_UNDO, 131 },
+ { java_awt_event_KeyEvent_VK_FIND, 136 },
+ { java_awt_event_KeyEvent_VK_HELP, 138 },
+ { java_awt_event_KeyEvent_VK_LEFT_PARENTHESIS, 179 },
+ { java_awt_event_KeyEvent_VK_RIGHT_PARENTHESIS, 180 },
+ { java_awt_event_KeyEvent_VK_F13, 183 },
+ { java_awt_event_KeyEvent_VK_F14, 184 },
+ { java_awt_event_KeyEvent_VK_F15, 185 },
+ { java_awt_event_KeyEvent_VK_F16, 186 },
+ { java_awt_event_KeyEvent_VK_F17, 187 },
+ { java_awt_event_KeyEvent_VK_F18, 188 },
+ { java_awt_event_KeyEvent_VK_F19, 189 },
+ { java_awt_event_KeyEvent_VK_F20, 190 },
+ { java_awt_event_KeyEvent_VK_F21, 191 },
+ { java_awt_event_KeyEvent_VK_F22, 192 },
+ { java_awt_event_KeyEvent_VK_F23, 193 },
+ { java_awt_event_KeyEvent_VK_F24, 194 },
+ { java_awt_event_KeyEvent_VK_UNDEFINED, -1 }
+};
+
+struct wayland_button_map_item {
+ int java_button_mask;
+ int wayland_button_code;
+};
+
+static struct wayland_button_map_item wayland_button_map[] = {
+ { java_awt_event_InputEvent_BUTTON1_DOWN_MASK | java_awt_event_InputEvent_BUTTON1_MASK, 0x110 },
+ { java_awt_event_InputEvent_BUTTON2_DOWN_MASK | java_awt_event_InputEvent_BUTTON2_MASK, 0x112 },
+ { java_awt_event_InputEvent_BUTTON3_DOWN_MASK | java_awt_event_InputEvent_BUTTON3_MASK, 0x111 },
+ { -1, -1 },
+};
#endif
static jclass pointClass; // java.awt.Point
@@ -298,6 +452,79 @@ Java_sun_awt_wl_WLRobotPeer_getRGBPixelsImpl
#endif
}
+JNIEXPORT void JNICALL
+Java_sun_awt_wl_WLRobotPeer_sendJavaKeyImpl
+ (JNIEnv *env, jclass clazz, jint javaKeyCode, jboolean pressed)
+{
+#ifdef WAKEFIELD_ROBOT
+ if (!wakefield) {
+ JNU_ThrowByName(env, "java/awt/AWTError", "no 'wakefield' protocol extension");
+ return;
+ }
+
+ uint32_t key = 0;
+
+ for (struct wayland_keycode_map_item* item = wayland_keycode_map; item->wayland_key_code != -1; ++item) {
+ if (item->java_key_code == javaKeyCode) {
+ key = item->wayland_key_code;
+ break;
+ }
+ }
+
+ if (!key) {
+ return;
+ }
+
+ wakefield_send_key(wakefield, key, pressed ? 1 : 0);
+#endif
+}
+
+JNIEXPORT void JNICALL
+Java_sun_awt_wl_WLRobotPeer_mouseMoveImpl
+ (JNIEnv *env, jclass clazz, jint x, jint y)
+{
+#ifdef WAKEFIELD_ROBOT
+ if (!wakefield) {
+ JNU_ThrowByName(env, "java/awt/AWTError", "no 'wakefield' protocol extension");
+ return;
+ }
+
+ wakefield_send_cursor(wakefield, x, y);
+#endif
+}
+
+JNIEXPORT void JNICALL
+Java_sun_awt_wl_WLRobotPeer_sendMouseButtonImpl
+ (JNIEnv *env, jclass clazz, jint buttons, jboolean pressed)
+{
+#ifdef WAKEFIELD_ROBOT
+ if (!wakefield) {
+ JNU_ThrowByName(env, "java/awt/AWTError", "no 'wakefield' protocol extension");
+ return;
+ }
+
+ for (struct wayland_button_map_item* item = wayland_button_map; item->wayland_button_code != -1; ++item) {
+ if (item->java_button_mask & buttons) {
+ wakefield_send_button(wakefield, item->wayland_button_code, pressed ? 1 : 0);
+ }
+ }
+#endif
+}
+
+JNIEXPORT void JNICALL
+Java_sun_awt_wl_WLRobotPeer_mouseWheelImpl
+ (JNIEnv *env, jclass clazz, jint amount)
+{
+#ifdef WAKEFIELD_ROBOT
+ if (!wakefield) {
+ JNU_ThrowByName(env, "java/awt/AWTError", "no 'wakefield' protocol extension");
+ return;
+ }
+
+ wakefield_send_wheel(wakefield, amount);
+#endif
+}
+
#ifdef WAKEFIELD_ROBOT
static void wakefield_surface_location(void *data, struct wakefield *wakefield,
diff --git a/src/java.desktop/unix/native/libawt_wlawt/wakefield-client-protocol.c b/src/java.desktop/unix/native/libawt_wlawt/wakefield-client-protocol.c
index a275fbaf790..87dc8808ac6 100644
--- a/src/java.desktop/unix/native/libawt_wlawt/wakefield-client-protocol.c
+++ b/src/java.desktop/unix/native/libawt_wlawt/wakefield-client-protocol.c
@@ -1,4 +1,4 @@
-/* Generated by wayland-scanner 1.19.0 */
+/* Generated by wayland-scanner 1.21.0 */
/*
* Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved.
@@ -28,6 +28,16 @@
#include <stdint.h>
#include "wayland-util.h"
+#ifndef __has_attribute
+# define __has_attribute(x) 0 /* Compatibility with non-clang compilers. */
+#endif
+
+#if (__has_attribute(visibility) || defined(__GNUC__) && __GNUC__ >= 4)
+#define WL_PRIVATE __attribute__ ((visibility("hidden")))
+#else
+#define WL_PRIVATE
+#endif
+
extern const struct wl_interface wl_buffer_interface;
extern const struct wl_interface wl_surface_interface;
@@ -56,6 +66,10 @@ static const struct wl_message wakefield_requests[] = {
{ "move_surface", "oii", wakefield_types + 4 },
{ "get_surface_location", "o", wakefield_types + 7 },
{ "get_pixel_color", "ii", wakefield_types + 0 },
+ { "send_key", "uu", wakefield_types + 0 },
+ { "send_cursor", "ii", wakefield_types + 0 },
+ { "send_button", "uu", wakefield_types + 0 },
+ { "send_wheel", "i", wakefield_types + 0 },
{ "capture_create", "oii", wakefield_types + 8 },
};
@@ -65,9 +79,9 @@ static const struct wl_message wakefield_events[] = {
{ "capture_ready", "ou", wakefield_types + 15 },
};
-WL_EXPORT const struct wl_interface wakefield_interface = {
+WL_PRIVATE const struct wl_interface wakefield_interface = {
"wakefield", 1,
- 5, wakefield_requests,
+ 9, wakefield_requests,
3, wakefield_events,
};
diff --git a/src/java.desktop/unix/native/libawt_wlawt/wakefield-client-protocol.h b/src/java.desktop/unix/native/libawt_wlawt/wakefield-client-protocol.h
index 9e45c618594..3dc9714ad82 100644
--- a/src/java.desktop/unix/native/libawt_wlawt/wakefield-client-protocol.h
+++ b/src/java.desktop/unix/native/libawt_wlawt/wakefield-client-protocol.h
@@ -1,4 +1,4 @@
-/* Generated by wayland-scanner 1.19.0 */
+/* Generated by wayland-scanner 1.21.0 */
#ifndef WAKEFIELD_CLIENT_PROTOCOL_H
#define WAKEFIELD_CLIENT_PROTOCOL_H
@@ -142,7 +142,11 @@ wakefield_add_listener(struct wakefield *wakefield,
#define WAKEFIELD_MOVE_SURFACE 1
#define WAKEFIELD_GET_SURFACE_LOCATION 2
#define WAKEFIELD_GET_PIXEL_COLOR 3
-#define WAKEFIELD_CAPTURE_CREATE 4
+#define WAKEFIELD_SEND_KEY 4
+#define WAKEFIELD_SEND_CURSOR 5
+#define WAKEFIELD_SEND_BUTTON 6
+#define WAKEFIELD_SEND_WHEEL 7
+#define WAKEFIELD_CAPTURE_CREATE 8
/**
* @ingroup iface_wakefield
@@ -176,6 +180,22 @@ wakefield_add_listener(struct wakefield *wakefield,
/**
* @ingroup iface_wakefield
*/
+#define WAKEFIELD_SEND_KEY_SINCE_VERSION 1
+/**
+ * @ingroup iface_wakefield
+ */
+#define WAKEFIELD_SEND_CURSOR_SINCE_VERSION 1
+/**
+ * @ingroup iface_wakefield
+ */
+#define WAKEFIELD_SEND_BUTTON_SINCE_VERSION 1
+/**
+ * @ingroup iface_wakefield
+ */
+#define WAKEFIELD_SEND_WHEEL_SINCE_VERSION 1
+/**
+ * @ingroup iface_wakefield
+ */
#define WAKEFIELD_CAPTURE_CREATE_SINCE_VERSION 1
/** @ingroup iface_wakefield */
@@ -204,10 +224,8 @@ wakefield_get_version(struct wakefield *wakefield)
static inline void
wakefield_destroy(struct wakefield *wakefield)
{
- wl_proxy_marshal((struct wl_proxy *) wakefield,
- WAKEFIELD_DESTROY);
-
- wl_proxy_destroy((struct wl_proxy *) wakefield);
+ wl_proxy_marshal_flags((struct wl_proxy *) wakefield,
+ WAKEFIELD_DESTROY, NULL, wl_proxy_get_version((struct wl_proxy *) wakefield), WL_MARSHAL_FLAG_DESTROY);
}
/**
@@ -221,8 +239,8 @@ wakefield_destroy(struct wakefield *wakefield)
static inline void
wakefield_move_surface(struct wakefield *wakefield, struct wl_surface *surface, int32_t x, int32_t y)
{
- wl_proxy_marshal((struct wl_proxy *) wakefield,
- WAKEFIELD_MOVE_SURFACE, surface, x, y);
+ wl_proxy_marshal_flags((struct wl_proxy *) wakefield,
+ WAKEFIELD_MOVE_SURFACE, NULL, wl_proxy_get_version((struct wl_proxy *) wakefield), 0, surface, x, y);
}
/**
@@ -233,8 +251,8 @@ wakefield_move_surface(struct wakefield *wakefield, struct wl_surface *surface,
static inline void
wakefield_get_surface_location(struct wakefield *wakefield, struct wl_surface *surface)
{
- wl_proxy_marshal((struct wl_proxy *) wakefield,
- WAKEFIELD_GET_SURFACE_LOCATION, surface);
+ wl_proxy_marshal_flags((struct wl_proxy *) wakefield,
+ WAKEFIELD_GET_SURFACE_LOCATION, NULL, wl_proxy_get_version((struct wl_proxy *) wakefield), 0, surface);
}
/**
@@ -245,8 +263,56 @@ wakefield_get_surface_location(struct wakefield *wakefield, struct wl_surface *s
static inline void
wakefield_get_pixel_color(struct wakefield *wakefield, int32_t x, int32_t y)
{
- wl_proxy_marshal((struct wl_proxy *) wakefield,
- WAKEFIELD_GET_PIXEL_COLOR, x, y);
+ wl_proxy_marshal_flags((struct wl_proxy *) wakefield,
+ WAKEFIELD_GET_PIXEL_COLOR, NULL, wl_proxy_get_version((struct wl_proxy *) wakefield), 0, x, y);
+}
+
+/**
+ * @ingroup iface_wakefield
+ *
+ * This requests an emulation of a key press by its Linux event key code.
+ */
+static inline void
+wakefield_send_key(struct wakefield *wakefield, uint32_t key, uint32_t state)
+{
+ wl_proxy_marshal_flags((struct wl_proxy *) wakefield,
+ WAKEFIELD_SEND_KEY, NULL, wl_proxy_get_version((struct wl_proxy *) wakefield), 0, key, state);
+}
+
+/**
+ * @ingroup iface_wakefield
+ *
+ * This requests an emulation of the mouse cursor being moved to the specified screen coordinates.
+ */
+static inline void
+wakefield_send_cursor(struct wakefield *wakefield, int32_t x, int32_t y)
+{
+ wl_proxy_marshal_flags((struct wl_proxy *) wakefield,
+ WAKEFIELD_SEND_CURSOR, NULL, wl_proxy_get_version((struct wl_proxy *) wakefield), 0, x, y);
+}
+
+/**
+ * @ingroup iface_wakefield
+ *
+ * This requests an emulation of a mouse button press by its Linux event code.
+ */
+static inline void
+wakefield_send_button(struct wakefield *wakefield, uint32_t button, uint32_t state)
+{
+ wl_proxy_marshal_flags((struct wl_proxy *) wakefield,
+ WAKEFIELD_SEND_BUTTON, NULL, wl_proxy_get_version((struct wl_proxy *) wakefield), 0, button, state);
+}
+
+/**
+ * @ingroup iface_wakefield
+ *
+ * This requests an emulation of a rotation of a mouse scroll wheel.
+ */
+static inline void
+wakefield_send_wheel(struct wakefield *wakefield, int32_t amount)
+{
+ wl_proxy_marshal_flags((struct wl_proxy *) wakefield,
+ WAKEFIELD_SEND_WHEEL, NULL, wl_proxy_get_version((struct wl_proxy *) wakefield), 0, amount);
}
/**
@@ -255,8 +321,8 @@ wakefield_get_pixel_color(struct wakefield *wakefield, int32_t x, int32_t y)
static inline void
wakefield_capture_create(struct wakefield *wakefield, struct wl_buffer *buffer, int32_t x, int32_t y)
{
- wl_proxy_marshal((struct wl_proxy *) wakefield,
- WAKEFIELD_CAPTURE_CREATE, buffer, x, y);
+ wl_proxy_marshal_flags((struct wl_proxy *) wakefield,
+ WAKEFIELD_CAPTURE_CREATE, NULL, wl_proxy_get_version((struct wl_proxy *) wakefield), 0, buffer, x, y);
}
#ifdef __cplusplus
diff --git a/test/jdk/java/awt/wakefield/RobotKeyboard.java b/test/jdk/java/awt/wakefield/RobotKeyboard.java
new file mode 100644
index 00000000000..3af23e94d37
--- /dev/null
+++ b/test/jdk/java/awt/wakefield/RobotKeyboard.java
@@ -0,0 +1,288 @@
+/*
+ * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2023, JetBrains s.r.o.. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+import javax.swing.*;
+import java.awt.*;
+import java.awt.event.KeyAdapter;
+import java.awt.event.KeyEvent;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * @test
+ * @key headful
+ * @summary JBR-5676 Wayland: support generation of input events by AWT Robot in weston plugin
+ * @requires (os.family == "linux")
+ * @library /test/lib
+ * @build RobotKeyboard
+ * @run driver WakefieldTestDriver -timeout 60 RobotKeyboard
+ */
+
+public class RobotKeyboard {
+ private static String ordinaryKeyNames[] = {
+ "VK_0",
+ "VK_1",
+ "VK_2",
+ "VK_3",
+ "VK_4",
+ "VK_5",
+ "VK_6",
+ "VK_7",
+ "VK_8",
+ "VK_9",
+ "VK_A",
+ "VK_ADD",
+ "VK_AGAIN",
+ "VK_ALT",
+// TODO: WLToolkit doesn't differentiate VK_ALT and VK_ALT_GRAPH for now
+// "VK_ALT_GRAPH",
+ "VK_B",
+ "VK_BACK_QUOTE",
+ "VK_BACK_SLASH",
+ "VK_BACK_SPACE",
+ "VK_C",
+ "VK_CLOSE_BRACKET",
+ "VK_COMMA",
+ "VK_CONTROL",
+ "VK_D",
+ "VK_DECIMAL",
+ "VK_DECIMAL",
+ "VK_DELETE",
+ "VK_DIVIDE",
+ "VK_DOWN",
+ "VK_E",
+ "VK_END",
+ "VK_ENTER",
+ "VK_EQUALS",
+ "VK_ESCAPE",
+ "VK_F",
+ "VK_F1",
+ "VK_F2",
+ "VK_F3",
+ "VK_F4",
+ "VK_F5",
+ "VK_F6",
+ "VK_F7",
+ "VK_F8",
+ "VK_F9",
+ "VK_F10",
+ "VK_F11",
+ "VK_F12",
+// TODO: WLToolkit ignores F13..F24 due to the XKB issues presumably
+// "VK_F13",
+// "VK_F14",
+// "VK_F15",
+// "VK_F16",
+// "VK_F17",
+// "VK_F18",
+// "VK_F19",
+// "VK_F20",
+// "VK_F21",
+// "VK_F22",
+// "VK_F23",
+// "VK_F24",
+ "VK_FIND",
+ "VK_G",
+ "VK_H",
+ "VK_HELP",
+ "VK_HIRAGANA",
+ "VK_HOME",
+ "VK_I",
+ "VK_INPUT_METHOD_ON_OFF",
+ "VK_INSERT",
+ "VK_J",
+ "VK_K",
+ "VK_KATAKANA",
+ "VK_L",
+ "VK_LEFT",
+ "VK_LEFT_PARENTHESIS",
+ "VK_LESS",
+ "VK_M",
+// TODO: WLToolkit reports the Meta key as VK_WINDOWS
+// "VK_META",
+ "VK_MINUS",
+ "VK_MULTIPLY",
+ "VK_N",
+ "VK_NONCONVERT",
+ "VK_NUMPAD0",
+ "VK_NUMPAD1",
+ "VK_NUMPAD2",
+ "VK_NUMPAD3",
+ "VK_NUMPAD4",
+ "VK_NUMPAD5",
+ "VK_NUMPAD6",
+ "VK_NUMPAD7",
+ "VK_NUMPAD8",
+ "VK_NUMPAD9",
+ "VK_O",
+ "VK_OPEN_BRACKET",
+ "VK_P",
+ "VK_PAGE_DOWN",
+ "VK_PAGE_UP",
+ "VK_PAUSE",
+ "VK_PERIOD",
+ "VK_PRINTSCREEN",
+ "VK_Q",
+ "VK_QUOTE",
+ "VK_R",
+ "VK_RIGHT",
+ "VK_RIGHT_PARENTHESIS",
+ "VK_S",
+ "VK_SEMICOLON",
+ "VK_SHIFT",
+ "VK_SLASH",
+ "VK_SPACE",
+ "VK_STOP",
+ "VK_SUBTRACT",
+ "VK_T",
+ "VK_TAB",
+ "VK_U",
+ "VK_UNDO",
+ "VK_UP",
+ "VK_V",
+ "VK_W",
+ "VK_WINDOWS",
+ "VK_X",
+ "VK_Y",
+ "VK_Z",
+ };
+
+ private static String lockingKeyNames[] = {
+ "VK_CAPS_LOCK",
+ "VK_NUM_LOCK",
+ "VK_SCROLL_LOCK",
+ };
+
+ private static Robot robot;
+ private static JFrame frame;
+ private static JTextArea textArea;
+ private static final List<KeyEvent> events = new ArrayList<>();
+
+ public static void main(String[] args) throws Exception {
+ SwingUtilities.invokeAndWait(() -> {
+ frame = new JFrame("test");
+
+ textArea = new JTextArea("");
+ textArea.setEditable(false);
+ frame.add(new JScrollPane(textArea));
+ frame.setSize(500, 500);
+ frame.setVisible(true);
+
+ KeyboardFocusManager.getCurrentKeyboardFocusManager().addKeyEventDispatcher(
+ new KeyEventDispatcher() {
+ @Override
+ public boolean dispatchKeyEvent(KeyEvent e) {
+ if (e.getID() == KeyEvent.KEY_PRESSED || e.getID() == KeyEvent.KEY_RELEASED) {
+ events.add(e);
+ }
+ return false;
+ }
+ }
+ );
+ });
+
+ robot = new Robot();
+ robot.setAutoDelay(50);
+ robot.delay(500);
+
+ boolean ok = true;
+
+ for (String key : ordinaryKeyNames) {
+ ok &= processKey(key);
+ }
+
+ for (String key : lockingKeyNames) {
+ ok &= processKey(key);
+
+ // reset the locking state to the previous one
+ int keyCode = getKeyCodeByName(key);
+ robot.keyPress(keyCode);
+ robot.keyRelease(keyCode);
+ robot.waitForIdle();
+ }
+
+ System.err.println("===== TEST RESULT =====");
+ System.err.println(ok ? "TEST PASSED" : "TEST FAILED");
+ System.err.println("===== FULL LOG =====");
+ System.err.println(textArea.getText());
+
+ frame.dispose();
+
+ // Due to some reason that probably has something to do with the implementation
+ // of the test driver, it's necessary to manually call System.exit() here
+ System.exit(ok ? 0 : 1);
+ }
+
+ private static int getKeyCodeByName(String name) {
+ try {
+ return KeyEvent.class.getDeclaredField(name).getInt(KeyEvent.class);
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ private static void checkKey(String name) {
+ int keyCode = getKeyCodeByName(name);
+ events.clear();
+ textArea.grabFocus();
+ robot.waitForIdle();
+ robot.keyPress(keyCode);
+ robot.keyRelease(keyCode);
+ robot.waitForIdle();
+
+ if (events.size() != 2) {
+ throw new RuntimeException("Expected two events, got: " + events.size());
+ }
+
+ if (events.get(0).getID() != KeyEvent.KEY_PRESSED || events.get(1).getID() != KeyEvent.KEY_RELEASED) {
+ throw new RuntimeException("Expected one KEY_PRESSED and one KEY_RELEASED");
+ }
+
+ if (events.get(0).getKeyCode() != keyCode) {
+ throw new RuntimeException("KEY_PRESSED keyCode is " + events.get(0).getKeyCode() + ", expected " + keyCode);
+ }
+
+ if (events.get(1).getKeyCode() != keyCode) {
+ throw new RuntimeException("KEY_RELEASED keyCode is " + events.get(1).getKeyCode() + ", expected " + keyCode);
+ }
+ }
+
+ private static void log(String what) {
+ textArea.append(what);
+ textArea.setCaretPosition(textArea.getDocument().getLength());
+ System.err.print(what);
+ }
+
+ private static boolean processKey(String name) {
+ log(name + ": ");
+ try {
+ checkKey(name);
+ log("OK\n");
+ return true;
+ } catch (RuntimeException e) {
+ log(e.getMessage() + "\n");
+ return false;
+ }
+ }
+} \ No newline at end of file
diff --git a/test/jdk/java/awt/wakefield/ScreenCapture.java b/test/jdk/java/awt/wakefield/ScreenCapture.java
index 8194bd7dbe3..ae78dca159c 100644
--- a/test/jdk/java/awt/wakefield/ScreenCapture.java
+++ b/test/jdk/java/awt/wakefield/ScreenCapture.java
@@ -40,8 +40,8 @@ import java.io.IOException;
* @requires (os.family == "linux")
* @library /test/lib
* @build ScreenCapture
- * @run driver WakefieldTestDriver 1x1400x800 ScreenCapture
- * @run driver WakefieldTestDriver 2x830x800 ScreenCapture
+ * @run driver WakefieldTestDriver -resolution 1x1400x800 ScreenCapture
+ * @run driver WakefieldTestDriver -resolution 2x830x800 ScreenCapture
*/
public class ScreenCapture {
diff --git a/test/jdk/java/awt/wakefield/WakefieldTestDriver.java b/test/jdk/java/awt/wakefield/WakefieldTestDriver.java
index aa9e6676937..2d461660691 100644
--- a/test/jdk/java/awt/wakefield/WakefieldTestDriver.java
+++ b/test/jdk/java/awt/wakefield/WakefieldTestDriver.java
@@ -37,11 +37,11 @@ public class WakefieldTestDriver {
final static int DEFAULT_NUMBER_OF_SCREENS = 1;
final static int DEFAULT_SCREEN_WIDTH = 1280;
final static int DEFAULT_SCREEN_HEIGHT = 800;
- final static int TEST_TIMEOUT_SECONDS = 10;
+ static int testTimeoutSeconds = 10;
static void usage() {
System.out.println(
"""
- WakefieldTestDriver [NxWxH] ClassName [args]
+ WakefieldTestDriver [-resolution NxWxH] [-timeout SECONDS] ClassName [args]
where
N - number of Weston outputs (screens); defaults to 1
W - width of each screen in pixels; defaults to 1280
@@ -65,24 +65,37 @@ public class WakefieldTestDriver {
int nScreens = DEFAULT_NUMBER_OF_SCREENS;
int screenWidth = DEFAULT_SCREEN_WIDTH;
int screenHeight = DEFAULT_SCREEN_HEIGHT;
- final String firstArg = args[0];
- if (Character.isDigit(firstArg.charAt(0))) {
- try {
- final int firstXIndex = firstArg.indexOf("x", 0);
- final int secondXIndex = firstArg.indexOf("x", firstXIndex + 1);
- nScreens = Integer.valueOf(firstArg.substring(0, firstXIndex));
- screenWidth = Integer.valueOf(firstArg.substring(firstXIndex + 1, secondXIndex));
- screenHeight = Integer.valueOf(firstArg.substring(secondXIndex + 1, firstArg.length()));
-
- for (int i = 1; i < args.length; ++i) {
- jvmArgs.add(args[i]);
+
+ for (int i = 0; i < args.length; ++i) {
+ if (args[i].equals("-resolution") && i + 1 < args.length) {
+ final String arg = args[i + 1];
+ if (Character.isDigit(arg.charAt(0))) {
+ try {
+ final int firstXIndex = arg.indexOf("x", 0);
+ final int secondXIndex = arg.indexOf("x", firstXIndex + 1);
+ nScreens = Integer.valueOf(arg.substring(0, firstXIndex));
+ screenWidth = Integer.valueOf(arg.substring(firstXIndex + 1, secondXIndex));
+ screenHeight = Integer.valueOf(arg.substring(secondXIndex + 1, arg.length()));
+ } catch (IndexOutOfBoundsException | NumberFormatException ignored) {
+ usage();
+ throw new RuntimeException("Error parsing the first argument of the test driver");
+ }
}
- } catch (IndexOutOfBoundsException | NumberFormatException ignored) {
- usage();
- throw new RuntimeException("Error parsing the first argument of the test driver");
+ ++i;
+ continue;
+ }
+
+ if (args[i].equals("-timeout") && i + 1 < args.length) {
+ final String arg = args[i + 1];
+ testTimeoutSeconds = Integer.valueOf(arg);
+ ++i;
+ continue;
+ }
+
+ for (int j = i; j < args.length; ++j) {
+ jvmArgs.add(args[j]);
}
- } else {
- jvmArgs.addAll(Arrays.asList(args));
+ break;
}
final String socketName = SOCKET_NAME_PREFIX + ProcessHandle.current().pid();
@@ -95,13 +108,13 @@ public class WakefieldTestDriver {
final Process p = pb.start();
final OutputAnalyzer output = new OutputAnalyzer(p);
- final boolean exited = p.waitFor(TEST_TIMEOUT_SECONDS, TimeUnit.SECONDS);
+ final boolean exited = p.waitFor(testTimeoutSeconds, TimeUnit.SECONDS);
if (!exited) p.destroy();
System.out.println("Test finished. Output: [[[");
System.out.println(output.getOutput());
System.out.println("]]]");
if (!exited) {
- throw new RuntimeException("Test timed out after " + TEST_TIMEOUT_SECONDS + " seconds");
+ throw new RuntimeException("Test timed out after " + testTimeoutSeconds + " seconds");
}
if (exited && output.getExitValue() != 0) {