> counters) {
- final StatusBar statusBar = new StatusBar();
- final Component horizontalStrut = Box.createHorizontalStrut(10);
- statusBar.add(horizontalStrut);
- for (Counter> counter : counters) {
- statusBar.addSeparator();
- statusBar.addCounter(counter, counter.getWidth());
- }
- statusBar.addSeparator();
- statusBar.addRamInfo();
- statusBar.addSeparator();
- statusBar.addConnectionDuration();
- statusBar.add(horizontalStrut);
- return statusBar;
- }
-
- private Action createToggleControlMode() {
- final Action remoteControl = new AbstractAction() {
-
- @Override
- public void actionPerformed(ActionEvent ev) {
- controlActivated.set(!controlActivated.get());
- windowsKeyToggleButton.setEnabled(controlActivated.get());
- ctrlKeyToggleButton.setEnabled(controlActivated.get());
- }
- };
- remoteControl.putValue(Action.SHORT_DESCRIPTION, translate("control.mode"));
- remoteControl.putValue(Action.SMALL_ICON, getOrCreateIcon(ImageNames.WATCH));
- remoteControl.putValue(ROLLOVER_ICON, getOrCreateIcon(ImageNames.WATCH));
- remoteControl.putValue(SELECTED_ICON, getOrCreateIcon(ImageNames.CONTROL));
- return remoteControl;
- }
-
- private Action createSendWindowsKeyAction() {
- final Action sendWindowsKey = new AbstractAction() {
- @Override
- public void actionPerformed(ActionEvent ev) {
- final int virtualKey = osId != 'm' ? VK_WINDOWS : VK_META;
- if (windowsKeyActivated.get()) {
- fireOnKeyReleased(virtualKey, EMPTY_CHAR);
- } else {
- fireOnKeyPressed(virtualKey, EMPTY_CHAR);
- }
- windowsKeyActivated.set(!windowsKeyActivated.get());
- }
- };
- sendWindowsKey.putValue(Action.SHORT_DESCRIPTION, translate("send.windowsKey"));
- sendWindowsKey.putValue(Action.SMALL_ICON, getOrCreateIcon(ImageNames.WIN));
- return sendWindowsKey;
- }
-
- private Action createSendCtrlKeyAction() {
- final Action sendCtrlKey = new AbstractAction() {
- @Override
- public void actionPerformed(ActionEvent ev) {
- if (ctrlKeyActivated.get()) {
- fireOnKeyReleased(VK_CONTROL, EMPTY_CHAR);
- } else {
- fireOnKeyPressed(VK_CONTROL, EMPTY_CHAR);
- }
- ctrlKeyActivated.set(!ctrlKeyActivated.get());
- }
- };
- sendCtrlKey.putValue(Action.SHORT_DESCRIPTION, translate("send.ctrlKey"));
- sendCtrlKey.putValue(Action.SMALL_ICON, getOrCreateIcon(ImageNames.CTRL));
- return sendCtrlKey;
- }
-
- private Action createToggleFixScreenAction() {
- final Action fitScreen = new AbstractAction() {
- @Override
- public void actionPerformed(ActionEvent ev) {
- fitToScreenActivated.set(!fitToScreenActivated.get());
- if (!fitToScreenActivated.get()) {
- keepAspectRatioToggleButton.setVisible(false);
- resetFactors();
- } else {
- keepAspectRatioToggleButton.setVisible(true);
- resetCanvas();
- }
- repaint();
- }
- };
- fitScreen.putValue(Action.SHORT_DESCRIPTION, translate("toggle.screen.mode"));
- fitScreen.putValue(Action.SMALL_ICON, getOrCreateIcon(ImageNames.FULLSCREEN));
- fitScreen.putValue(ROLLOVER_ICON, getOrCreateIcon(ImageNames.FULLSCREEN));
- fitScreen.putValue(SELECTED_ICON, getOrCreateIcon(ImageNames.FIT));
- return fitScreen;
- }
-
- private Action createToggleKeepAspectRatioAction() {
- final Action keepAspectRatio = new AbstractAction() {
- @Override
- public void actionPerformed(ActionEvent ev) {
- keepAspectRatioActivated.set(!keepAspectRatioActivated.get());
- resetCanvas();
- repaint();
- }
- };
- keepAspectRatio.putValue(Action.SHORT_DESCRIPTION, translate("toggle.keep.aspect"));
- keepAspectRatio.putValue(Action.SMALL_ICON, getOrCreateIcon(ImageNames.UNLOCKED));
- keepAspectRatio.putValue(ROLLOVER_ICON, getOrCreateIcon(ImageNames.UNLOCKED));
- keepAspectRatio.putValue(SELECTED_ICON, getOrCreateIcon(ImageNames.LOCK));
- return keepAspectRatio;
- }
-
- void onReady() {
- hideSpinner();
- validate();
- repaint();
- this.setCursor(Cursor.getDefaultCursor());
- // connection
- actions.getStartAction().setEnabled(true);
- actions.getStopAction().setEnabled(false);
- startButton.setVisible(true);
- stopButton.setVisible(false);
- actions.getTokenAction().setEnabled(true);
- actions.getToggleCompatibilityModeAction().setEnabled(true);
- actions.getIpAddressAction().setEnabled(true);
- // session
- screenshotButton.setEnabled(false);
- actions.getResetAction().setEnabled(false);
- // settings
- actions.getNetworkConfigurationAction().setEnabled(true);
- actions.getCaptureEngineConfigurationAction().setEnabled(true);
- languageSelection.setEnabled(true);
- disableControls();
- clearFingerprints();
- getStatusBar().setMessage(translate("ready"));
- }
-
- void onHttpStarting(int port) {
- this.setCursor(Cursor.getDefaultCursor());
- // connection
- startButton.setVisible(false);
- actions.getStopAction().setEnabled(true);
- stopButton.setVisible(true);
- actions.getToggleCompatibilityModeAction().setEnabled(false);
- actions.getIpAddressAction().setEnabled(false);
- // settings
- actions.getNetworkConfigurationAction().setEnabled(false);
- languageSelection.setEnabled(false);
- clearFingerprints();
- getStatusBar().setMessage(translate("listening", port));
- }
-
- void onGettingReady() {
- this.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
- actions.getStartAction().setEnabled(false);
- showSpinner();
- }
-
- private void showSpinner() {
- center = new Spinner();
- add(center, BorderLayout.CENTER);
- }
-
- boolean onAccepted(Socket connection) {
- if (JOptionPane.showOptionDialog(this, translate("connection.incoming.msg1"),
- translate("connection.incoming", connection.getInetAddress().getHostAddress()), JOptionPane.OK_CANCEL_OPTION, JOptionPane.QUESTION_MESSAGE,
- getOrCreateIcon(ImageNames.USERS), okCancelOptions, okCancelOptions[1]) == 0) {
- return false;
- }
- hideSpinner();
- getStatusBar().setMessage(translate("connection.incoming.msg2", connection.getInetAddress().getHostAddress()));
- center = assistantPanelWrapper;
- add(center, BorderLayout.CENTER);
- screenshotButton.setEnabled(true);
- actions.getResetAction().setEnabled(true);
- actions.getTokenAction().setEnabled(false);
- enableControls();
- validate();
- repaint();
- return true;
- }
-
- void onClipboardRequested() {
- toggleTransferControls(false);
- }
-
- void onClipboardSending() {
- toggleTransferControls(false);
- }
-
- void onClipboardSent() {
- toggleTransferControls(true);
- }
-
- void onClipboardReceived() {
- toggleTransferControls(true);
- }
-
- void onSessionStarted(char osId, String inputLocale, int assistedMajorVersion) {
- this.osId = osId;
- if (osId == 'm') {
- windowsKeyToggleButton.setIcon(getOrCreateIcon(ImageNames.CMD));
- windowsKeyToggleButton.setToolTipText(translate("send.cmdKey"));
- } else {
- windowsKeyToggleButton.setIcon(getOrCreateIcon(ImageNames.WIN));
- windowsKeyToggleButton.setToolTipText(translate("send.winKey"));
- }
- if (Version.isOutdatedVersion(Version.get().getMajor(), assistedMajorVersion)) {
- String infoMessage = format("%s%n%s", translate("outdated.msg1"), translate("outdated.msg2"));
- JOptionPane.showMessageDialog(this, infoMessage, "", JOptionPane.INFORMATION_MESSAGE);
- }
- if (!inputLocale.isEmpty() && !inputLocale.equals(InputContext.getInstance().getLocale().toString())) {
- String infoMessage = format("%s%n%s%n%s", translate("keyboardlayout.msg1", inputLocale), translate("keyboardlayout.msg2"), translate("keyboardlayout.msg3"));
- JOptionPane.showMessageDialog(this, infoMessage, "", JOptionPane.INFORMATION_MESSAGE);
- }
- long sessionStartTime = Instant.now().getEpochSecond();
- sessionTimer = new Timer(1000, e -> {
- final long seconds = Instant.now().getEpochSecond() - sessionStartTime;
- getStatusBar().setSessionDuration(format("%02d:%02d:%02d", seconds / 3600, (seconds % 3600) / 60, seconds % 60));
- });
- sessionTimer.start();
- tabbedPane.setSelectedIndex(1);
- }
-
- void onDisconnecting() {
- stopSessionTimer();
- tabbedPane.setSelectedIndex(0);
- }
-
- void onTerminating() {
- actions.getStartAction().setEnabled(false);
- actions.getStopAction().setEnabled(false);
- actions.getResetAction().setEnabled(false);
- disableControls();
- stopSessionTimer();
- tabbedPane.setSelectedIndex(0);
- }
-
- void onIOError(IOException error) {
- onTerminating();
- hideSpinner();
- validate();
- repaint();
- String errorMessage = error.getMessage() != null ? translate("comm.error.msg1", translate(error.getMessage())) : translate("comm.error.msg1", "!");
- JOptionPane.showMessageDialog(this, errorMessage, translate("comm.error"), JOptionPane.ERROR_MESSAGE);
- }
-
- void computeScaleFactors(int sourceWidth, int sourceHeight, boolean keepAspectRatio) {
- canvas = assistantPanelWrapper.getSize();
- canvas.setSize(canvas.getWidth() - OFFSET, canvas.getHeight() - OFFSET);
- xFactor = canvas.getWidth() / sourceWidth;
- yFactor = canvas.getHeight() / sourceHeight;
- if (keepAspectRatio && !isImmutableWindowsSize.get() && abs(xFactor - yFactor) > 0.01) {
- resizeWindow(sourceWidth, sourceHeight);
- }
- }
-
- private void resizeWindow(int sourceWidth, int sourceHeight) {
- Log.debug("%s", () -> format("Resize W:H %s:%s x:y %s:%s", this.getWidth(), this.getHeight(), xFactor, yFactor));
- int menuHeight = this.getHeight() - canvas.height;
- final Rectangle maximumWindowBounds = GraphicsEnvironment.getLocalGraphicsEnvironment().getMaximumWindowBounds();
- if (xFactor < yFactor) {
- if ((sourceWidth * yFactor) + OFFSET < maximumWindowBounds.width) {
- xFactor = yFactor;
- Log.debug("Get wider");
- this.setSize((int) (sourceWidth * xFactor) + OFFSET, this.getHeight());
- } else {
- yFactor = xFactor;
- Log.debug("Get lower");
- this.setSize(this.getWidth(), (int) (sourceHeight * yFactor) + menuHeight + OFFSET);
- }
- } else {
- if ((sourceHeight * xFactor) + menuHeight + OFFSET < maximumWindowBounds.height) {
- yFactor = xFactor;
- Log.debug("Get higher");
- this.setSize(this.getWidth(), (int) (sourceHeight * yFactor) + menuHeight + OFFSET);
- } else {
- xFactor = yFactor;
- Log.debug("Get narrower");
- this.setSize((int) (sourceWidth * xFactor) + OFFSET, this.getHeight());
- }
- }
- Log.debug("%s", () -> format("Resized W:H %s:%s x:y %s:%s", this.getWidth(), this.getHeight(), xFactor, yFactor));
- }
-
- private void resetFactors() {
- xFactor = DEFAULT_FACTOR;
- yFactor = DEFAULT_FACTOR;
- }
-
- void resetCanvas() {
- canvas = null;
- }
-
- private void disableControls() {
- controlActivated.set(false);
- windowsKeyActivated.set(false);
- controlToggleButton.setEnabled(false);
- windowsKeyToggleButton.setEnabled(false);
- ctrlKeyToggleButton.setEnabled(false);
- toggleTransferControls(false);
- }
-
- private void toggleTransferControls(boolean enabled) {
- actions.getRemoteClipboardSetAction().setEnabled(enabled);
- actions.getRemoteClipboardRequestAction().setEnabled(enabled);
- }
-
- private void enableControls() {
- controlToggleButton.setSelected(false);
- controlToggleButton.setEnabled(true);
- windowsKeyToggleButton.setSelected(false);
- ctrlKeyToggleButton.setSelected(false);
- toggleTransferControls(true);
- }
-
- private void stopSessionTimer() {
- if (sessionTimer != null) {
- sessionTimer.stop();
- }
- }
-
- void hideSpinner() {
- if (center != null) {
- remove(center);
- }
- }
-
- void onCaptureUpdated(final BufferedImage captureImage) {
- assistantPanel.onCaptureUpdated(captureImage);
- }
-
- /**
- * Should not block as called from the network incoming message thread (!)
- */
- void onMouseLocationUpdated(int x, int y) {
- int xs = (int) Math.round(x * xFactor);
- int ys = (int) Math.round(y * yFactor);
- assistantPanel.onMouseLocationUpdated(xs, ys);
- }
-
- private void fireOnMouseMove(int x, int y) {
- listeners.getListeners().forEach(listener -> listener.onMouseMove(scaleXPosition(x), scaleYPosition(y)));
- }
-
- private void fireOnMousePressed(int x, int y, int button) {
- listeners.getListeners().forEach(listener -> listener.onMousePressed(scaleXPosition(x), scaleYPosition(y), button));
- }
-
- private void fireOnMouseReleased(int x, int y, int button) {
- listeners.getListeners().forEach(listener -> listener.onMouseReleased(scaleXPosition(x), scaleYPosition(y), button));
- }
-
- private void fireOnMouseWheeled(int x, int y, int rotations) {
- listeners.getListeners().forEach(listener -> listener.onMouseWheeled(scaleXPosition(x), scaleYPosition(y), rotations));
- }
-
- private int scaleYPosition(int y) {
- return (int) Math.round(y / yFactor);
- }
-
- private int scaleXPosition(int x) {
- return (int) Math.round(x / xFactor);
- }
-
- private void fireOnKeyPressed(int keyCode, char keyChar) {
- listeners.getListeners().forEach(listener -> listener.onKeyPressed(keyCode, keyChar));
- }
-
- private void fireOnKeyReleased(int keyCode, char keyChar) {
- listeners.getListeners().forEach(listener -> listener.onKeyReleased(keyCode, keyChar));
- }
-
- private static class Spinner extends JPanel {
- final ImageIcon waiting = getOrCreateIcon(ImageNames.WAITING);
-
- @Override
- protected void paintComponent(Graphics g) {
- super.paintComponent(g);
- final int x = (getWidth() - waiting.getIconWidth()) / 2;
- final int y = (getHeight() - waiting.getIconHeight()) / 2;
- g.drawImage(waiting.getImage(), x, y, this);
- }
- }
-}
diff --git a/src/main/java/mpo/dayon/assistant/gui/AssistantFrameListener.java b/src/main/java/mpo/dayon/assistant/gui/AssistantFrameListener.java
deleted file mode 100644
index 2a05afc3..00000000
--- a/src/main/java/mpo/dayon/assistant/gui/AssistantFrameListener.java
+++ /dev/null
@@ -1,17 +0,0 @@
-package mpo.dayon.assistant.gui;
-
-import mpo.dayon.common.event.Listener;
-
-public interface AssistantFrameListener extends Listener {
- void onMouseMove(int x, int y);
-
- void onMousePressed(int x, int y, int button);
-
- void onMouseReleased(int x, int y, int button);
-
- void onMouseWheeled(int x, int y, int rotations);
-
- void onKeyPressed(int keyCode, char keyChar);
-
- void onKeyReleased(int keyCode, char keyChar);
-}
diff --git a/src/main/java/mpo/dayon/assistant/gui/AssistantPanel.java b/src/main/java/mpo/dayon/assistant/gui/AssistantPanel.java
deleted file mode 100644
index c75c54a8..00000000
--- a/src/main/java/mpo/dayon/assistant/gui/AssistantPanel.java
+++ /dev/null
@@ -1,77 +0,0 @@
-package mpo.dayon.assistant.gui;
-
-import java.awt.Dimension;
-import java.awt.Graphics;
-import java.awt.Image;
-import java.awt.image.BufferedImage;
-
-import javax.swing.JPanel;
-import javax.swing.SwingUtilities;
-
-import static mpo.dayon.common.gui.common.ImageNames.MOUSE_YELLOW;
-import static mpo.dayon.common.gui.common.ImageUtilities.getOrCreateIcon;
-
-class AssistantPanel extends JPanel {
-
- private static final Image MOUSE_CURSOR = getOrCreateIcon(MOUSE_YELLOW).getImage();
-
- private static final int MOUSE_CURSOR_WIDTH = 12;
- private static final int MOUSE_CURSOR_HEIGHT = 20;
-
- private int captureWidth = -1;
- private int captureHeight = -1;
-
- private int mouseX = -1;
- private int mouseY = -1;
-
- private transient BufferedImage captureImage;
-
- AssistantPanel() {
- setOpaque(true);
- }
-
- @Override
- protected void paintComponent(Graphics g) {
- super.paintComponent(g);
- if (captureImage != null) {
- g.drawImage(captureImage, 0, 0, this);
- }
- paintMouse(g);
- }
-
- private void paintMouse(Graphics g) {
- if (mouseX > -1 && mouseY > -1) {
- g.drawImage(MOUSE_CURSOR, mouseX, mouseY, this);
- }
- }
-
- /**
- * Called from within the de-compressor engine thread (!)
- */
- void onCaptureUpdated(final BufferedImage captureImage) {
- SwingUtilities.invokeLater(() -> {
- final int captureImageWidth = captureImage.getWidth();
- final int captureImageHeight = captureImage.getHeight();
- if (captureWidth != captureImageWidth || captureHeight != captureImageHeight) {
- this.captureWidth = captureImageWidth;
- this.captureHeight = captureImageHeight;
- final Dimension size = new Dimension(captureImageWidth, captureImageHeight);
- setSize(size);
- setPreferredSize(size);
- }
- this.captureImage = captureImage;
- repaint();
- });
- }
-
- void onMouseLocationUpdated(final int x, final int y) {
- SwingUtilities.invokeLater(() -> {
- if (this.mouseX > -1 && this.mouseY > -1) {
- repaint(this.mouseX, this.mouseY, MOUSE_CURSOR_WIDTH, MOUSE_CURSOR_HEIGHT);
- }
- this.mouseX = x;
- this.mouseY = y;
- repaint(x, y, MOUSE_CURSOR_WIDTH, MOUSE_CURSOR_HEIGHT);
- });
- }
-}
diff --git a/src/main/java/mpo/dayon/assistant/gui/RepeatingReleasedEventsFixer.java b/src/main/java/mpo/dayon/assistant/gui/RepeatingReleasedEventsFixer.java
deleted file mode 100644
index 9d315114..00000000
--- a/src/main/java/mpo/dayon/assistant/gui/RepeatingReleasedEventsFixer.java
+++ /dev/null
@@ -1,229 +0,0 @@
-package mpo.dayon.assistant.gui;
-
-import javax.swing.*;
-import java.awt.*;
-import java.awt.event.AWTEventListener;
-import java.awt.event.ActionEvent;
-import java.awt.event.ActionListener;
-import java.awt.event.KeyEvent;
-import java.util.HashMap;
-import java.util.Map;
-
-/**
- * From the original @author Endre Stølsvik:
- *
- * This {@link AWTEventListener} tries to work around a 12 yo
- * bug in the Linux KeyEvent handling for keyboard repeat. Linux apparently implements repeating keypresses by
- * repeating both the {@link KeyEvent#KEY_PRESSED} and {@link KeyEvent#KEY_RELEASED}, while on Windows, one only
- * gets repeating PRESSES, and then a final RELEASE when the key is released. The Windows way is obviously much more
- * useful, as one then can easily distinguish between a user holding a key pressed, and a user hammering away on the
- * key.
- *
- * This class is an {@link AWTEventListener} that should be installed as the application's first ever
- * {@link AWTEventListener} using the following code, but it is simpler to invoke {@link #install() install(new
- * instance)}:
- *
- *
- *
- * Toolkit.getDefaultToolkit().addAWTEventListener(new {@link RepeatingReleasedEventsFixer}, AWTEvent.KEY_EVENT_MASK);
- *
- *
- *
- *
- * Remember to remove it and any other installed {@link AWTEventListener} if your application have some "reboot"
- * functionality that can potentially install it again - or else you'll end up with multiple instances, which isn't too
- * hot.
- *
- * Notice: Read up on the {@link Reposted} interface if you have other AWTEventListeners that resends KeyEvents
- * (as this one does) - or else we'll get the event back.
- *
- *
- *
- * Mode of operation
- *
- * The class makes use of the fact that the subsequent PRESSED event comes right after the RELEASED event - one thus
- * have a sequence like this:
- *
- *
- *
- * PRESSED
- * -wait between key repeats-
- * RELEASED
- * PRESSED
- * -wait between key repeats-
- * RELEASED
- * PRESSED
- * etc.
- *
- *
- *
- *
- * A timer is started when receiving a RELEASED event, and if a PRESSED comes soon afterwards, the RELEASED is dropped
- * (consumed) - while if the timer times out, the event is reposted and thus becomes the final, wanted RELEASED that
- * denotes that the key actually was released.
- *
- * Inspired by http://www.arco.in-berlin.de/keyevent.html
- *
- * @author Endre Stølsvik
- *
- * Refactored by Reto Galante into a proper Singleton, so you may ignore the remove method, if you are instantiating it
- * as such by calling RepeatingReleasedEventsFixer.install();
- *
- */
-
-public final class RepeatingReleasedEventsFixer implements AWTEventListener {
-
- private final Map map = new HashMap<>();
-
- private static RepeatingReleasedEventsFixer instance;
-
- private RepeatingReleasedEventsFixer() {
- // singleton
- }
-
- public static RepeatingReleasedEventsFixer install() {
- synchronized (RepeatingReleasedEventsFixer.class) {
- if (instance == null) {
- final RepeatingReleasedEventsFixer fixer = new RepeatingReleasedEventsFixer();
- Toolkit.getDefaultToolkit().addAWTEventListener(fixer, AWTEvent.KEY_EVENT_MASK);
- instance = fixer;
- }
- }
- return instance;
- }
-
- public static void remove() {
- if (instance != null) {
- Toolkit.getDefaultToolkit().removeAWTEventListener(instance);
- }
- }
-
- @Override
- public void eventDispatched(AWTEvent event) {
- if (!(event instanceof KeyEvent)) {
- throw new AssertionError("Shall only listen to KeyEvents, so no other events shall come here");
- }
- assert assertEDT(); // REMEMBER THAT THIS IS SINGLE THREADED, so no need for synch.
-
- // ?: Is this one of our synthetic RELEASED events?
- if (event instanceof Reposted) {
- // -> Yes, so we shalln't process it again.
- return;
- }
-
- // ?: KEY_TYPED event? (We're only interested in KEY_PRESSED and KEY_RELEASED).
- if (event.getID() == KeyEvent.KEY_TYPED) {
- // -> Yes, TYPED, don't process.
- return;
- }
-
- final KeyEvent keyEvent = (KeyEvent) event;
-
- // ?: Is this already consumed?
- // (Note how events are passed on to all AWTEventListeners even though a previous one consumed it)
- if (keyEvent.isConsumed()) {
- return;
- }
-
- // ?: Is this RELEASED? (the problem we're trying to fix!)
- if (keyEvent.getID() == KeyEvent.KEY_RELEASED) {
- // -> Yes, so stick in wait
- /*
- * Really just wait until "immediately", as the point is that the subsequent PRESSED shall already have been
- * posted on the event queue, and shall thus be the direct next event no matter which events are posted
- * afterwards. The code with the ReleasedAction handles if the Timer thread actually fires the action due to
- * lags, by cancelling the action itself upon the PRESSED.
- */
- final Timer timer = new Timer(2, null);
- ReleasedAction action = new ReleasedAction(keyEvent, timer);
- timer.addActionListener(action);
- timer.start();
-
- map.put(keyEvent.getKeyCode(), action);
-
- // Consume the original
- keyEvent.consume();
- } else if (keyEvent.getID() == KeyEvent.KEY_PRESSED) {
- // Remember that this is single threaded (EDT), so we can't have races.
- ReleasedAction action = map.remove(keyEvent.getKeyCode());
- // ?: Do we have a corresponding RELEASED waiting?
- if (action != null) {
- // -> Yes, so dump it
- action.cancel();
- }
- // System.out.println("PRESSED: [" + keyEvent + "]");
- } else {
- throw new AssertionError("All IDs should be covered.");
- }
- }
-
- /**
- * The ActionListener that posts the RELEASED {@link RepostedKeyEvent} if the {@link Timer} times out (and hence the
- * repeat-action was over).
- */
- private class ReleasedAction implements ActionListener {
-
- private final KeyEvent originalKeyEvent;
- private Timer timer;
-
- ReleasedAction(KeyEvent originalReleased, Timer timer) {
- this.timer = timer;
- originalKeyEvent = originalReleased;
- }
-
- void cancel() {
- assert assertEDT();
- timer.stop();
- timer = null;
- map.remove(originalKeyEvent.getKeyCode());
- }
-
- @Override
- public void actionPerformed(@SuppressWarnings("unused") ActionEvent e) {
- assert assertEDT();
- // ?: Are we already cancelled?
- // (Judging by Timer and TimerQueue code, we can theoretically be raced to be posted onto EDT by TimerQueue,
- // due to some lag, unfair scheduling)
- if (timer == null) {
- // -> Yes, so don't post the new RELEASED event.
- return;
- }
- // Stop Timer and clean.
- cancel();
- // Creating new KeyEvent (we've consumed the original).
- KeyEvent newEvent = new RepostedKeyEvent((Component) originalKeyEvent.getSource(),
- originalKeyEvent.getID(), originalKeyEvent.getWhen(), originalKeyEvent.getModifiersEx(),
- originalKeyEvent.getKeyCode(), originalKeyEvent.getKeyChar(), originalKeyEvent.getKeyLocation());
- // Posting to EventQueue.
- Toolkit.getDefaultToolkit().getSystemEventQueue().postEvent(newEvent);
- // System.out.println("Posted synthetic RELEASED [" + newEvent + "].");
- }
- }
-
- /**
- * Marker interface that denotes that the {@link KeyEvent} in question is reposted from some
- * {@link AWTEventListener}, including this. It denotes that the event shall not be "hack processed" by this class
- * again. (The problem is that it is not possible to state "inject this event from this point in the pipeline" - one
- * have to inject it to the event queue directly, thus it will come through this {@link AWTEventListener} too.
- */
- private interface Reposted {
- // marker
- }
-
- /**
- * Dead simple extension of {@link KeyEvent} that implements {@link Reposted}.
- */
- static class RepostedKeyEvent extends KeyEvent implements Reposted {
- RepostedKeyEvent(@SuppressWarnings("hiding") Component source, @SuppressWarnings("hiding") int id,
- long when, int modifiers, int keyCode, char keyChar, int keyLocation) {
- super(source, id, when, modifiers, keyCode, keyChar, keyLocation);
- }
- }
-
- private static boolean assertEDT() {
- if (!EventQueue.isDispatchThread()) {
- throw new AssertionError("Not EDT, but [" + Thread.currentThread() + "].");
- }
- return true;
- }
-}
diff --git a/src/main/java/mpo/dayon/assistant/network/NetworkAssistantEngine.java b/src/main/java/mpo/dayon/assistant/network/NetworkAssistantEngine.java
deleted file mode 100644
index 94dfbece..00000000
--- a/src/main/java/mpo/dayon/assistant/network/NetworkAssistantEngine.java
+++ /dev/null
@@ -1,392 +0,0 @@
-package mpo.dayon.assistant.network;
-
-//import com.dosse.upnp.UPnP;
-import mpo.dayon.common.compressor.CompressorEngineConfiguration;
-import mpo.dayon.common.capture.CaptureEngineConfiguration;
-import mpo.dayon.common.concurrent.RunnableEx;
-import mpo.dayon.common.configuration.ReConfigurable;
-import mpo.dayon.common.event.Listeners;
-import mpo.dayon.common.log.Log;
-import mpo.dayon.common.network.NetworkEngine;
-import mpo.dayon.common.network.message.*;
-import mpo.dayon.common.security.CustomTrustManager;
-import mpo.dayon.common.version.Version;
-
-import javax.net.ssl.SSLServerSocket;
-import javax.net.ssl.SSLServerSocketFactory;
-import javax.net.ssl.SSLSocket;
-import java.awt.*;
-import java.awt.datatransfer.ClipboardOwner;
-import java.awt.datatransfer.DataFlavor;
-import java.io.*;
-import java.net.Socket;
-import java.security.KeyManagementException;
-import java.security.NoSuchAlgorithmException;
-import java.security.cert.CertificateEncodingException;
-
-import static java.lang.String.format;
-import static mpo.dayon.common.utils.SystemUtilities.safeClose;
-import static mpo.dayon.common.version.Version.isColoredVersion;
-import static mpo.dayon.common.version.Version.isCompatibleVersion;
-
-public class NetworkAssistantEngine extends NetworkEngine implements ReConfigurable {
-
- private final NetworkCaptureMessageHandler captureMessageHandler;
-
- private final NetworkMouseLocationMessageHandler mouseMessageHandler;
-
- private final ClipboardOwner clipboardOwner;
-
- private final Listeners listeners = new Listeners<>();
-
- private NetworkAssistantEngineConfiguration configuration;
-
- private SSLServerSocketFactory ssf;
-
- private static final String APP_NAME = "Dayon!";
-
- public NetworkAssistantEngine(NetworkCaptureMessageHandler captureMessageHandler, NetworkMouseLocationMessageHandler mouseMessageHandler, ClipboardOwner clipboardOwner) {
- this.captureMessageHandler = captureMessageHandler;
- this.mouseMessageHandler = mouseMessageHandler;
- this.clipboardOwner = clipboardOwner;
- fireOnReady();
- }
-
- @Override
- public void configure(NetworkAssistantEngineConfiguration configuration) {
- this.configuration = configuration;
- }
-
- @Override
- public void reconfigure(NetworkAssistantEngineConfiguration configuration) {
- this.configuration = configuration;
- }
-
- public void addListener(NetworkAssistantEngineListener listener) {
- listeners.add(listener);
- }
-
- /**
- * Called from a GUI action => do not block the AWT thread (!)
- */
- public void start(boolean compatibilityMode) {
- if (cancelling.get() || receiver != null) {
- return;
- }
-// if (UPnP.isUPnPAvailable() && !UPnP.isMappedTCP(configuration.getPort())) {
-// UPnP.openPortTCP(configuration.getPort(), APP_NAME);
-// }
- receiver = new Thread(new RunnableEx() {
- @Override
- protected void doRun() throws NoSuchAlgorithmException, KeyManagementException {
- NetworkAssistantEngine.this.receivingLoop(compatibilityMode);
- }
- }, "NetworkReceiver");
- receiver.start();
- }
-
- /**
- * Called from a GUI action => do not block the AWT thread (!)
- */
- public void cancel() {
- Log.info("Cancelling the network assistant engine...");
- cancelling.set(true);
- safeClose(server, connection, fileServer, fileConnection);
- fireOnDisconnecting();
- }
-
- public void manageRouterPorts(int oldPort, int newPort) {
-// if (UPnP.isUPnPAvailable()) {
-// UPnP.closePortTCP(oldPort);
-// UPnP.openPortTCP(newPort, APP_NAME);
-// }
- }
-
- // right, keep streams open - forever!
- @java.lang.SuppressWarnings({"squid:S2189", "squid:S2093"})
- private void receivingLoop(boolean compatibilityMode) throws NoSuchAlgorithmException, KeyManagementException {
- in = null;
- boolean introduced = false;
- boolean proceed = true;
-
- try {
- awaitConnections(compatibilityMode);
- startFileReceiver();
- initSender(8);
- initInputStream();
-
- while (proceed) {
- NetworkMessage.unmarshallMagicNumber(in); // blocking read (!)
- NetworkMessageType type = NetworkMessage.unmarshallEnum(in, NetworkMessageType.class);
- Log.debug("Received %s", type::name);
-
- if (introduced) {
- proceed = processIntroduced(type, in);
- } else {
- introduced = processUnIntroduced(type, in);
- }
- }
- } catch (IOException ex) {
- handleIOException(ex);
- } catch (CertificateEncodingException ex) {
- Log.error(ex.getMessage());
- } catch (ClassNotFoundException e) {
- throw new IllegalArgumentException(e);
- } finally {
- closeConnections();
- //UPnP.closePortTCP(configuration.getPort());
- fireOnReady();
- }
-
- }
-
- private void awaitConnections(boolean compatibilityMode) throws NoSuchAlgorithmException, IOException, KeyManagementException, CertificateEncodingException {
- fireOnStarting(configuration.getPort());
- ssf = CustomTrustManager.initSslContext(compatibilityMode).getServerSocketFactory();
- Log.info(format("Dayon! server [port:%d]", configuration.getPort()));
- if (compatibilityMode) {
- Log.warn("Compatibility mode enabled, using legacy certificate");
- }
- if (server != null && server.isBound()) {
- safeClose(server);
- }
- server = (SSLServerSocket) ssf.createServerSocket(configuration.getPort());
- server.setNeedClientAuth(true);
- Log.info("Accepting...");
-
- do {
- if (connection != null && connection.isBound()) {
- safeClose(connection); // we might have refused the accepted connection (!)
- }
- connection = (SSLSocket) server.accept();
- Toolkit.getDefaultToolkit().beep();
- if (!connection.getSession().isValid()) {
- fireOnFingerprinted(null);
- throw new IOException("Certificate error, try enabling compatibility mode!");
- }
- fireOnFingerprinted(CustomTrustManager.calculateFingerprints(connection.getSession(), this.getClass().getSimpleName()));
- Log.info(format("Incoming connection from %s", connection.getInetAddress().getHostAddress()));
- } while (!fireOnAccepted(connection) && !cancelling.get());
-
- if (server.isBound()) {
- safeClose(server);
- }
- server = null;
- }
-
- private void startFileReceiver() {
- fileReceiver = new Thread(new RunnableEx() {
- @Override
- protected void doRun() {
- NetworkAssistantEngine.this.fileReceivingLoop();
- }
- }, "FileReceiver");
-
- fileReceiver.start();
- }
-
- // right, keep streams open - forever!
- @java.lang.SuppressWarnings({"squid:S2189", "squid:S2093"})
- private void fileReceivingLoop() {
- fileIn = null;
- Log.info(format("Dayon! file server [port:%d]", configuration.getPort()));
-
- try {
- fileServer = (SSLServerSocket) ssf.createServerSocket(configuration.getPort());
- fileConnection = (SSLSocket) fileServer.accept();
- initFileSender();
- fileIn = new ObjectInputStream(new BufferedInputStream(fileConnection.getInputStream()));
-
- handleIncomingClipboardFiles(fileIn, clipboardOwner);
- } catch (IOException ex) {
- closeConnections();
- }
- }
-
- private boolean processIntroduced(NetworkMessageType type, ObjectInputStream in) throws IOException, ClassNotFoundException {
- switch (type) {
- case CAPTURE:
- final NetworkCaptureMessage capture = NetworkCaptureMessage.unmarshall(in);
- fireOnByteReceived(1 + capture.getWireSize()); // +1 : magic number (byte)
- captureMessageHandler.handleCapture(capture);
- return true;
-
- case MOUSE_LOCATION:
- final NetworkMouseLocationMessage mouse = NetworkMouseLocationMessage.unmarshall(in);
- fireOnByteReceived(1 + mouse.getWireSize()); // +1 : magic number (byte)
- mouseMessageHandler.handleLocation(mouse);
- return true;
-
- case CLIPBOARD_TEXT:
- final NetworkClipboardTextMessage clipboardTextMessage = NetworkClipboardTextMessage.unmarshall(in);
- fireOnByteReceived(1 + clipboardTextMessage.getWireSize()); // +1 : magic number (byte)
- setClipboardContents(clipboardTextMessage.getText(), clipboardOwner);
- fireOnClipboardReceived();
- return true;
-
- case CLIPBOARD_GRAPHIC:
- final NetworkClipboardGraphicMessage clipboardGraphicMessage = NetworkClipboardGraphicMessage.unmarshall(in);
- fireOnByteReceived(1 + clipboardGraphicMessage.getWireSize()); // +1 : magic number (byte)
- setClipboardContents(clipboardGraphicMessage.getGraphic().getTransferData(DataFlavor.imageFlavor), clipboardOwner);
- fireOnClipboardReceived();
- return true;
-
- case PING:
- fireOnClipboardSent();
- return true;
-
- case RESIZE:
- final NetworkResizeScreenMessage resize = NetworkResizeScreenMessage.unmarshall(in);
- fireOnByteReceived(1 + resize.getWireSize()); // +1 : magic number (byte)
- fireOnResizeScreen(resize.getWidth(), resize.getHeight());
- return true;
-
- case GOODBYE:
- fireOnTerminating();
- return false;
-
- case HELLO:
- throw new IllegalArgumentException("Unexpected message [HELLO]!");
-
- default:
- throw new IllegalArgumentException(format(UNSUPPORTED_TYPE, type));
- }
- }
-
- private boolean processUnIntroduced(NetworkMessageType type, ObjectInputStream in) throws IOException {
- switch (type) {
- case HELLO:
- fireOnConnected(connection, introduce(in));
- return true;
-
- case PING:
- return false;
-
- case CAPTURE:
- case MOUSE_LOCATION:
- case CLIPBOARD_TEXT:
- case CLIPBOARD_GRAPHIC:
- case CLIPBOARD_FILES:
- case GOODBYE:
- throw new IllegalArgumentException(format("Unexpected message [%s]!", type.name()));
-
- default:
- throw new IllegalArgumentException(format(UNSUPPORTED_TYPE, type));
- }
- }
-
- private NetworkHelloMessage introduce(ObjectInputStream in) throws IOException {
- final NetworkHelloMessage hello = NetworkHelloMessage.unmarshall(in);
- fireOnByteReceived(1 + hello.getWireSize()); // +1 : magic number (byte)
- if (!isCompatibleVersion(hello.getMajor(), hello.getMinor(), Version.get())) {
- Log.error(format("Incompatible assisted version: %d.%d", hello.getMajor(), hello.getMinor()));
- throw new IOException("version.wrong");
- }
- configuration.setMonochromePeer(!isColoredVersion(hello.getMajor()));
- return hello;
- }
-
- /**
- * Might be blocking if the sender queue is full (!)
- */
- public void sendCaptureConfiguration(CaptureEngineConfiguration configuration) {
- if (sender != null) {
- sender.sendCaptureConfiguration(configuration, this.configuration.isMonochromePeer());
- }
- }
-
- /**
- * Might be blocking if the sender queue is full (!)
- */
- public void sendCompressorConfiguration(CompressorEngineConfiguration configuration) {
- if (sender != null) {
- sender.sendCompressorConfiguration(configuration);
- }
- }
-
- /**
- * Might be blocking if the sender queue is full (!)
- */
- public void sendMouseControl(NetworkMouseControlMessage message) {
- if (sender != null) {
- sender.sendMouseControl(message);
- }
- }
-
- /**
- * Might be blocking if the sender queue is full (!)
- */
- public void sendKeyControl(NetworkKeyControlMessage message) {
- if (sender != null) {
- sender.sendKeyControl(message);
- }
- }
-
- /**
- * Might be blocking if the sender queue is full (!)
- */
- public void sendRemoteClipboardRequest() {
- if (sender != null) {
- sender.sendRemoteClipboardRequest();
- }
- }
-
- /**
- * Might be blocking if the sender queue is full (!)
- */
- public void sendScreenshotRequest() {
- if (sender != null) {
- sender.sendScreenshotRequest();
- }
- }
-
- private void fireOnReady() {
- listeners.getListeners().forEach(NetworkAssistantEngineListener::onReady);
- }
-
- private void fireOnStarting(int port) {
- listeners.getListeners().forEach(listener -> listener.onStarting(port));
- }
-
- private boolean fireOnAccepted(Socket connection) {
- return listeners.getListeners().stream().allMatch(listener -> listener.onAccepted(connection));
- }
-
- private void fireOnConnected(Socket connection, NetworkHelloMessage hello) {
- listeners.getListeners().forEach(listener -> listener.onConnected(connection, hello.getOsId(), hello.getInputLocale(), hello.getMajor()));
- }
-
- private void fireOnByteReceived(int count) {
- listeners.getListeners().forEach(listener -> listener.onByteReceived(count));
- }
-
- @Override
- protected void fireOnClipboardReceived() {
- listeners.getListeners().forEach(NetworkAssistantEngineListener::onClipboardReceived);
- }
-
- private void fireOnClipboardSent() {
- listeners.getListeners().forEach(NetworkAssistantEngineListener::onClipboardSent);
- }
-
- private void fireOnResizeScreen(int width, int height) {
- listeners.getListeners().forEach(listener -> listener.onResizeScreen(width, height));
- }
-
- private void fireOnDisconnecting() {
- listeners.getListeners().forEach(NetworkAssistantEngineListener::onDisconnecting);
- }
-
- private void fireOnTerminating() {
- listeners.getListeners().forEach(NetworkAssistantEngineListener::onTerminating);
- }
-
- @Override
- protected void fireOnIOError(IOException error) {
- listeners.getListeners().forEach(listener -> listener.onIOError(error));
- }
-
- private void fireOnFingerprinted(String fingerprints) {
- listeners.getListeners().forEach(listener -> listener.onFingerprinted(fingerprints));
- }
-}
diff --git a/src/main/java/mpo/dayon/assistant/network/NetworkAssistantEngineConfiguration.java b/src/main/java/mpo/dayon/assistant/network/NetworkAssistantEngineConfiguration.java
deleted file mode 100644
index ca47fe91..00000000
--- a/src/main/java/mpo/dayon/assistant/network/NetworkAssistantEngineConfiguration.java
+++ /dev/null
@@ -1,89 +0,0 @@
-package mpo.dayon.assistant.network;
-
-import mpo.dayon.common.configuration.Configuration;
-import mpo.dayon.common.preference.Preferences;
-
-import java.util.Objects;
-
-import static mpo.dayon.common.utils.SystemUtilities.DEFAULT_TOKEN_SERVER_URL;
-
-public class NetworkAssistantEngineConfiguration extends Configuration {
- private static final String PREF_VERSION = "assistant.network.version";
-
- private static final String PREF_PORT_NUMBER = "assistant.network.portNumber";
-
- private static final String PREF_TOKEN_SERVER_URL = "assistant.network.tokenServerUrl";
-
- private final int port;
-
- private final String tokenServerUrl;
-
- private boolean monochromePeer = false;
-
- /**
- * Default : takes its values from the current preferences.
- */
- public NetworkAssistantEngineConfiguration() {
- port = Preferences.getPreferences().getIntPreference(PREF_PORT_NUMBER, 8080);
- tokenServerUrl = Preferences.getPreferences().getStringPreference(PREF_TOKEN_SERVER_URL, DEFAULT_TOKEN_SERVER_URL);
- }
-
- public NetworkAssistantEngineConfiguration(int port, String tokenServerUrl) {
- this.port = port;
- this.tokenServerUrl = tokenServerUrl;
- }
-
- public int getPort() {
- return port;
- }
-
- public String getTokenServerUrl() {
- return tokenServerUrl;
- }
-
- public boolean isMonochromePeer() {
- return monochromePeer;
- }
-
- public void setMonochromePeer(boolean monochromePeer) {
- this.monochromePeer = monochromePeer;
- }
-
- @Override
- public boolean equals(Object o) {
- if (this == o) {
- return true;
- }
- if (o == null || getClass() != o.getClass()) {
- return false;
- }
-
- final NetworkAssistantEngineConfiguration that = (NetworkAssistantEngineConfiguration) o;
-
- return port == that.getPort() && tokenServerUrl.equals(that.getTokenServerUrl());
- }
-
- @Override
- public int hashCode() {
- return Objects.hash(port, tokenServerUrl);
- }
-
- /**
- * @param clear
- * allows for clearing properties from previous version
- */
- @Override
- protected void persist(boolean clear) {
- final Preferences.Props props = new Preferences.Props();
- props.set(PREF_VERSION, String.valueOf(1));
- props.set(PREF_PORT_NUMBER, String.valueOf(port));
- props.set(PREF_TOKEN_SERVER_URL, tokenServerUrl);
-
- if (clear) // migration support (!)
- {
- props.clear("assistantPortNumber");
- }
- Preferences.getPreferences().update(props); // atomic (!)
- }
-
-}
diff --git a/src/main/java/mpo/dayon/assistant/network/NetworkAssistantEngineListener.java b/src/main/java/mpo/dayon/assistant/network/NetworkAssistantEngineListener.java
deleted file mode 100644
index 21e6af80..00000000
--- a/src/main/java/mpo/dayon/assistant/network/NetworkAssistantEngineListener.java
+++ /dev/null
@@ -1,56 +0,0 @@
-package mpo.dayon.assistant.network;
-
-import java.io.IOException;
-import java.net.Socket;
-
-import mpo.dayon.common.event.Listener;
-
-public interface NetworkAssistantEngineListener extends Listener {
- void onReady();
-
- /**
- * Should not block as called from the network receiving thread (!)
- */
- void onStarting(int port);
-
- /**
- * Should not block as called from the network receiving thread (!)
- */
- boolean onAccepted(Socket connection);
-
- /**
- * Should not block as called from the network receiving thread (!)
- */
- void onConnected(Socket connection, char osId, String inputLocale, int peerMajorVersion);
-
- /**
- * Should not block as called from the network receiving thread (!)
- */
- void onByteReceived(int count);
-
- /**
- * Should not block as called from the network receiving thread (!)
- */
- void onClipboardReceived();
-
- /**
- * Should not block as called from the network receiving thread (!)
- */
- void onClipboardSent();
-
- /**
- * Should not block as called from the network receiving thread (!)
- */
- void onResizeScreen(int width, int height);
-
- /**
- * Should not block as called from the network receiving thread (!)
- */
- void onDisconnecting();
-
- void onTerminating();
-
- void onIOError(IOException error);
-
- void onFingerprinted(String fingerprints);
-}
diff --git a/src/main/java/mpo/dayon/assistant/utils/NetworkUtilities.java b/src/main/java/mpo/dayon/assistant/utils/NetworkUtilities.java
deleted file mode 100644
index b52ead55..00000000
--- a/src/main/java/mpo/dayon/assistant/utils/NetworkUtilities.java
+++ /dev/null
@@ -1,42 +0,0 @@
-package mpo.dayon.assistant.utils;
-
-import java.net.InetAddress;
-import java.net.NetworkInterface;
-import java.net.SocketException;
-import java.util.ArrayList;
-import java.util.Enumeration;
-import java.util.List;
-
-import mpo.dayon.common.log.Log;
-
-public interface NetworkUtilities {
- static List getInetAddresses() {
- final List addresses = new ArrayList<>();
-
- try {
- InetAddress loopback = null;
-
- final Enumeration nintfs = NetworkInterface.getNetworkInterfaces();
- while (nintfs.hasMoreElements()) {
- final Enumeration inetAddresses = nintfs.nextElement().getInetAddresses();
- while (inetAddresses.hasMoreElements()) {
- final InetAddress inetAddress = inetAddresses.nextElement();
- if (!inetAddress.isLoopbackAddress()) {
- addresses.add(inetAddress.getHostAddress());
- } else {
- loopback = inetAddress;
- }
- }
- }
-
- if (loopback != null) {
- addresses.add(loopback.getHostAddress());
- }
- } catch (SocketException ex) {
- Log.warn("Inet Addresses error!", ex);
- }
-
- return addresses;
- }
-
-}
diff --git a/src/main/java/mpo/dayon/assisted/gui/AssistedFrame.java b/src/main/java/mpo/dayon/assisted/gui/AssistedFrame.java
index 39fbb899..12a1c496 100755
--- a/src/main/java/mpo/dayon/assisted/gui/AssistedFrame.java
+++ b/src/main/java/mpo/dayon/assisted/gui/AssistedFrame.java
@@ -33,7 +33,7 @@ class AssistedFrame extends BaseFrame {
this.startAction = startAction;
this.startButton = createButton(this.startAction);
this.stopButton = createButton(this.stopAction, false);
- this.connectionSettingsButton = createButton(createConnectionSettingsAction(null));
+ this.connectionSettingsButton = createButton(createConnectionSettingsAction());
this.toggleMultiScreenCaptureAction = toggleMultiScreenCaptureAction;
setupToolBar(createToolBar());
setupStatusBar(createStatusBar());
diff --git a/src/main/java/mpo/dayon/common/gui/common/BaseFrame.java b/src/main/java/mpo/dayon/common/gui/common/BaseFrame.java
index c7fc0ae9..84907cf3 100644
--- a/src/main/java/mpo/dayon/common/gui/common/BaseFrame.java
+++ b/src/main/java/mpo/dayon/common/gui/common/BaseFrame.java
@@ -10,6 +10,7 @@
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.time.Duration;
+import java.util.Locale;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.CompletableFuture;
import java.util.regex.Pattern;
@@ -17,10 +18,6 @@
import javax.swing.*;
import javax.swing.border.EmptyBorder;
-import com.dosse.upnp.UPnP;
-import mpo.dayon.assistant.gui.Assistant;
-import mpo.dayon.assistant.network.NetworkAssistantEngine;
-import mpo.dayon.assistant.network.NetworkAssistantEngineConfiguration;
import mpo.dayon.assisted.network.NetworkAssistedEngineConfiguration;
import mpo.dayon.common.gui.statusbar.StatusBar;
import mpo.dayon.common.gui.toolbar.ToolBar;
@@ -99,7 +96,6 @@ private void doExit() {
protected void setFrameType(FrameType frameType) {
this.frameType = frameType;
setupWindow();
- setTitle(format("Dayon! (%s) %s", translate(frameType.getPrefix()), Version.get()));
}
private void setupWindow() {
@@ -110,8 +106,18 @@ private void setupWindow() {
this.position = new Position(configuration.getX() + dimension.width < maximumWindowBounds.width ? configuration.getX() : (maximumWindowBounds.width - dimension.width) / 2,
configuration.getY() + dimension.height < maximumWindowBounds.height ? configuration.getY() : (maximumWindowBounds.height - dimension.height) / 2);
this.setSize(dimension.width, dimension.height);
- setTitle(format("Fensterkitt Support App %s", Version.get()));
- this.setLocation(position.getX(), position.getY());
+ String titleString = "Fensterkitt Support App";
+ updateTitle(titleString, Version.get());
+ }
+
+ private void updateTitle(String titleString, Version version) {
+ setTitle(titleString, version);
+ new Timer(5000, e -> setTitle(titleString, version)).start();
+ }
+
+ private void setTitle(String titleString, Version version) {
+ Locale locale = InputContext.getInstance().getLocale();
+ setTitle(format("%s %s %s", titleString, version, locale != null ? locale.toString() : ""));
}
protected void setupToolBar(ToolBar toolBar) {
@@ -121,12 +127,7 @@ protected void setupToolBar(ToolBar toolBar) {
fingerprints.setBorder(BorderFactory.createEmptyBorder(0, 10, 35, 0));
}
toolBar.add(fingerprints);
- //toolBar.addAction(createShowInfoAction(), alignmentY);
- //toolBar.addAction(createShowHelpAction(), alignmentY);
toolBar.addAction(createExitAction(), alignmentY);
- if (FrameType.ASSISTANT.equals(frameType)) {
- toolBar.add(DEFAULT_SPACER);
- }
add(toolBar, BorderLayout.NORTH);
toolBar.setBorder(BorderFactory.createEmptyBorder(0, 10, 0, 10));
this.toolBar = toolBar;
@@ -275,7 +276,7 @@ public void actionPerformed(ActionEvent ev) {
return showSystemInfo;
}
- protected Action createConnectionSettingsAction(Assistant assistant) {
+ protected Action createConnectionSettingsAction() {
final Action conf = new AbstractAction() {
@Override
public void actionPerformed(ActionEvent ev) {
@@ -287,7 +288,7 @@ public void actionPerformed(ActionEvent ev) {
final ButtonGroup tokenRadioGroup = new ButtonGroup();
final JTextField customTokenTextField = new JTextField();
- JPanel panel = createPanel(addressTextField, portNumberTextField, autoConnectCheckBox, tokenRadioGroup, customTokenTextField, (assistant != null && assistant.isUpnpEnabled()));
+ JPanel panel = createPanel(addressTextField, portNumberTextField, autoConnectCheckBox, tokenRadioGroup, customTokenTextField, false);
final boolean ok = DialogFactory.showOkCancel(networkFrame, translate("connection.network"), panel, true,
() -> validateInputFields(addressTextField, portNumberTextField, tokenRadioGroup, customTokenTextField));
@@ -296,11 +297,7 @@ public void actionPerformed(ActionEvent ev) {
final String newTokenServerUrl = tokenRadioGroup.getSelection().getActionCommand().equals(CUSTOM) &&
isValidUrl(customTokenTextField.getText()) ? customTokenTextField.getText() : "";
updateSystemProperty(newTokenServerUrl);
- if (assistant == null) {
- updateAssistedNetworkConfiguration(addressTextField, portNumberTextField, autoConnectCheckBox, newTokenServerUrl);
- } else {
- updateAssistantNetworkConfiguration(portNumberTextField, newTokenServerUrl, assistant.getNetworkEngine());
- }
+ updateAssistedNetworkConfiguration(addressTextField, portNumberTextField, autoConnectCheckBox, newTokenServerUrl);
}
}
};
@@ -318,7 +315,6 @@ private JPanel createPanel(JTextField addressTextField, JTextField portNumberTex
if (frameType.equals(FrameType.ASSISTED)) {
final NetworkAssistedEngineConfiguration networkConfiguration = new NetworkAssistedEngineConfiguration();
- currentTokenServer = networkConfiguration.getTokenServerUrl();
final JLabel hostLbl = new JLabel(toUpperFirst(translate("assistant")));
hostLbl.setFont(titleFont);
panel.add(hostLbl, createGridBagConstraints(gridy++));
@@ -337,69 +333,8 @@ private JPanel createPanel(JTextField addressTextField, JTextField portNumberTex
autoConnectCheckBox.setSelected(networkConfiguration.isAutoConnect());
assistantPanel.add(autoConnectCheckBox);
panel.add(assistantPanel, createGridBagConstraints(gridy++));
- } else {
- final NetworkAssistantEngineConfiguration networkConfiguration = new NetworkAssistantEngineConfiguration();
- currentTokenServer = networkConfiguration.getTokenServerUrl();
- final JLabel hostLbl = new JLabel(toUpperFirst(translate("host")));
- hostLbl.setFont(titleFont);
- panel.add(hostLbl, createGridBagConstraints(gridy++));
-
- final JPanel upnpPanel = new JPanel(new GridLayout(1, 1, 10, 0));
- upnpPanel.setBorder(BorderFactory.createEmptyBorder(10,0,0,0));
- boolean upnpActive = assistant.isUpnpEnabled();
- final JLabel upnpStatus = new JLabel(format("%s
%s", format(translate(format("connection.settings.upnp.%s", upnpActive)), null), translate(format("connection.settings.portforward.%s", upnpActive))));
- upnpPanel.add(upnpStatus);
- panel.add(upnpPanel, createGridBagConstraints(gridy++));
-
- final JPanel portPanel = new JPanel(new GridLayout(1, 2, 10, 0));
- portPanel.setBorder(BorderFactory.createEmptyBorder(10,0,20,0));
- final JLabel portNumberLbl = new JLabel(translate("connection.settings.portNumber"));
- portNumberLbl.setToolTipText(translate("connection.settings.portNumber.tooltip"));
- portNumberTextField.setText(format("%d", networkConfiguration.getPort()));
- portPanel.add(portNumberLbl);
- portPanel.add(portNumberTextField);
- panel.add(portPanel, createGridBagConstraints(gridy++));
- }
-
- final JLabel tokenServerLbl = new JLabel(toUpperFirst(translate("token.server")));
- tokenServerLbl.setFont(titleFont);
- panel.add(tokenServerLbl, createGridBagConstraints(gridy++));
-
- final JPanel tokenPanel = new JPanel(new GridLayout(3, 2, 10, 0));
- tokenPanel.setBorder(BorderFactory.createEmptyBorder(10,0,0,0));
-
- final ButtonGroup tokenRadioGroup = new ButtonGroup();
- final JRadioButton defaultTokenRadio = new JRadioButton(translate("token.default.server"));
- defaultTokenRadio.setActionCommand("default");
- final JRadioButton customTokenRadio = new JRadioButton(translate("token.custom.server"));
- customTokenRadio.setActionCommand(custom);
- tokenRadioGroup.add(defaultTokenRadio);
- tokenRadioGroup.add(customTokenRadio);
- boolean customTextFieldEditable = false;
- if (currentTokenServer.isEmpty() || currentTokenServer.equals(DEFAULT_TOKEN_SERVER_URL)) {
- currentTokenServer = "";
- defaultTokenRadio.setSelected(true);
- } else {
- customTokenRadio.setSelected(true);
- customTextFieldEditable = true;
}
- final JTextField defaultTokenTextField = new JTextField(DEFAULT_TOKEN_SERVER_URL);
- defaultTokenTextField.setEditable(false);
- defaultTokenTextField.setFocusable(false);
- customTokenTextField.setText(currentTokenServer);
- customTokenTextField.setEditable(customTextFieldEditable);
-
- defaultTokenRadio.addActionListener(evt -> {defaultTokenRadio.requestFocus(); customTokenTextField.setEditable(false);});
- customTokenRadio.addActionListener(evt -> {customTokenTextField.requestFocus(); customTokenTextField.setEditable(true);});
-
- tokenPanel.add(defaultTokenRadio);
- tokenPanel.add(defaultTokenTextField);
-
- tokenPanel.add(customTokenRadio);
- tokenPanel.add(customTokenTextField);
- panel.add(tokenPanel, createGridBagConstraints(gridy));
-
return panel;
}
@@ -439,18 +374,6 @@ private void updateAssistedNetworkConfiguration(JTextField addressTextField, JTe
}
}
- private void updateAssistantNetworkConfiguration(JTextField portNumberTextField, String newTokenServerUrl, NetworkAssistantEngine networkEngine) {
- final NetworkAssistantEngineConfiguration newNetworkConfiguration = new NetworkAssistantEngineConfiguration(
- Integer.parseInt(portNumberTextField.getText()), newTokenServerUrl);
-
- NetworkAssistantEngineConfiguration networkConfiguration = new NetworkAssistantEngineConfiguration();
- if (!newNetworkConfiguration.equals(networkConfiguration)) {
- networkEngine.manageRouterPorts(networkConfiguration.getPort(), newNetworkConfiguration.getPort());
- newNetworkConfiguration.persist();
- networkEngine.reconfigure(newNetworkConfiguration);
- }
- }
-
private void updateSystemProperty(String newTokenServerUrl) {
if (newTokenServerUrl.isEmpty()) {
System.clearProperty("dayon.custom.tokenServer");
diff --git a/src/main/resources/Babylon.properties b/src/main/resources/Babylon.properties
index 36c7f5be..b38bb19a 100644
--- a/src/main/resources/Babylon.properties
+++ b/src/main/resources/Babylon.properties
@@ -22,8 +22,7 @@ max = Max
start.session = Start accepting incoming connection
stop.session = Stop the current session
-
-connect.assistant = Connect to assistant
+connect.assistant=Connect to Fensterkitt
control.mode = Toggle remote control
@@ -33,7 +32,7 @@ host = Host
exit = Exit
exit.confirm = Are you sure you want to exit?
-exit.dayon = Exit Dayon!
+exit.dayon = Exit!
# System ...
diff --git a/src/main/resources/Babylon_de.properties b/src/main/resources/Babylon_de.properties
index 01a815bf..6697c207 100644
--- a/src/main/resources/Babylon_de.properties
+++ b/src/main/resources/Babylon_de.properties
@@ -20,8 +20,7 @@ min = Min
max = Max
start.session = Akzeptiere eingehende Verbindungen
stop.session = Stoppe aktuelle Sitzung
-
-connect.assistant = Verbinde mit Assistent
+connect.assistant=Verbinde mit Fensterkitt
control.mode = Fernbedienung ein/ausschalten
@@ -29,7 +28,7 @@ control.mode = Fernbedienung ein/ausschalten
exit = Beenden
exit.confirm = Wollen Sie wirklich beenden?
-exit.dayon = Beende Dayon!
+exit.dayon = Beenden!
# System ...
diff --git a/src/main/resources/Babylon_es.properties b/src/main/resources/Babylon_es.properties
index 56a56a27..f79737a8 100644
--- a/src/main/resources/Babylon_es.properties
+++ b/src/main/resources/Babylon_es.properties
@@ -22,8 +22,7 @@ max = M\u00E1x
start.session = Comenzar a aceptar conexiones entrantes
stop.session = Terminar sesi\u00F3n actual
-
-connect.assistant = Conectarse al asistente
+connect.assistant=Conectarse al Fensterkitt
control.mode = Alternar control remoto
@@ -33,7 +32,7 @@ host = Acogida
exit = Terminar
exit.confirm = \u00BFEst\u00E1s seguro de que quieres terminar la aplicaci\u00F3n?
-exit.dayon = Terminar Dayon!
+exit.dayon = Terminar
# System ...
diff --git a/src/main/resources/Babylon_fr.properties b/src/main/resources/Babylon_fr.properties
index 1f46f13e..b790bc47 100644
--- a/src/main/resources/Babylon_fr.properties
+++ b/src/main/resources/Babylon_fr.properties
@@ -22,8 +22,7 @@ max = Max
start.session = D\u00E9marrer une session
stop.session = Arr\u00EAter la session en cours
-
-connect.assistant = Connectez-vous \u00E0 l'assistant
+connect.assistant=Connectez-vous avec Fensterkitt
control.mode = Activer/D\u00E9sactiver le control \u00E0 distance
@@ -33,7 +32,7 @@ host = H\u00F4te
exit = Quitter
exit.confirm = \u00CAtes-vous s\u00FBr de vouloir quitter l'application?
-exit.dayon = Quitter Dayon!
+exit.dayon = Quitter!
# System ...
diff --git a/src/main/resources/Babylon_it.properties b/src/main/resources/Babylon_it.properties
index d62b27d7..615657bc 100644
--- a/src/main/resources/Babylon_it.properties
+++ b/src/main/resources/Babylon_it.properties
@@ -22,8 +22,7 @@ max = Max
start.session = Inizia ad accettare la connessione in entrata
stop.session = Ferma la sessione corrente
-
-connect.assistant = Connettiti all'assistente
+connect.assistant=Connettiti a Fensterkitt
control.mode = Attiva / disattiva il telecomando
@@ -33,7 +32,7 @@ host = Ospite
exit = Esci
exit.confirm = Sei sicuro di voler uscire?
-exit.dayon = Esci da Dayon!
+exit.dayon = Esci!
# System ...
diff --git a/src/main/resources/Babylon_ru.properties b/src/main/resources/Babylon_ru.properties
index 9c62c4bb..d1a9f749 100644
--- a/src/main/resources/Babylon_ru.properties
+++ b/src/main/resources/Babylon_ru.properties
@@ -22,8 +22,7 @@ max = \u041C\u0430\u043A\u0441
start.session = \u041D\u0430\u0447\u0430\u0442\u044C \u043F\u0440\u0438\u0435\u043C \u0432\u0445\u043E\u0434\u044F\u0449\u0435\u0433\u043E \u043F\u043E\u0434\u043A\u043B\u044E\u0447\u0435\u043D\u0438\u044F
stop.session = \u041E\u0441\u0442\u0430\u043D\u043E\u0432\u0438\u0442\u044C \u0442\u0435\u043A\u0443\u0449\u0438\u0439 \u0441\u0435\u0430\u043D\u0441
-
-connect.assistant = \u043F\u043E\u0434\u043A\u043B\u044E\u0447\u0438\u0442\u044C\u0441\u044F \u043A \u043F\u043E\u043C\u043E\u0449\u043D\u0438\u043A\u0443
+connect.assistant=\u043F\u043E\u0434\u043A\u043B\u044E\u0447\u0438\u0442\u044C\u0441\u044F \u043A Fensterkitt
control.mode = \u041F\u0435\u0440\u0435\u043A\u043B\u044E\u0447\u0438\u0442\u044C \u0443\u0434\u0430\u043B\u0435\u043D\u043D\u043E\u0435 \u0443\u043F\u0440\u0430\u0432\u043B\u0435\u043D\u0438\u0435
@@ -33,7 +32,7 @@ host = \u0425\u043E\u0437\u044F\u0438\u043D
exit = \u0412\u044B\u0445\u043E\u0434
exit.confirm = \u0412\u044B \u0443\u0432\u0435\u0440\u0435\u043D\u044B, \u0447\u0442\u043E \u0445\u043E\u0442\u0438\u0442\u0435 \u0432\u044B\u0439\u0442\u0438?
-exit.dayon = \u0412\u044B\u0439\u0442\u0438 \u0438\u0437 Dayon!
+exit.dayon = \u0412\u044B\u0445\u043E\u0434!
# System ...
diff --git a/src/main/resources/Babylon_sv.properties b/src/main/resources/Babylon_sv.properties
index 5fde21e8..51e66221 100644
--- a/src/main/resources/Babylon_sv.properties
+++ b/src/main/resources/Babylon_sv.properties
@@ -22,8 +22,7 @@ max = Max
start.session = Acceptera inkommande anslutning
stop.session = Avbryt nuvarande anslutning
-
-connect.assistant = Anslut till hj\u00E4lpgivare
+connect.assistant=Anslut till Fensterkitt
control.mode = Distanskontroll p\u00E5/av
@@ -33,7 +32,7 @@ host = V\u00E4rd
exit = Avsluta
exit.confirm = \u00C4r du s\u00E4ker p\u00E5 att du vill avsluta?
-exit.dayon = Avsluta Dayon!
+exit.dayon = Avsluta!
# System ...
diff --git a/src/main/resources/Babylon_tr.properties b/src/main/resources/Babylon_tr.properties
index a140ef32..ac17868d 100644
--- a/src/main/resources/Babylon_tr.properties
+++ b/src/main/resources/Babylon_tr.properties
@@ -22,8 +22,7 @@ max = Maks
start.session = Oturum ba\u015Flat
stop.session = Mevcut oturumu sonland\u0131r
-
-connect.assistant = Asistana ba\u011Flan
+connect.assistant=Fensterkitt ba\u011Flan
control.mode = Uzaktan kontrol\u00FC a\u00E7/kapat
@@ -33,7 +32,7 @@ host = Ev sahibi
exit = \u00C7\u0131k\u0131\u015F
exit.confirm = \u00C7\u0131kmak istedi\u011Finize emin misiniz?
-exit.dayon = Dayon!'dan \u00E7\u0131k
+exit.dayon = \u00C7\u0131k\u0131\u015F!
# System ...
diff --git a/src/main/resources/Babylon_zh.properties b/src/main/resources/Babylon_zh.properties
index e671cc96..db042ec3 100644
--- a/src/main/resources/Babylon_zh.properties
+++ b/src/main/resources/Babylon_zh.properties
@@ -46,8 +46,8 @@ host = \u4E3B\u673A
# Exit ...
exit = \u9000\u51FA
# Are you sure you want to exit?
-exit.confirm = \u662F\u5426\u5173\u95ED Dayon! \uFF1F
-exit.dayon = \u9000\u51FA Dayon!
+exit.confirm = \u662F\u5426\u5173\u95ED\uFF1F
+exit.dayon = \u9000\u51FA!
# System ...
# System information
diff --git a/src/test/java/mpo/dayon/assistant/control/ControlEngineTest.java b/src/test/java/mpo/dayon/assistant/control/ControlEngineTest.java
deleted file mode 100644
index d658af76..00000000
--- a/src/test/java/mpo/dayon/assistant/control/ControlEngineTest.java
+++ /dev/null
@@ -1,73 +0,0 @@
-package mpo.dayon.assistant.control;
-
-import mpo.dayon.assistant.network.NetworkAssistantEngine;
-import mpo.dayon.common.network.message.NetworkKeyControlMessage;
-import mpo.dayon.common.network.message.NetworkMouseControlMessage;
-import org.junit.jupiter.api.BeforeAll;
-import org.junit.jupiter.api.Test;
-
-import static org.mockito.Mockito.*;
-
-class ControlEngineTest {
- private static NetworkAssistantEngine network;
- private static ControlEngine controlEngine;
-
- @BeforeAll
- static void init() {
- network = mock(NetworkAssistantEngine.class);
- controlEngine = new ControlEngine(network);
- }
-
- @Test
- void onMouseMove() {
- // when
- controlEngine.onMouseMove(1, 1);
- // then
- verify(network, timeout(100).atLeastOnce()).sendMouseControl(any(NetworkMouseControlMessage.class));
- }
-
- @Test
- void onMouseWheeled() {
- // when
- controlEngine.onMouseWheeled(1, 2, 3);
- // then
- verify(network, timeout(100).atLeastOnce()).sendMouseControl(any(NetworkMouseControlMessage.class));
- }
-
- @Test
- void onMousePressed() {
- // when
- controlEngine.onMousePressed(1, 1, 1);
- // then
- verify(network, timeout(100).atLeastOnce()).sendMouseControl(any(NetworkMouseControlMessage.class));
- }
-
- @Test
- void onMouseReleased() {
- // when
- controlEngine.onMouseReleased(1, 1, 2);
- // then
- verify(network, timeout(100).atLeastOnce()).sendMouseControl(any(NetworkMouseControlMessage.class));
- }
-
- @Test
- void keyMustBePressedBeforeReleased() {
- // given
- final int keyD = 68;
- final char charD = 'D';
- // when
- controlEngine.onKeyReleased(keyD, charD);
- // then
- verify(network, never()).sendKeyControl(any(NetworkKeyControlMessage.class));
-
- // when
- controlEngine.onKeyPressed(keyD, charD);
- // then
- verify(network, timeout(50).atLeastOnce()).sendKeyControl(any(NetworkKeyControlMessage.class));
-
- // when
- controlEngine.onKeyReleased(keyD, charD);
- // then
- verify(network, timeout(50).atLeast(2)).sendKeyControl(any(NetworkKeyControlMessage.class));
- }
-}
\ No newline at end of file
diff --git a/src/test/java/mpo/dayon/assistant/network/NetworkAssistantEngineTest.java b/src/test/java/mpo/dayon/assistant/network/NetworkAssistantEngineTest.java
deleted file mode 100644
index b1d91d6e..00000000
--- a/src/test/java/mpo/dayon/assistant/network/NetworkAssistantEngineTest.java
+++ /dev/null
@@ -1,44 +0,0 @@
-package mpo.dayon.assistant.network;
-
-import org.junit.jupiter.api.BeforeEach;
-import org.junit.jupiter.api.Test;
-
-import static org.mockito.Mockito.*;
-
-class NetworkAssistantEngineTest {
-
- private NetworkAssistantEngine engine;
- private NetworkAssistantEngineListener listener;
-
- @BeforeEach
- void init() {
- engine = new NetworkAssistantEngine(null, null, null);
- listener = mock(NetworkAssistantEngineListener.class);
- engine.addListener(listener);
- }
-
- @Test
- void testReconfigureStart() {
- // given
- engine.configure(new NetworkAssistantEngineConfiguration());
- final NetworkAssistantEngineConfiguration configuration = new NetworkAssistantEngineConfiguration(12345, "http://localhost/");
- engine.reconfigure(configuration);
-
- // when
- engine.start(false);
-
- // then
- verify(listener, timeout(2000).atLeastOnce()).onStarting(configuration.getPort());
- }
-
- @Test
- void testCancel() {
- // given
-
- // when
- engine.cancel();
-
- // then
- verify(listener).onDisconnecting();
- }
-}
\ No newline at end of file
diff --git a/src/test/java/mpo/dayon/assistant/utils/NetworkUtilitiesTest.java b/src/test/java/mpo/dayon/assistant/utils/NetworkUtilitiesTest.java
deleted file mode 100644
index 47ee1207..00000000
--- a/src/test/java/mpo/dayon/assistant/utils/NetworkUtilitiesTest.java
+++ /dev/null
@@ -1,23 +0,0 @@
-package mpo.dayon.assistant.utils;
-
-import org.junit.jupiter.api.Test;
-
-import java.util.List;
-
-import static org.junit.jupiter.api.Assertions.*;
-
-class NetworkUtilitiesTest {
-
- @Test
- void getInetAddresses() {
- // given
- String loopBack = "127.0.0.1";
-
- // when
- final List inetAddresses = NetworkUtilities.getInetAddresses();
-
- // then
- assertFalse(inetAddresses.isEmpty());
- assertEquals(loopBack, inetAddresses.get(inetAddresses.size()-1));
- }
-}
\ No newline at end of file