Skip to content

Commit

Permalink
Improved handling of special chars
Browse files Browse the repository at this point in the history
  • Loading branch information
RetGal committed Feb 21, 2017
1 parent 7ef7f60 commit c2e2c44
Show file tree
Hide file tree
Showing 7 changed files with 153 additions and 32 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ With his permission I moved the code base to GitHub, where it can be maintained

## Releases

The ![latest version](https://github.com/RetGal/Dayon/releases/latest) is 1.4.2 - released more than eight years after the latest release of the original author.
The ![latest version](https://github.com/RetGal/Dayon/releases/latest) is 1.4.3 - released more than eight years after the latest release of the original author.

This version uses updated libraries, can handle Windows UAC-dialogs and encrypts all its communication.

Expand Down
2 changes: 1 addition & 1 deletion build.xml
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@
<target name="build" depends="compile">
<jar destfile="${dir.build}/dayon.jar">
<manifest>
<attribute name="Implementation-Version" value="1.4 #2" />
<attribute name="Implementation-Version" value="1.4 #3" />
<attribute name="Main-Class" value="${main.class}" />
<attribute name="Class-Path" value=". jetty-continuation-8.1.21.v20160908.jar jetty-http-8.1.21.v20160908.jar jetty-io-8.1.21.v20160908.jar jetty-server-8.1.21.v20160908.jar jetty-util-8.1.21.v20160908.jar servlet-api-3.0.jar" />
<attribute name="Permissions" value="all-permissions" />
Expand Down
1 change: 1 addition & 0 deletions src/mpo/dayon/assistant/gui/Assistant.java
Original file line number Diff line number Diff line change
Expand Up @@ -164,6 +164,7 @@ public void start() {

FatalErrorHandler.attachFrame(frame);


frame.addListener(control);
frame.setVisible(true);
}
Expand Down
127 changes: 103 additions & 24 deletions src/mpo/dayon/assisted/control/RobotNetworkControlMessageHandler.java
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import java.awt.Robot;
import java.awt.event.InputEvent;
import java.awt.event.KeyEvent;
import java.io.File;
import java.util.ArrayList;
import java.util.List;

Expand All @@ -17,27 +18,27 @@

public class RobotNetworkControlMessageHandler implements NetworkControlMessageHandler {
private final Robot robot;

private List<Subscriber> subscribers = new ArrayList<>();

private List<Subscriber> subscribers = new ArrayList<Subscriber>();

public RobotNetworkControlMessageHandler() {
try {
robot = new Robot();
} catch (AWTException ex) {
throw new RuntimeException(ex);
}
}

public void subscribe(Subscriber subscriber) {
subscribers.add(subscriber);
}

public void shout(char bogusChar) {
for (Subscriber subscriber : subscribers) {
subscriber.digest(String.valueOf(bogusChar));
}
}

public RobotNetworkControlMessageHandler() {
try {
robot = new Robot();
} catch (AWTException ex) {
throw new RuntimeException(ex);
}
}

/**
* Should not block as called from the network incoming message thread (!)
*/
Expand All @@ -61,7 +62,6 @@ public void handleMessage(NetworkEngine engine, NetworkMouseControlMessage messa
} else if (message.isWheel()) {
robot.mouseWheel(message.getRotations());
}

robot.mouseMove(message.getX(), message.getY());
}

Expand All @@ -74,12 +74,14 @@ public void handleMessage(NetworkEngine engine, NetworkKeyControlMessage message
robot.keyPress(message.getKeyCode());
} catch (IllegalArgumentException ex) {
Log.warn(message.toString() +" contained an invalid keyCode for "+message.getKeyChar());
shout(message.getKeyChar());
if (message.getKeyChar() != KeyEvent.CHAR_UNDEFINED) {
KeyStroke key = KeyStroke.getKeyStroke(message.getKeyChar());
KeyStroke key = KeyStroke.getKeyStroke(message.getKeyChar(), 0);
// plan b
if (key.getKeyCode() != Character.MIN_VALUE) {
Log.warn("retrying with keyCode "+key.getKeyCode());
robot.keyPress(key.getKeyCode());
typeUnicode(key.getKeyCode());
} else {
shout(message.getKeyChar());
}
}
}
Expand All @@ -88,16 +90,93 @@ public void handleMessage(NetworkEngine engine, NetworkKeyControlMessage message
robot.keyRelease(message.getKeyCode());
} catch (IllegalArgumentException ex) {
Log.warn(message.toString() +" contained an invalid keyCode for "+message.getKeyChar());
shout(message.getKeyChar());
if (message.getKeyChar() != KeyEvent.CHAR_UNDEFINED) {
KeyStroke key = KeyStroke.getKeyStroke(message.getKeyChar());
if (key.getKeyCode() != Character.MIN_VALUE) {
Log.warn("retrying with keyCode "+key.getKeyCode());
robot.keyRelease(key.getKeyCode());
}
}
}

}
}

/**
* Q&D OS detection
*/
public void typeUnicode(int keyCode)
{
if (File.separatorChar == '/') {
typeLinuxUnicode(keyCode);
} else {
typeWindowsUnicode(keyCode);
}
}

