Skip to content

Commit

Permalink
Improved handling of special chars typed on varying locales on assist…
Browse files Browse the repository at this point in the history
…ant/assisted should close #28
  • Loading branch information
RetGal committed Feb 21, 2021
1 parent f21793e commit 86393fd
Show file tree
Hide file tree
Showing 3 changed files with 172 additions and 22 deletions.
7 changes: 7 additions & 0 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
<bzip2.version>0.9.1</bzip2.version>
<grizzly-lzma.version>1.9.65</grizzly-lzma.version>
<junit.jupiter.version>5.7.1</junit.jupiter.version>
<mockito.core.version>3.7.7</mockito.core.version>
</properties>

<dependencies>
Expand All @@ -59,6 +60,12 @@
<version>${junit.jupiter.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-core</artifactId>
<version>${mockito.core.version}</version>
<scope>test</scope>
</dependency>
</dependencies>

<profiles>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,10 @@ public RobotNetworkControlMessageHandler() {
}
}

public RobotNetworkControlMessageHandler(Robot robot) {
this.robot = robot;
}

@Override
public void subscribe(Subscriber subscriber) {
subscribers.add(subscriber);
Expand Down Expand Up @@ -71,41 +75,67 @@ public void handleMessage(NetworkMouseControlMessage message) {
public void handleMessage(NetworkKeyControlMessage message) {
if (message.isPressed()) {
try {
robot.keyPress(message.getKeyCode());
pressKey(message);
} catch (IllegalArgumentException ex) {
Log.warn(message.toString() + " contained an invalid keyCode for " + message.getKeyChar());
if (message.getKeyChar() != KeyEvent.CHAR_UNDEFINED) {
KeyStroke key = KeyStroke.getKeyStroke(message.getKeyChar(), 0);
// plan b
if (key.getKeyCode() != Character.MIN_VALUE) {
Log.warn("retrying with keyCode " + key.getKeyCode());
typeUnicode(key.getKeyCode());
return;
}
shout(message.getKeyChar());
}
Log.error("Error while handling key press", ex);
}
} else if (message.isReleased()) {
try {
robot.keyRelease(message.getKeyCode());
releaseKey(message);
} catch (IllegalArgumentException ex) {
Log.warn(message.toString() + " contained an invalid keyCode for " + message.getKeyChar());
Log.error("Error while handling key release", ex);
}
}
}

/**
* Q&D OS detection
*/
private void typeUnicode(int keyCode)
{
private void pressKey(NetworkKeyControlMessage message) {
if (message.getKeyCode() != KeyEvent.VK_UNDEFINED) {
robot.keyPress(message.getKeyCode());
} else {
Log.warn(message.toString() + " contained an invalid keyCode for " + message.getKeyChar());
if (message.getKeyChar() != KeyEvent.CHAR_UNDEFINED) {
KeyStroke key = KeyStroke.getKeyStroke(message.getKeyChar(), 0);
// plan b
if (key.getKeyCode() != Character.MIN_VALUE) {
Log.warn("retrying with keyCode " + key.getKeyCode());
typeUnicode(key.getKeyCode());
return;
}
shout(message.getKeyChar());
}
}
}

private void typeUnicode(int keyCode) {
if (File.separatorChar == '/') {
typeLinuxUnicode(keyCode);
return;
}
typeWindowsUnicode(keyCode);
}

private void releaseKey(NetworkKeyControlMessage message) {
if (message.getKeyCode() != KeyEvent.VK_UNDEFINED) {
robot.keyRelease(message.getKeyCode());
} else {
if (message.getKeyChar() != KeyEvent.CHAR_UNDEFINED) {
KeyStroke key = KeyStroke.getKeyStroke(message.getKeyChar(), 0);
if (key.getKeyCode() != Character.MIN_VALUE) {
releaseUnicode();
return;
}
}
}
}

private void releaseUnicode() {
if (File.separatorChar == '/') {
releaseLinuxUnicode();
return;
}
releaseWindowsUnicode();
}

/**
* Unicode characters are typed in decimal on Windows ä => 228
*/
Expand All @@ -117,7 +147,11 @@ private void typeWindowsUnicode(int keyCode) {
robot.keyPress(code);
robot.keyRelease(code);
}
robot.keyRelease(KeyEvent.VK_ALT);
// will be released when handling the subsequent message
}

private void releaseWindowsUnicode() {
robot.keyRelease(KeyEvent.VK_ALT);
}

/**
Expand All @@ -136,8 +170,11 @@ private void typeLinuxUnicode(int keyCode) {
robot.keyPress(code);
robot.keyRelease(code);
}
robot.keyRelease(KeyEvent.VK_SHIFT);
robot.keyRelease(KeyEvent.VK_CONTROL);
// will be released when handling the subsequent message
}

private void releaseLinuxUnicode() {
robot.keyRelease(KeyEvent.VK_SHIFT);
robot.keyRelease(KeyEvent.VK_CONTROL);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
package mpo.dayon.assisted.control;

import mpo.dayon.common.network.message.NetworkKeyControlMessage;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.condition.DisabledOnOs;

import java.awt.*;
import java.awt.event.KeyEvent;

import static mpo.dayon.common.network.message.NetworkKeyControlMessage.KeyState.PRESSED;
import static mpo.dayon.common.network.message.NetworkKeyControlMessage.KeyState.RELEASED;
import static org.junit.jupiter.api.condition.OS.WINDOWS;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;

class RobotNetworkControlMessageHandlerTest {

Robot robot = mock(Robot.class);
RobotNetworkControlMessageHandler controlMessageHandler = new RobotNetworkControlMessageHandler(robot);

@Test
void testHandleMessagePressA() {
// given
NetworkKeyControlMessage message = new NetworkKeyControlMessage(PRESSED, 65, 'A');
// when
controlMessageHandler.handleMessage(message);
// then
verify(robot).keyPress(message.getKeyChar());
}

@Test
void testHandleMessageReleaseA() {
// given
NetworkKeyControlMessage message = new NetworkKeyControlMessage(RELEASED, 65, 'A');
// when
controlMessageHandler.handleMessage(message);
// then
verify(robot).keyRelease(message.getKeyChar());
}

@Test
@DisabledOnOs(WINDOWS)
void testHandleMessagePressTurkishLowerSpecialSTypedOnNonTurkishAssisted() {
// given
NetworkKeyControlMessage message = new NetworkKeyControlMessage(PRESSED, 0, 'ş');
// when
controlMessageHandler.handleMessage(message);
// then
verify(robot).keyPress(KeyEvent.VK_CONTROL);
verify(robot).keyPress(KeyEvent.VK_SHIFT);
verify(robot).keyPress(KeyEvent.VK_U);
verify(robot).keyRelease(KeyEvent.VK_U);
// 351 as hex 15F
verify(robot).keyPress(KeyEvent.VK_1);
verify(robot).keyRelease(KeyEvent.VK_1);
verify(robot).keyPress(KeyEvent.VK_5);
verify(robot).keyRelease(KeyEvent.VK_5);
verify(robot).keyPress(KeyEvent.VK_F);
verify(robot).keyRelease(KeyEvent.VK_F);
}

@Test
@DisabledOnOs(WINDOWS)
void testHandleMessageReleaseTurkishLowerSpecialSTypedOnNonTurkishAssisted() {
// given
NetworkKeyControlMessage message = new NetworkKeyControlMessage(RELEASED, 0, 'ş');
// when
controlMessageHandler.handleMessage(message);
// then
robot.keyRelease(KeyEvent.VK_SHIFT);
robot.keyRelease(KeyEvent.VK_CONTROL);
}

@Test
@DisabledOnOs(WINDOWS)
void testHandleMessagePressTurkishUpperSpecialSTypedOnNonTurkishAssisted() {
// given
NetworkKeyControlMessage message = new NetworkKeyControlMessage(PRESSED, 0, 'Ş');
// when
controlMessageHandler.handleMessage(message);
// then
verify(robot).keyPress(KeyEvent.VK_CONTROL);
verify(robot).keyPress(KeyEvent.VK_SHIFT);
verify(robot).keyPress(KeyEvent.VK_U);
verify(robot).keyRelease(KeyEvent.VK_U);
// 350 as hex 15E
verify(robot).keyPress(KeyEvent.VK_1);
verify(robot).keyRelease(KeyEvent.VK_1);
verify(robot).keyPress(KeyEvent.VK_5);
verify(robot).keyRelease(KeyEvent.VK_5);
verify(robot).keyPress(KeyEvent.VK_E);
verify(robot).keyRelease(KeyEvent.VK_E);
}

@Test
@DisabledOnOs(WINDOWS)
void testHandleMessageReleaseTurkishUpperSpecialSTypedOnNonTurkishAssisted() {
// given
NetworkKeyControlMessage message = new NetworkKeyControlMessage(RELEASED, 0, 'Ş');
// when
controlMessageHandler.handleMessage(message);
// then
robot.keyRelease(KeyEvent.VK_SHIFT);
robot.keyRelease(KeyEvent.VK_CONTROL);
}
}

0 comments on commit 86393fd

Please sign in to comment.