mirror of
https://github.com/JetBrains/JetBrainsRuntime.git
synced 2025-12-06 09:29:38 +01:00
Compare commits
8 Commits
jb21.0.6-b
...
nikita.tsa
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
bb83d4ab82 | ||
|
|
d757b1d05e | ||
|
|
7873f04375 | ||
|
|
21ccebc484 | ||
|
|
513d168fa3 | ||
|
|
2eaee2a445 | ||
|
|
0b3596aefa | ||
|
|
62e6c4c8d8 |
6
jb/generate-wakefield.sh
Executable file
6
jb/generate-wakefield.sh
Executable file
@@ -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
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -131,7 +131,7 @@ public class WLGraphicsEnvironment extends SunGraphicsEnvironment {
|
||||
}
|
||||
|
||||
// Skip notification during the initial configuration events
|
||||
if (EventQueue.isDispatchThread()) {
|
||||
if (WLToolkit.isInitialized()) {
|
||||
displayChanged();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -133,12 +133,15 @@ public class WLToolkit extends UNIXToolkit implements Runnable {
|
||||
private static final int MOUSE_BUTTONS_COUNT = 3;
|
||||
private static final int AWT_MULTICLICK_DEFAULT_TIME_MS = 500;
|
||||
|
||||
private static boolean initialized = false;
|
||||
|
||||
private static native void initIDs();
|
||||
|
||||
static {
|
||||
if (!GraphicsEnvironment.isHeadless()) {
|
||||
initIDs();
|
||||
}
|
||||
initialized = true;
|
||||
}
|
||||
|
||||
@SuppressWarnings("removal")
|
||||
@@ -1005,4 +1008,8 @@ public class WLToolkit extends UNIXToolkit implements Runnable {
|
||||
static void resetPointerInputState() {
|
||||
inputState = inputState.resetPointerState();
|
||||
}
|
||||
|
||||
static boolean isInitialized() {
|
||||
return initialized;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -927,26 +927,6 @@ wl_display_poll(struct wl_display *display, int events, int poll_timeout)
|
||||
return rc;
|
||||
}
|
||||
|
||||
static void
|
||||
dispatch_nondefault_queues(JNIEnv *env)
|
||||
{
|
||||
// The handlers of the events on these queues will be called from here, i.e. on
|
||||
// the 'AWT-Wayland' (toolkit) thread. The handlers must *not* execute any
|
||||
// arbitrary user code that can block.
|
||||
int rc = 0;
|
||||
|
||||
#ifdef WAKEFIELD_ROBOT
|
||||
if (robot_queue) {
|
||||
rc = wl_display_dispatch_queue_pending(wl_display, robot_queue);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (rc < 0) {
|
||||
JNU_ThrowByName(env, "java/awt/AWTError", "Wayland error during events processing");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
wl_flush_to_server(JNIEnv *env)
|
||||
{
|
||||
@@ -985,21 +965,31 @@ JNIEXPORT void JNICALL
|
||||
Java_sun_awt_wl_WLToolkit_dispatchNonDefaultQueuesImpl
|
||||
(JNIEnv *env, jobject obj)
|
||||
{
|
||||
int rc = 0;
|
||||
while (rc != -1) {
|
||||
#ifdef WAKEFIELD_ROBOT
|
||||
if (robot_queue) {
|
||||
rc = wl_display_dispatch_queue(wl_display, robot_queue);
|
||||
} else {
|
||||
if (!robot_queue) {
|
||||
return;
|
||||
}
|
||||
|
||||
int rc = 0;
|
||||
|
||||
while (rc >= 0) {
|
||||
// Dispatch pending events on the wakefield queue
|
||||
while (wl_display_prepare_read_queue(wl_display, robot_queue) != 0 && rc >= 0) {
|
||||
rc = wl_display_dispatch_queue_pending(wl_display, robot_queue);
|
||||
}
|
||||
if (rc < 0) {
|
||||
wl_display_cancel_read(wl_display);
|
||||
break;
|
||||
}
|
||||
#else
|
||||
break;
|
||||
#endif
|
||||
|
||||
// Wait for new events, wl_display_read_events is a synchronization point between all threads reading events.
|
||||
rc = wl_display_read_events(wl_display);
|
||||
}
|
||||
|
||||
// Simply return in case of any error; the actual error reporting (exception)
|
||||
// and/or shutdown will happen on the "main" toolkit thread AWT-Wayland,
|
||||
// see readEvents() below.
|
||||
#endif
|
||||
}
|
||||
|
||||
JNIEXPORT jint JNICALL
|
||||
|
||||
@@ -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,
|
||||
};
|
||||
|
||||
|
||||
@@ -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
|
||||
@@ -173,6 +177,22 @@ wakefield_add_listener(struct wakefield *wakefield,
|
||||
* @ingroup iface_wakefield
|
||||
*/
|
||||
#define WAKEFIELD_GET_PIXEL_COLOR_SINCE_VERSION 1
|
||||
/**
|
||||
* @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
|
||||
*/
|
||||
@@ -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
|
||||
|
||||
288
test/jdk/java/awt/wakefield/RobotKeyboard.java
Normal file
288
test/jdk/java/awt/wakefield/RobotKeyboard.java
Normal file
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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 {
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
} else {
|
||||
jvmArgs.addAll(Arrays.asList(args));
|
||||
|
||||
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]);
|
||||
}
|
||||
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) {
|
||||
|
||||
Reference in New Issue
Block a user