From b70664267ddfe58a9ccd7d8bcb4fb9e96feb5f91 Mon Sep 17 00:00:00 2001 From: Benjamin Klaus Date: Wed, 5 Dec 2018 17:49:07 +0100 Subject: [PATCH 1/5] added interface and implementation of AREKeyboardListener --- .../mw/services/IAREKeyboardListener.java | 49 +++++++++++++++++++ .../serverUtils/AREKeyboardListener.java | 43 ++++++++++++++++ 2 files changed, 92 insertions(+) create mode 100644 ARE/middleware/src/main/java/eu/asterics/mw/services/IAREKeyboardListener.java create mode 100644 ARE/services/WebService/src/main/java/eu/asterics/mw/webservice/serverUtils/AREKeyboardListener.java diff --git a/ARE/middleware/src/main/java/eu/asterics/mw/services/IAREKeyboardListener.java b/ARE/middleware/src/main/java/eu/asterics/mw/services/IAREKeyboardListener.java new file mode 100644 index 000000000..c5753d2bf --- /dev/null +++ b/ARE/middleware/src/main/java/eu/asterics/mw/services/IAREKeyboardListener.java @@ -0,0 +1,49 @@ +package eu.asterics.mw.services; + +/* + * AsTeRICS - Assistive Technology Rapid Integration and Construction Set + * + * + * d8888 88888888888 8888888b. 8888888 .d8888b. .d8888b. + * d88888 888 888 Y88b 888 d88P Y88b d88P Y88b + * d88P888 888 888 888 888 888 888 Y88b. + * d88P 888 .d8888b 888 .d88b. 888 d88P 888 888 "Y888b. + * d88P 888 88K 888 d8P Y8b 8888888P" 888 888 "Y88b. + * d88P 888 "Y8888b. 888 88888888 888 T88b 888 888 888 "888 + * d8888888888 X88 888 Y8b. 888 T88b 888 Y88b d88P Y88b d88P + * d88P 888 88888P' 888 "Y8888 888 T88b 8888888 "Y8888P" "Y8888P" + * + * + * homepage: http://www.asterics.org + * + * This project has been partly funded by the European Commission, + * Grant Agreement Number 247730 + * + * + * Dual License: MIT or GPL v3.0 with "CLASSPATH" exception + * (please refer to the folder LICENSE) + * + */ + +import org.jnativehook.keyboard.NativeKeyEvent; + +/** + * generic listener for NativeKeyEvents + */ +public interface IAREKeyboardListener { + + /** + * to be called if a key is pressed + * + * @param nke + */ + void keyPressed(NativeKeyEvent nke); + + /** + * to be called if a key is released + * + * @param nke + */ + void keyReleased(NativeKeyEvent nke); + +} diff --git a/ARE/services/WebService/src/main/java/eu/asterics/mw/webservice/serverUtils/AREKeyboardListener.java b/ARE/services/WebService/src/main/java/eu/asterics/mw/webservice/serverUtils/AREKeyboardListener.java new file mode 100644 index 000000000..0e7bd8b1e --- /dev/null +++ b/ARE/services/WebService/src/main/java/eu/asterics/mw/webservice/serverUtils/AREKeyboardListener.java @@ -0,0 +1,43 @@ +/* + * AsTeRICS - Assistive Technology Rapid Integration and Construction Set + * + * + * d8888 88888888888 8888888b. 8888888 .d8888b. .d8888b. + * d88888 888 888 Y88b 888 d88P Y88b d88P Y88b + * d88P888 888 888 888 888 888 888 Y88b. + * d88P 888 .d8888b 888 .d88b. 888 d88P 888 888 "Y888b. + * d88P 888 88K 888 d8P Y8b 8888888P" 888 888 "Y88b. + * d88P 888 "Y8888b. 888 88888888 888 T88b 888 888 888 "888 + * d8888888888 X88 888 Y8b. 888 T88b 888 Y88b d88P Y88b d88P + * d88P 888 88888P' 888 "Y8888 888 T88b 8888888 "Y8888P" "Y8888P" + * + * + * homepage: http://www.asterics.org + * + * This project has been funded by the European Commission, + * Grant Agreement Number 247730 + * + * + * Dual License: MIT or GPL v3.0 with "CLASSPATH" exception + * (please refer to the folder LICENSE) + * + */ + +package eu.asterics.mw.webservice.serverUtils; + +import eu.asterics.mw.services.IAREKeyboardListener; +import eu.asterics.mw.webservice.SseResource; +import org.jnativehook.keyboard.NativeKeyEvent; + +public class AREKeyboardListener implements IAREKeyboardListener { + + @Override + public void keyPressed(NativeKeyEvent nke) { + SseResource.broadcastKeyboardPressedEvent(ObjectTransformation.objectToJSON(nke)); + } + + @Override + public void keyReleased(NativeKeyEvent nke) { + SseResource.broadcastKeyboardReleasedEvent(ObjectTransformation.objectToJSON(nke)); + } +} From 96c609abd96ec34d1fe49ae1c6d490f221f2c581 Mon Sep 17 00:00:00 2001 From: Benjamin Klaus Date: Wed, 5 Dec 2018 17:51:42 +0100 Subject: [PATCH 2/5] added possibility to register/deregister keyboard listeners, listeners are called on native keyPressed() and keyReleased() events --- .../mw/jnativehook/NativeHookServices.java | 35 ++++++++++++++++--- 1 file changed, 30 insertions(+), 5 deletions(-) diff --git a/ARE/services/JNativeHook/src/main/java/eu/asterics/mw/jnativehook/NativeHookServices.java b/ARE/services/JNativeHook/src/main/java/eu/asterics/mw/jnativehook/NativeHookServices.java index 466f1c217..9deb61da7 100644 --- a/ARE/services/JNativeHook/src/main/java/eu/asterics/mw/jnativehook/NativeHookServices.java +++ b/ARE/services/JNativeHook/src/main/java/eu/asterics/mw/jnativehook/NativeHookServices.java @@ -30,9 +30,12 @@ import java.io.IOException; import java.lang.reflect.Field; import java.text.MessageFormat; +import java.util.HashSet; +import java.util.Set; import java.util.logging.Level; import java.util.logging.Logger; +import eu.asterics.mw.services.IAREKeyboardListener; import eu.asterics.mw.utils.OSUtils; import org.jnativehook.GlobalScreen; import org.jnativehook.NativeHookException; @@ -74,6 +77,8 @@ public class NativeHookServices implements NativeKeyListener { private AsapiSupport as; + private Set keyboardListeners = new HashSet<>(); + private NativeHookServices() { AstericsErrorHandling.instance.getLogger().fine("Registering native hooks..."); try { @@ -205,15 +210,17 @@ protected void finalize() throws Throwable { @Override public void nativeKeyPressed(NativeKeyEvent nke) { - // TODO Auto-generated method stub - + for(IAREKeyboardListener listener : keyboardListeners) { + listener.keyPressed(nke); + } } @Override public void nativeKeyReleased(NativeKeyEvent nke) { - // TODO Auto-generated method stub - // System.out.println("Native key released: - // "+nke.getKeyText(nke.getKeyCode())); + + for(IAREKeyboardListener listener : keyboardListeners) { + listener.keyReleased(nke); + } if (nke.getKeyCode() == keyCodeStartModel) { try { as.runModel(); @@ -250,6 +257,24 @@ public void nativeKeyTyped(NativeKeyEvent nke) { // System.out.println("Native key typed: "+nke); } + /** + * register a new keyboard listener + * @param listener + * @return + */ + public boolean registerAREKeyboardListener(IAREKeyboardListener listener) { + return this.keyboardListeners.add(listener); + } + + /** + * deregisters a keyboard listener + * @param listener + * @return + */ + public boolean unregisterAREKeyboardListener(IAREKeyboardListener listener) { + return this.keyboardListeners.remove(listener); + } + private String getCurrentRestPort() { String port = AREProperties.instance.getProperty(PROPTERTY_REST_PORT); if(port == null || port.isEmpty()) { From 4e8e90cdc95f93f8e7afcbcfa9a5e4fe8f83b8f4 Mon Sep 17 00:00:00 2001 From: Benjamin Klaus Date: Wed, 5 Dec 2018 17:52:59 +0100 Subject: [PATCH 3/5] added asterics.mw.jnativehook.jar to build.xml -> compile dependency because of usage of NativeKeyEvent --- ARE/middleware/build.xml | 2 ++ ARE/services/WebService/build.xml | 1 + 2 files changed, 3 insertions(+) diff --git a/ARE/middleware/build.xml b/ARE/middleware/build.xml index b6e7fb6a9..1f32c7768 100644 --- a/ARE/middleware/build.xml +++ b/ARE/middleware/build.xml @@ -7,11 +7,13 @@ + + diff --git a/ARE/services/WebService/build.xml b/ARE/services/WebService/build.xml index f1e83491a..2eb75a9ba 100644 --- a/ARE/services/WebService/build.xml +++ b/ARE/services/WebService/build.xml @@ -16,6 +16,7 @@ + From 92f390ead7dd776135b3d3ddd1b179411d4056cf Mon Sep 17 00:00:00 2001 From: Benjamin Klaus Date: Wed, 5 Dec 2018 17:54:02 +0100 Subject: [PATCH 4/5] added SSE endpoint for subscribing to keyboard pressed/released events --- .../asterics/mw/webservice/SseResource.java | 66 +++++++++++++++++-- 1 file changed, 62 insertions(+), 4 deletions(-) diff --git a/ARE/services/WebService/src/main/java/eu/asterics/mw/webservice/SseResource.java b/ARE/services/WebService/src/main/java/eu/asterics/mw/webservice/SseResource.java index 6ffa9faf5..839bb10fd 100644 --- a/ARE/services/WebService/src/main/java/eu/asterics/mw/webservice/SseResource.java +++ b/ARE/services/WebService/src/main/java/eu/asterics/mw/webservice/SseResource.java @@ -38,6 +38,8 @@ import javax.ws.rs.Produces; import javax.ws.rs.core.MediaType; +import eu.asterics.mw.jnativehook.NativeHookServices; +import eu.asterics.mw.webservice.serverUtils.*; import org.glassfish.jersey.media.sse.EventOutput; import org.glassfish.jersey.media.sse.OutboundEvent; import org.glassfish.jersey.media.sse.SseBroadcaster; @@ -47,10 +49,6 @@ import eu.asterics.mw.model.deployment.IChannel; import eu.asterics.mw.services.AREServices; import eu.asterics.mw.services.AstericsErrorHandling; -import eu.asterics.mw.webservice.serverUtils.AREEventListener; -import eu.asterics.mw.webservice.serverUtils.AstericsAPIEncoding; -import eu.asterics.mw.webservice.serverUtils.ObjectTransformation; -import eu.asterics.mw.webservice.serverUtils.RuntimeListener; @Singleton @Path("/") @@ -60,6 +58,8 @@ public class SseResource { // Client broadcasters private static SseBroadcaster deploymentBroadcaster = new SseBroadcaster(); + private static SseBroadcaster keyboardPressedBroadcaster = new SseBroadcaster(); + private static SseBroadcaster keyboardReleasedBroadcaster = new SseBroadcaster(); private static SseBroadcaster modelStateBroadcaster = new SseBroadcaster(); private static SseBroadcaster eventChannelBroadcaster = new SseBroadcaster(); private static SseBroadcaster propertyChangeBroadcaster = new SseBroadcaster(); @@ -68,14 +68,17 @@ public class SseResource { // System listeners private static AREEventListener eventListener; private static RuntimeListener runtimeListener; + private static AREKeyboardListener keyboardListener; public SseResource() { // create and register listeners SseResource.eventListener = new AREEventListener(); SseResource.runtimeListener = new RuntimeListener(); + SseResource.keyboardListener = new AREKeyboardListener(); AREServices.instance.registerAREEventListener(eventListener); AREServices.instance.registerRuntimeDataListener(runtimeListener); + NativeHookServices.getInstance().registerAREKeyboardListener(keyboardListener); initializeDataChannelListeners(); } @@ -122,6 +125,28 @@ public EventOutput subscribe_AREDeploymentEvents() { return eventOutput; } + @Path("/runtime/keyboard/pressed/listener") + @GET + @Produces(SseFeature.SERVER_SENT_EVENTS) + public EventOutput subscribe_keyboardPressedEvents() { + final EventOutput eventOutput = new EventOutput(); + + SseResource.keyboardPressedBroadcaster.add(eventOutput); + + return eventOutput; + } + + @Path("/runtime/keyboard/released/listener") + @GET + @Produces(SseFeature.SERVER_SENT_EVENTS) + public EventOutput subscribe_keyboardReleasedEvents() { + final EventOutput eventOutput = new EventOutput(); + + SseResource.keyboardReleasedBroadcaster.add(eventOutput); + + return eventOutput; + } + @Path("/runtime/model/state/listener") @GET @Produces(SseFeature.SERVER_SENT_EVENTS) @@ -206,6 +231,28 @@ public static String broadcastDeploymentEvent(String eventMessage) { return eventMessage; } + /** + * Static method that broadcasts an event to clients who were subscribed to keyboard pressed events. + * + * @param eventMessage JSON formatted native key event that was triggered + * + * @return the json that was sent to the SSE subscribers + */ + public static String broadcastKeyboardPressedEvent(String eventMessage) { + return broadcastEvent(keyboardPressedBroadcaster, eventMessage, MediaType.APPLICATION_JSON_TYPE); + } + + /** + * Static method that broadcasts an event to clients who were subscribed to keyboard released events. + * + * @param eventMessage JSON formatted native key event that was triggered + * + * @return the json that was sent to the SSE subscribers + */ + public static String broadcastKeyboardReleasedEvent(String eventMessage) { + return broadcastEvent(keyboardReleasedBroadcaster, eventMessage, MediaType.APPLICATION_JSON_TYPE); + } + /** * Static method that broadcasts an event to clients who were subscribed to model state events. * @@ -342,4 +389,15 @@ public static String broadcastPropertyChangedEvent(String componentId, String co * BROADCASTER METHODS - end **********************************/ + + private static String broadcastEvent(SseBroadcaster broadcaster, String eventMessage, MediaType eventType) { + OutboundEvent.Builder eventBuilder = new OutboundEvent.Builder(); + eventBuilder.name("event"); + eventBuilder.mediaType(eventType); + eventBuilder.data(String.class, eventMessage); + OutboundEvent event = eventBuilder.build(); + broadcaster.broadcast(event); + return eventMessage; + } + } \ No newline at end of file From fd877a355f199b63c87d4fef47e0965320be0b33 Mon Sep 17 00:00:00 2001 From: Benjamin Klaus Date: Wed, 12 Dec 2018 15:35:59 +0100 Subject: [PATCH 5/5] added first version of AREKeyEvent, not finished --- .../asterics/mw/jnativehook/AREKeyEvent.java | 41 +++++++++++++++++++ 1 file changed, 41 insertions(+) create mode 100644 ARE/services/JNativeHook/src/main/java/eu/asterics/mw/jnativehook/AREKeyEvent.java diff --git a/ARE/services/JNativeHook/src/main/java/eu/asterics/mw/jnativehook/AREKeyEvent.java b/ARE/services/JNativeHook/src/main/java/eu/asterics/mw/jnativehook/AREKeyEvent.java new file mode 100644 index 000000000..7d5b2272f --- /dev/null +++ b/ARE/services/JNativeHook/src/main/java/eu/asterics/mw/jnativehook/AREKeyEvent.java @@ -0,0 +1,41 @@ +/* + * AsTeRICS - Assistive Technology Rapid Integration and Construction Set + * + * + * d8888 88888888888 8888888b. 8888888 .d8888b. .d8888b. + * d88888 888 888 Y88b 888 d88P Y88b d88P Y88b + * d88P888 888 888 888 888 888 888 Y88b. + * d88P 888 .d8888b 888 .d88b. 888 d88P 888 888 "Y888b. + * d88P 888 88K 888 d8P Y8b 8888888P" 888 888 "Y88b. + * d88P 888 "Y8888b. 888 88888888 888 T88b 888 888 888 "888 + * d8888888888 X88 888 Y8b. 888 T88b 888 Y88b d88P Y88b d88P + * d88P 888 88888P' 888 "Y8888 888 T88b 8888888 "Y8888P" "Y8888P" + * + * + * homepage: http://www.asterics.org + * + * This project has been funded by the European Commission, + * Grant Agreement Number 247730 + * + * + * Dual License: MIT or GPL v3.0 with "CLASSPATH" exception + * (please refer to the folder LICENSE) + * + */ + +package eu.asterics.mw.jnativehook; + +import org.jnativehook.keyboard.NativeKeyEvent; +import org.osgi.framework.BundleActivator; +import org.osgi.framework.BundleContext; + +public class AREKeyEvent extends NativeKeyEvent { + + public AREKeyEvent(int id, int modifiers, int rawCode, int keyCode, char keyChar, int keyLocation) { + super(id, modifiers, rawCode, keyCode, keyChar, keyLocation); + } + + public AREKeyEvent(int id, int modifiers, int rawCode, int keyCode, char keyChar) { + super(id, modifiers, rawCode, keyCode, keyChar); + } +}