Compare commits

...

8 Commits

Author SHA1 Message Date
Denis Konoplev
17021368ab Windows touch tests 2019-12-05 16:49:41 +03:00
Denis Konoplev
df91f20e24 Merge remote-tracking branch 'origin/ui-touch-test' into ui-touch-test 2019-12-04 18:33:21 +03:00
Denis Konoplev
5035f268e6 Unix touch tests 2019-12-04 18:32:07 +03:00
Denis Konoplev
5da58806e3 Touchscreen test with virtual device 2019-12-04 18:32:07 +03:00
Denis Konoplev
8db73eda00 Merge branch 'linux-ui-touch-test' of github.com:JetBrains/JetBrainsRuntime into ui-touch-test 2019-12-04 17:33:38 +03:00
Denis Konoplev
683ca75651 Unix touch tests 2019-12-04 17:33:12 +03:00
Denis Konoplev
c7c83bda83 Unix touch tests 2019-12-04 17:29:31 +03:00
Denis Konoplev
06b0dff9b0 Touchscreen test with virtual device 2019-11-20 18:55:20 +03:00
8 changed files with 810 additions and 0 deletions

View File

@@ -0,0 +1,38 @@
###Tips for compiling libraries and preparing env for test running
## Linux
prepare env for work with uinput: [group permissions](https://github.com/tuomasjjrasanen/python-uinput/issues/6#issuecomment-538710069)
```shell script
cd JetBrainsRuntime/test/jdk/jbu/native
# complile lib
gcc -shared -fPIC -I<path_to_jdk>/JetBrainsRuntime/build/linux-x86_64-normal-server-release/images/jdk/include/linux -I<path_to_jdk>/JetBrainsRuntime/build/linux-x86_64-normal-server-release/images/jdk/include touchscreen_device.c -o libtouchscreen_device.so
```
In IDEA run configurations set envvar to find libtouchscreen_device.so
```
LD_LIBRARY_PATH=<path_to_jdk>\JetBrainsRuntime\test\jdk\jbu\native
```
## Windows
prepare windows env: look for vcvarsall.bat [here](https://github.com/JetBrains/JetBrainsRuntime#windows)
```
cd JetBrainsRuntime\test\jdk\jbu\native
cl -I<path_to_jdk>\JetBrainsRuntime\build\windows-x86_64-normal-server-release\jdk\include\win32 -I<path_to_jdk>\JetBrainsRuntime\build\windows-x86_64-normal-server-release\jdk\include -MD -LD windows_touch_robot.c "<path_to_user32lib>\user32.lib" -Fewindows_touch_robot.dll
```
user32.lib is needed for WinUser.h (touch injection stuff)
In IDEA run configurations set envvar to find windows_touch_robot.dll
```
PATH="<path_to_jdk>\JetBrainsRuntime\test\jdk\jbu\native"
```
my paths are
```
user32: "C:\Program Files (x86)\Windows Kits\10\Lib\10.0.18362.0\um\x64\user32.lib"
path_to_jdk: "C:\Program_Files\cygwin64\home\Denis.Konoplev"
```

View File

@@ -0,0 +1,205 @@
#include <jni.h>
#include <errno.h>
#include <fcntl.h>
#include <linux/input.h>
#include <linux/types.h>
#include <linux/uinput.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/ioctl.h>
#include <sys/time.h>
#include <sys/types.h>
#include <unistd.h>
// TODO sort includes
// TODO add casts
typedef struct {
__u16 type;
__u16 code;
__s32 value;
} TEventData;
static int set_bit(int fd, unsigned long int request, unsigned long int bit) {
return ioctl(fd, request, bit);
}
static int touch_begin(int fd, int tracking_id, int x, int y) {
struct input_event ev;
const int cnt = 7;
TEventData eventData[7] = {{EV_ABS, ABS_MT_TRACKING_ID, tracking_id},
{EV_ABS, ABS_MT_POSITION_X, x},
{EV_ABS, ABS_MT_POSITION_Y, y},
{EV_KEY, BTN_TOUCH, 1},
{EV_ABS, ABS_X, x},
{EV_ABS, ABS_Y, y},
{EV_SYN, 0, 0}};
for (int i = 0; i < cnt; i++) {
memset(&ev, 0, sizeof(struct input_event));
ev.type = eventData[i].type;
ev.code = eventData[i].code;
ev.value = eventData[i].value;
if (write(fd, &ev, sizeof(struct input_event)) < 0) {
return -1;
}
}
return 0;
}
static int touch_update(int fd, int x, int y) {
struct input_event ev;
const int cnt = 5;
TEventData eventData[5] = {{EV_ABS, ABS_MT_POSITION_X, x},
{EV_ABS, ABS_MT_POSITION_Y, y},
{EV_ABS, ABS_X, x},
{EV_ABS, ABS_Y, y},
{EV_SYN, 0, 0}};
for (int i = 0; i < cnt; i++) {
memset(&ev, 0, sizeof(struct input_event));
ev.type = eventData[i].type;
ev.code = eventData[i].code;
ev.value = eventData[i].value;
if (write(fd, &ev, sizeof(struct input_event)) < 0) {
return -1;
}
}
return 0;
}
// todo consider different name in case of multitouch
static int touch_end(int fd) {
struct input_event ev;
const int cnt = 3;
TEventData eventData[3] = {
{EV_ABS, ABS_MT_TRACKING_ID, -1}, {EV_KEY, BTN_TOUCH, 0}, {EV_SYN, 0, 0}};
for (int i = 0; i < cnt; i++) {
memset(&ev, 0, sizeof(struct input_event));
ev.type = eventData[i].type;
ev.code = eventData[i].code;
ev.value = eventData[i].value;
if (write(fd, &ev, sizeof(struct input_event)) < 0) {
return -1;
}
}
return 0;
}
/*
* Class: quality_util_TouchScreenDevice
* Method: create
* Signature: ()I
*/
JNIEXPORT jint JNICALL Java_quality_util_UnixTouchScreenDevice_create(JNIEnv *env,
jobject o,
jint width,
jint height) {
int productId = 123;
const int FAKE_VENDOR_ID = 0x453;
const int MAX_FINGER_COUNT = 9;
const int MAX_TRACKING_ID = 65535;
int fd = open("/dev/uinput", O_WRONLY | O_NONBLOCK);
if (fd < 0) {
return -1;
}
int ret_code = 0;
ret_code = set_bit(fd, UI_SET_EVBIT, EV_SYN);
ret_code = set_bit(fd, UI_SET_EVBIT, EV_KEY);
ret_code = set_bit(fd, UI_SET_KEYBIT, BTN_TOUCH);
ret_code = set_bit(fd, UI_SET_EVBIT, EV_ABS);
ret_code = set_bit(fd, UI_SET_ABSBIT, ABS_X);
ret_code = set_bit(fd, UI_SET_ABSBIT, ABS_Y);
ret_code = set_bit(fd, UI_SET_ABSBIT, ABS_MT_SLOT);
ret_code = set_bit(fd, UI_SET_ABSBIT, ABS_MT_POSITION_X);
ret_code = set_bit(fd, UI_SET_ABSBIT, ABS_MT_POSITION_Y);
ret_code = set_bit(fd, UI_SET_ABSBIT, ABS_MT_TRACKING_ID);
ret_code = set_bit(fd, UI_SET_PROPBIT, INPUT_PROP_DIRECT);
if (ret_code < 0) {
return -1;
}
struct uinput_user_dev virtual_touch_device;
memset(&virtual_touch_device, 0, sizeof(virtual_touch_device));
snprintf(virtual_touch_device.name, UINPUT_MAX_NAME_SIZE,
"Virtual Touch Device - %#x", productId);
virtual_touch_device.id.bustype = BUS_VIRTUAL;
virtual_touch_device.id.vendor = FAKE_VENDOR_ID;
virtual_touch_device.id.product = productId;
virtual_touch_device.id.version = 1;
virtual_touch_device.absmin[ABS_X] = 0;
virtual_touch_device.absmax[ABS_X] = width;
virtual_touch_device.absmin[ABS_Y] = 0;
virtual_touch_device.absmax[ABS_Y] = height;
virtual_touch_device.absmin[ABS_MT_SLOT] = 0;
virtual_touch_device.absmax[ABS_MT_SLOT] = MAX_FINGER_COUNT;
virtual_touch_device.absmin[ABS_MT_POSITION_X] = 0;
virtual_touch_device.absmax[ABS_MT_POSITION_X] = width;
virtual_touch_device.absmin[ABS_MT_POSITION_Y] = 0;
virtual_touch_device.absmax[ABS_MT_POSITION_Y] = height;
virtual_touch_device.absmin[ABS_MT_TRACKING_ID] = 0;
virtual_touch_device.absmax[ABS_MT_TRACKING_ID] = MAX_TRACKING_ID;
ret_code = write(fd, &virtual_touch_device, sizeof(virtual_touch_device));
ret_code = ioctl(fd, UI_DEV_CREATE);
if (ret_code < 0) {
return -1;
}
return fd;
}
/*
* Class: quality_util_TouchScreenDevice
* Method: destroy
* Signature: (I)V
*/
JNIEXPORT jint JNICALL Java_quality_util_UnixTouchScreenDevice_destroy(JNIEnv *env,
jobject o,
jint fd) {
if (ioctl(fd, UI_DEV_DESTROY) < 0) {
return -1;
}
return close(fd);
}
/*
* Class: quality_util_TouchScreenDevice
* Method: clickImpl
* Signature: (IIII)V
*/
// todo return code with checked exception
JNIEXPORT jint JNICALL Java_quality_util_UnixTouchScreenDevice_clickImpl(
JNIEnv *env, jobject o, jint fd, jint trackingId, jint x, jint y) {
touch_begin(fd, trackingId, x, y);
touch_end(fd);
return 0;
}
/*
* Class: quality_util_TouchScreenDevice
* Method: moveImpl
* Signature: (IIIIII)V
*/
JNIEXPORT jint JNICALL Java_quality_util_UnixTouchScreenDevice_moveImpl(
JNIEnv *env, jobject o, jint fd, jint trackingId, jint fromX, jint fromY,
jint toX, jint toY) {
touch_begin(fd, trackingId, fromX, fromY);
touch_update(fd, toX, toY);
touch_end(fd);
return 0;
}

View File

@@ -0,0 +1,84 @@
#include <jni.h>
#include <windows.h>
#include <WinUser.h>
POINTER_TOUCH_INFO create_touch_info()
{
POINTER_TOUCH_INFO contact;
InitializeTouchInjection(1, TOUCH_FEEDBACK_DEFAULT); // Number of contact point
memset(&contact, 0, sizeof(POINTER_TOUCH_INFO));
contact.touchFlags = TOUCH_FLAG_NONE;
contact.touchMask = TOUCH_MASK_CONTACTAREA | TOUCH_MASK_ORIENTATION | TOUCH_MASK_PRESSURE;
contact.orientation = 90; // Orientation of 90 means touching perpendicular to screen.
contact.pressure = 32000;
return contact;
}
void set_contact_area(POINTER_TOUCH_INFO *contact)
{
// 4 x 4 pixel contact area
contact->rcContact.top = contact->pointerInfo.ptPixelLocation.y - 2;
contact->rcContact.bottom = contact->pointerInfo.ptPixelLocation.y + 2;
contact->rcContact.left = contact->pointerInfo.ptPixelLocation.x - 2;
contact->rcContact.right = contact->pointerInfo.ptPixelLocation.x + 2;
}
void touchBegin(POINTER_TOUCH_INFO* contact, LONG x, LONG y)
{
contact->pointerInfo.pointerType = PT_TOUCH;
// primary finger pointerId == 0
contact->pointerInfo.pointerId = 0;
contact->pointerInfo.ptPixelLocation.x = x;
contact->pointerInfo.ptPixelLocation.y = y;
set_contact_area(contact);
contact->pointerInfo.pointerFlags = POINTER_FLAG_DOWN | POINTER_FLAG_INRANGE | POINTER_FLAG_INCONTACT;
InjectTouchInput(1, contact);
}
void touchUpdate(POINTER_TOUCH_INFO* contact, LONG x, LONG y)
{
contact->pointerInfo.pointerFlags = POINTER_FLAG_UPDATE | POINTER_FLAG_INRANGE | POINTER_FLAG_INCONTACT;
contact->pointerInfo.ptPixelLocation.x = x;
contact->pointerInfo.ptPixelLocation.y = y;
InjectTouchInput(1, contact);
}
void touchEnd(POINTER_TOUCH_INFO* contact)
{
contact->pointerInfo.pointerFlags = POINTER_FLAG_UP;
InjectTouchInput(1, contact);
}
/*
* Class: quality_util_WindowsTouchRobot
* Method: clickImpl
* Signature: (II)V
*/
JNIEXPORT void JNICALL
Java_quality_util_WindowsTouchRobot_clickImpl(JNIEnv* env, jobject o,
jint x, jint y)
{
POINTER_TOUCH_INFO contact = create_touch_info();
touchBegin(&contact, x, y);
touchEnd(&contact);
}
/*
* Class: quality_util_WindowsTouchRobot
* Method: moveImpl
* Signature: (IIII)V
*/
JNIEXPORT void JNICALL
Java_quality_util_WindowsTouchRobot_moveImpl(JNIEnv* env, jobject o,
jint fromX, jint fromY,
jint toX, jint toY)
{
POINTER_TOUCH_INFO contact = create_touch_info();
touchBegin(&contact, fromX, fromY);
touchUpdate(&contact, toX, toY);
touchEnd(&contact);
}

View File

@@ -0,0 +1,338 @@
package quality.event;
import org.apache.commons.lang3.SystemUtils;
import org.junit.Test;
import quality.util.UnixTouchRobot;
import quality.util.TouchRobot;
import quality.util.WindowsTouchRobot;
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.io.IOException;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
public class TouchScreenEventsTest {
static final int TIMEOUT = 2;
// TODO make this constants accessible within jdk
static final int TOUCH_BEGIN = 2;
static final int TOUCH_UPDATE = 3;
static final int TOUCH_END = 4;
@Test
public void testTouchClick() throws Exception {
runTest(new TouchClickSuite());
}
@Test
public void testTouchMove() throws Exception {
runTest(new TouchMoveSuite());
}
@Test
public void testTouchTinyMove() throws Exception {
runTest(new TouchTinyMoveSuite());
}
@Test
public void testTouchHorizontalScroll() throws Exception {
runTest(new TouchAxesScrollSuite(TouchAxesScrollSuite.AXIS.X));
}
@Test
public void testTouchVerticalScroll() throws Exception {
runTest(new TouchAxesScrollSuite(TouchAxesScrollSuite.AXIS.Y));
}
private static void runTest(TouchTestSuite suite) throws Exception {
GUI gui = new GUI();
try {
TouchRobot robot = getTouchRobot();
SwingUtilities.invokeAndWait(gui::createAndShow);
suite.addListener(gui.frame);
robot.waitForIdle();
suite.perform(gui, robot);
robot.waitForIdle();
suite.passed();
} finally {
SwingUtilities.invokeLater(() -> {
if (gui.frame != null) {
gui.frame.dispose();
}
});
}
}
private static TouchRobot getTouchRobot() throws IOException, AWTException {
if (SystemUtils.IS_OS_UNIX) {
return new UnixTouchRobot();
} else if (SystemUtils.IS_OS_WINDOWS) {
return new WindowsTouchRobot();
}
throw new RuntimeException("Touch robot for this platform isn't implemented");
}
}
class GUI {
JFrame frame;
Rectangle frameBounds;
void createAndShow() {
frame = new JFrame();
frame.setSize(640, 480);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
frameBounds = frame.getBounds();
}
}
interface TouchTestSuite {
void perform(GUI gui, TouchRobot robot) throws IOException;
void passed() throws InterruptedException;
void addListener(JFrame frame);
}
class TouchClickSuite implements MouseListener, TouchTestSuite {
private volatile boolean pressed;
private volatile boolean released;
private volatile boolean clicked;
private final CountDownLatch latch = new CountDownLatch(3);
@Override
public void mouseClicked(MouseEvent e) {
if (!clicked) {
clicked = true;
latch.countDown();
}
}
@Override
public void mousePressed(MouseEvent e) {
pressed = true;
if (!pressed) {
pressed = true;
latch.countDown();
}
}
@Override
public void mouseReleased(MouseEvent e) {
if (!released) {
released = true;
latch.countDown();
}
}
@Override
public void mouseEntered(MouseEvent e) {
}
@Override
public void mouseExited(MouseEvent e) {
}
@Override
public void perform(GUI gui, TouchRobot robot) throws IOException {
int x = gui.frameBounds.x + gui.frameBounds.width / 2;
int y = gui.frameBounds.y + gui.frameBounds.height / 2;
robot.touchClick(42, x, y);
}
@Override
public void passed() throws InterruptedException {
latch.await(TouchScreenEventsTest.TIMEOUT, TimeUnit.SECONDS);
if (!pressed || !released || !clicked) {
String error = (pressed ? "" : "pressed: " + pressed) +
(released ? "" : ", released: " + released) +
(clicked ? "" : ", clicked: " + clicked);
throw new RuntimeException("Touch click failed: " + error);
}
}
@Override
public void addListener(JFrame frame) {
frame.addMouseListener(this);
}
}
class TouchMoveSuite implements MouseWheelListener, TouchTestSuite {
private volatile boolean begin;
private volatile boolean update;
private volatile boolean end;
private final CountDownLatch latch = new CountDownLatch(3);
@Override
public void mouseWheelMoved(MouseWheelEvent e) {
if (e.getScrollType() == TouchScreenEventsTest.TOUCH_BEGIN) {
if (!begin) {
begin = true;
latch.countDown();
}
} else if (e.getScrollType() == TouchScreenEventsTest.TOUCH_UPDATE) {
if (!update) {
update = true;
latch.countDown();
}
} else if (e.getScrollType() == TouchScreenEventsTest.TOUCH_END) {
if (!end) {
end = true;
latch.countDown();
}
}
}
@Override
public void perform(GUI gui, TouchRobot robot) throws IOException {
int x1 = gui.frameBounds.x + gui.frameBounds.width / 4;
int y1 = gui.frameBounds.y + gui.frameBounds.height / 4;
int x2 = gui.frameBounds.x + gui.frameBounds.width / 2;
int y2 = gui.frameBounds.y + gui.frameBounds.height / 2;
robot.touchMove(42, x1, y1, x2, y2);
}
@Override
public void passed() throws InterruptedException {
latch.await(TouchScreenEventsTest.TIMEOUT, TimeUnit.SECONDS);
if (!begin || !update || !end) {
String error = (begin ? "" : "begin: " + begin) +
(update ? "" : ", update: " + update) +
(end ? "" : ", end: " + end);
throw new RuntimeException("Touch move failed: " + error);
}
}
@Override
public void addListener(JFrame frame) {
frame.addMouseWheelListener(this);
}
}
class TouchTinyMoveSuite implements MouseWheelListener, MouseListener, TouchTestSuite {
private volatile boolean scroll;
private volatile boolean click;
private final CountDownLatch latch = new CountDownLatch(1);
@Override
public void mouseWheelMoved(MouseWheelEvent e) {
if (e.getScrollType() == TouchScreenEventsTest.TOUCH_UPDATE) {
scroll = true;
latch.countDown();
}
}
@Override
public void perform(GUI gui, TouchRobot robot) throws IOException {
int x1 = gui.frameBounds.x + gui.frameBounds.width / 4;
int y1 = gui.frameBounds.y + gui.frameBounds.height / 4;
// move inside tiny area
int x2 = x1 + 1;
int y2 = y1 + 1;
robot.touchMove(42, x1, y1, x2, y2);
}
@Override
public void passed() throws InterruptedException {
latch.await(TouchScreenEventsTest.TIMEOUT, TimeUnit.SECONDS);
if (scroll || !click) {
String error = (scroll ? "scroll " + scroll : "") +
(click ? "" : ", click: " + click);
throw new RuntimeException("Tiny touch move failed: " + error);
}
}
@Override
public void addListener(JFrame frame) {
frame.addMouseWheelListener(this);
frame.addMouseListener(this);
}
@Override
public void mouseClicked(MouseEvent e) {
click = true;
latch.countDown();
}
@Override
public void mousePressed(MouseEvent e) {
}
@Override
public void mouseReleased(MouseEvent e) {
}
@Override
public void mouseEntered(MouseEvent e) {
}
@Override
public void mouseExited(MouseEvent e) {
}
}
class TouchAxesScrollSuite implements MouseWheelListener, TouchTestSuite {
enum AXIS {X, Y}
private final AXIS axis;
private volatile boolean vertical;
private volatile boolean horizontal;
private final CountDownLatch latch = new CountDownLatch(1);
TouchAxesScrollSuite(AXIS axis) {
this.axis = axis;
}
@Override
public void mouseWheelMoved(MouseWheelEvent e) {
if (e.getScrollType() == TouchScreenEventsTest.TOUCH_UPDATE) {
if (e.isShiftDown()) {
horizontal = true;
} else {
vertical = true;
}
latch.countDown();
}
}
@Override
public void perform(GUI gui, TouchRobot robot) throws IOException {
int x1 = gui.frameBounds.x + gui.frameBounds.width / 4;
int y1 = gui.frameBounds.y + gui.frameBounds.height / 4;
switch (axis) {
case X:
int x2 = gui.frameBounds.x + gui.frameBounds.width / 2;
robot.touchMove(42, x1, y1, x2, y1);
break;
case Y:
int y2 = gui.frameBounds.y + gui.frameBounds.height / 2;
robot.touchMove(42, x1, y1, x1, y2);
break;
}
}
@Override
public void passed() throws InterruptedException {
latch.await(TouchScreenEventsTest.TIMEOUT, TimeUnit.SECONDS);
String error = "horizontal " + horizontal + ", vertical: " + vertical;
switch (axis) {
case X:
if (!horizontal || vertical) {
throw new RuntimeException("Touch axes failed: " + error);
}
break;
case Y:
if (horizontal || !vertical) {
throw new RuntimeException("Touch axes failed: " + error);
}
break;
}
}
@Override
public void addListener(JFrame frame) {
frame.addMouseWheelListener(this);
}
}

View File

@@ -0,0 +1,17 @@
package quality.util;
import java.awt.*;
import java.io.IOException;
public abstract class TouchRobot extends Robot {
public TouchRobot() throws AWTException {
}
public TouchRobot(GraphicsDevice screen) throws AWTException {
super(screen);
}
public abstract void touchClick(int fingerId, int x, int y) throws IOException;
public abstract void touchMove(int fingerId, int fromX, int fromY, int toX, int toY) throws IOException;
}

View File

@@ -0,0 +1,26 @@
package quality.util;
import java.awt.*;
import java.io.IOException;
public class UnixTouchRobot extends TouchRobot {
private UnixTouchScreenDevice device;
public UnixTouchRobot() throws AWTException, IOException {
super();
device = new UnixTouchScreenDevice();
}
public UnixTouchRobot(GraphicsDevice screen) throws AWTException, IOException {
super(screen);
device = new UnixTouchScreenDevice();
}
public void touchClick(int fingerId, int x, int y) throws IOException {
device.click(fingerId, x, y);
}
public void touchMove(int fingerId, int fromX, int fromY, int toX, int toY) throws IOException {
device.move(fingerId, fromX, fromY, toX, toY);
}
}

View File

@@ -0,0 +1,68 @@
package quality.util;
import java.awt.*;
import java.io.IOException;
public class UnixTouchScreenDevice implements AutoCloseable {
// TODO add product id
private int width;
private int height;
private int fileDescriptor;
static {
System.loadLibrary("touchscreen_device");
}
public UnixTouchScreenDevice() throws IOException {
this(Toolkit.getDefaultToolkit().getScreenSize().width, Toolkit.getDefaultToolkit().getScreenSize().height);
}
public UnixTouchScreenDevice(int width, int height) throws IOException {
this.width = width;
this.height = height;
fileDescriptor = create(getWidth(), getHeight());
checkCompletion(fileDescriptor,
"Failed to create virtual touchscreen device");
}
@Override
public void close() throws Exception {
checkCompletion(destroy(fileDescriptor),
"Failed to close touchscreen device");
}
public int getWidth() {
return width;
}
public int getHeight() {
return height;
}
public void click(int trackingId, int x, int y) throws IOException {
checkCompletion(clickImpl(fileDescriptor, trackingId, x, y),
"Failed to click on touchscreen device");
}
public void move(int trackingId, int fromX, int fromY, int toX, int toY) throws IOException {
checkCompletion(moveImpl(fileDescriptor, trackingId, fromX, fromY, toX, toY),
"Failed to move on virtual touchscreen device");
}
private void checkCompletion(int code, String errorMessage) throws IOException {
if (code < 0) {
throw new IOException(errorMessage);
}
}
private native int create(int width, int height);
private native int destroy(int fd);
private native int clickImpl(int fd, int trackingId, int x, int y);
private native int moveImpl(int fd, int trackingId, int fromX, int fromY, int toX, int toY);
}

View File

@@ -0,0 +1,34 @@
package quality.util;
import java.awt.*;
import java.io.IOException;
public class WindowsTouchRobot extends TouchRobot {
static {
System.loadLibrary("windows_touch_robot");
}
public WindowsTouchRobot() throws AWTException, IOException {
super();
}
public WindowsTouchRobot(GraphicsDevice screen) throws AWTException, IOException {
super(screen);
}
@Override
public void touchClick(int fingerId, int x, int y) throws IOException {
// TODO unused finger id cause windows use different finger id model
clickImpl(x, y);
}
@Override
public void touchMove(int fingerId, int fromX, int fromY, int toX, int toY) throws IOException {
// TODO unused finger id cause windows use different finger id model
moveImpl(fromX, fromY, toX, toY);
}
private native void clickImpl(int x, int y);
private native void moveImpl(int fromX, int fromY, int toX, int toY);
}