/**
* Unicode characters are typed in decimal on Windows ä => 228
*/
private void typeWindowsUnicode(int keyCode) {
robot.keyPress(KeyEvent.VK_ALT);
// simulate a numpad key press for each digit
for(int i = 3; i >= 0; --i)
{
int code = keyCode / (int) (Math.pow(10, i)) % 10 + KeyEvent.VK_NUMPAD0;
robot.keyPress(code);
robot.keyRelease(code);
}
robot.keyRelease(KeyEvent.VK_ALT);
}

/**
* Unicode characters are typed in hex on Linux ä => e4
*/
private void typeLinuxUnicode(int keyCode) {
robot.keyPress(KeyEvent.VK_CONTROL);
robot.keyPress(KeyEvent.VK_SHIFT);
robot.keyPress(KeyEvent.VK_U);
robot.keyRelease(KeyEvent.VK_U);
char[] charArray = Integer.toHexString(keyCode).toCharArray();
// simulate a key press for each char
for (char c : charArray) {
int code = getKeyCode(c);
robot.keyPress(code);
robot.keyRelease(code);
}
robot.keyRelease(KeyEvent.VK_SHIFT);
robot.keyRelease(KeyEvent.VK_CONTROL);
}

/**
* Maps a hex char to its corresponding virtual key code
*/
private int getKeyCode(char c) {
switch(c) {
case '0':
return 48;
case '1':
return 49;
case '2':
return 50;
case '3':
return 51;
case '4':
return 52;
case '5':
return 53;
case '6':
return 54;
case '7':
return 55;
case '8':
return 56;
case '9':
return 57;
case 'a':
return 65;
case 'b':
return 66;
case 'c':
return 67;
case 'd':
return 68;
case 'e':
return 69;
default:
return 70;
}
}
}
3 changes: 1 addition & 2 deletions src/mpo/dayon/assisted/gui/Assisted.java
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@ public void start() throws IOException {
frame = new AssistedFrame(new AssistedFrameConfiguration());

FatalErrorHandler.attachFrame(frame);
SeriousErrorHandler.attachFrame(frame);

frame.setVisible(true);

Expand Down Expand Up @@ -158,8 +159,6 @@ public void handleConfiguration(NetworkEngine engine, NetworkCompressorConfigura

final NetworkControlMessageHandler controlHandler = new RobotNetworkControlMessageHandler();

SeriousErrorHandler.attachFrame(frame);

controlHandler.subscribe(this);

frame.onConnecting(configuration);
Expand Down
3 changes: 3 additions & 0 deletions src/mpo/dayon/common/error/FatalErrorHandler.java
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,9 @@ public abstract class FatalErrorHandler {
@Nullable
private static JFrame frame;

/**
* Displays a translated error message and terminates
*/
public static void bye(String message, Throwable error) {
Log.fatal(message, error);
Log.fatal("Bye!");
Expand Down
47 changes: 43 additions & 4 deletions src/mpo/dayon/common/error/SeriousErrorHandler.java
Original file line number Diff line number Diff line change
@@ -1,24 +1,63 @@
package mpo.dayon.common.error;

import java.awt.Window;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.SwingUtilities;
import javax.swing.Timer;

import org.jetbrains.annotations.Nullable;

import mpo.dayon.common.babylon.Babylon;
import mpo.dayon.common.log.Log;

public abstract class SeriousErrorHandler {

@Nullable
private static JFrame frame;

public static void warn(String message) {
/**
* Displays a self closing translated warning message
*/
public static void warn(final String message) {

if (frame != null) {
JOptionPane.showMessageDialog(frame, Babylon.translate("serious.error.msg1") + "\n" + Babylon.translate("serious.error.msg2", message) + "\n" + Babylon.translate("serious.error.msg3") ,
Babylon.translate("serious.error"), JOptionPane.ERROR_MESSAGE);
final JLabel label = new JLabel();
int timerDelay = 1000;
new Timer(timerDelay, new ActionListener() {
int timeLeft = 4;

@Override
public void actionPerformed(ActionEvent e) {
if (timeLeft > 0) {
StringBuilder sb = new StringBuilder("<html>");
sb.append(Babylon.translate("serious.error.msg1")).append("<br/>");
sb.append(Babylon.translate("serious.error.msg2", message)).append("<br/>");
sb.append(Babylon.translate("serious.error.msg3", message)).append("</html>");
label.setText(sb.toString());
--timeLeft;
} else {
((Timer) e.getSource()).stop();
Window win = SwingUtilities.getWindowAncestor(label);
win.setVisible(false);
}
}
}) {
private static final long serialVersionUID = -3451080808563481433L;

{
setInitialDelay(0);
}
}.start();

JOptionPane.showMessageDialog(frame, label, Babylon.translate("serious.error"), JOptionPane.WARNING_MESSAGE);

} else {
Log.error("Unable to display error message "+message);
Log.error("Unable to display error message " + message);
}

}
Expand Down

0 comments on commit c2e2c44

Please sign in to comment.