Enhance TerminalUI eventing
- New methods in an eventloop and message builder - Generic polish to use these methods - Relates #761
This commit is contained in:
@@ -33,8 +33,6 @@ import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.messaging.Message;
|
||||
import org.springframework.messaging.support.MessageBuilder;
|
||||
import org.springframework.shell.component.view.control.View;
|
||||
import org.springframework.shell.component.view.control.ViewService;
|
||||
import org.springframework.shell.component.view.event.DefaultEventLoop;
|
||||
@@ -48,10 +46,8 @@ import org.springframework.shell.component.view.event.MouseHandler;
|
||||
import org.springframework.shell.component.view.event.MouseHandler.MouseHandlerResult;
|
||||
import org.springframework.shell.component.view.geom.Rectangle;
|
||||
import org.springframework.shell.component.view.message.ShellMessageBuilder;
|
||||
import org.springframework.shell.component.view.message.ShellMessageHeaderAccessor;
|
||||
import org.springframework.shell.component.view.screen.DefaultScreen;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
@@ -236,40 +232,24 @@ public class TerminalUI implements ViewService {
|
||||
}
|
||||
|
||||
private void dispatchWinch() {
|
||||
Message<String> message = MessageBuilder.withPayload("WINCH")
|
||||
.setHeader(ShellMessageHeaderAccessor.EVENT_TYPE, EventLoop.Type.SIGNAL)
|
||||
.build();
|
||||
eventLoop.dispatch(message);
|
||||
eventLoop.dispatch(ShellMessageBuilder.ofSignal("WINCH"));
|
||||
}
|
||||
|
||||
private void registerEventHandling() {
|
||||
// XXX: think this again
|
||||
eventLoop.onDestroy(eventLoop.events()
|
||||
.filter(m -> {
|
||||
return ObjectUtils.nullSafeEquals(m.getHeaders().get(ShellMessageHeaderAccessor.EVENT_TYPE), EventLoop.Type.SIGNAL);
|
||||
})
|
||||
.doOnNext(m -> {
|
||||
eventLoop.onDestroy(eventLoop.signalEvents()
|
||||
.subscribe(event -> {
|
||||
display();
|
||||
})
|
||||
.subscribe());
|
||||
}));
|
||||
|
||||
// XXX: think this again
|
||||
eventLoop.onDestroy(eventLoop.events()
|
||||
.filter(m -> {
|
||||
return ObjectUtils.nullSafeEquals(m.getHeaders().get(ShellMessageHeaderAccessor.EVENT_TYPE), EventLoop.Type.SYSTEM);
|
||||
})
|
||||
.doOnNext(m -> {
|
||||
Object payload = m.getPayload();
|
||||
if (payload instanceof String s) {
|
||||
if ("redraw".equals(s)) {
|
||||
display();
|
||||
}
|
||||
else if ("int".equals(s)) {
|
||||
this.terminal.raise(Signal.INT);
|
||||
}
|
||||
eventLoop.onDestroy(eventLoop.systemEvents()
|
||||
.subscribe(event -> {
|
||||
if ("redraw".equals(event)) {
|
||||
display();
|
||||
}
|
||||
})
|
||||
.subscribe());
|
||||
else if ("int".equals(event)) {
|
||||
this.terminal.raise(Signal.INT);
|
||||
}
|
||||
}));
|
||||
|
||||
eventLoop.onDestroy(eventLoop.keyEvents()
|
||||
.doOnNext(m -> {
|
||||
@@ -417,11 +397,8 @@ public class TerminalUI implements ViewService {
|
||||
}
|
||||
|
||||
private void dispatchKeyEvent(KeyEvent event) {
|
||||
Message<KeyEvent> message = MessageBuilder
|
||||
.withPayload(event)
|
||||
.setHeader(ShellMessageHeaderAccessor.EVENT_TYPE, EventLoop.Type.KEY)
|
||||
.build();
|
||||
eventLoop.dispatch(message);
|
||||
log.debug("Dispatch key event: {}", event);
|
||||
eventLoop.dispatch(ShellMessageBuilder.ofKeyEvent(event));
|
||||
}
|
||||
|
||||
private void dispatchMouse(MouseEvent event) {
|
||||
|
||||
@@ -150,6 +150,22 @@ public class DefaultEventLoop implements EventLoop {
|
||||
.ofType(MouseEvent.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Flux<String> systemEvents() {
|
||||
return events()
|
||||
.filter(m -> EventLoop.Type.SYSTEM.equals(StaticShellMessageHeaderAccessor.getEventType(m)))
|
||||
.map(m -> m.getPayload())
|
||||
.ofType(String.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Flux<String> signalEvents() {
|
||||
return events()
|
||||
.filter(m -> EventLoop.Type.SIGNAL.equals(StaticShellMessageHeaderAccessor.getEventType(m)))
|
||||
.map(m -> m.getPayload())
|
||||
.ofType(String.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T extends ViewEvent> Flux<T> viewEvents(Class<T> clazz) {
|
||||
return events(EventLoop.Type.VIEW, clazz);
|
||||
|
||||
@@ -61,6 +61,22 @@ public interface EventLoop {
|
||||
*/
|
||||
Flux<MouseEvent> mouseEvents();
|
||||
|
||||
/**
|
||||
* Specialisation of {@link #events()} which returns type safe
|
||||
* {code system} events.
|
||||
*
|
||||
* @return the system events from an event loop
|
||||
*/
|
||||
Flux<String> systemEvents();
|
||||
|
||||
/**
|
||||
* Specialisation of {@link #events()} which returns type safe
|
||||
* {code signal} events.
|
||||
*
|
||||
* @return the signal events from an event loop
|
||||
*/
|
||||
Flux<String> signalEvents();
|
||||
|
||||
/**
|
||||
* Specialisation of {@link #events()} which returns type safe {@link ViewEvent}s.
|
||||
*
|
||||
|
||||
@@ -20,6 +20,7 @@ import org.springframework.messaging.Message;
|
||||
import org.springframework.messaging.support.GenericMessage;
|
||||
import org.springframework.shell.component.view.control.View;
|
||||
import org.springframework.shell.component.view.event.EventLoop;
|
||||
import org.springframework.shell.component.view.event.KeyEvent;
|
||||
import org.springframework.shell.component.view.event.MouseEvent;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
@@ -83,6 +84,30 @@ public final class ShellMessageBuilder<T> {
|
||||
.build();
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a {@code signal} message.
|
||||
*
|
||||
* @return a signal message
|
||||
*/
|
||||
public static Message<String> ofSignal(String signal) {
|
||||
return new ShellMessageBuilder<>(signal, null)
|
||||
.setEventType(EventLoop.Type.SIGNAL)
|
||||
.setPriority(0)
|
||||
.build();
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a message of a {@link KeyEvent}.
|
||||
*
|
||||
* @param event the event type
|
||||
* @return a message with {@link KeyEvent} as a payload
|
||||
*/
|
||||
public static Message<KeyEvent> ofKeyEvent(KeyEvent event) {
|
||||
return new ShellMessageBuilder<>(event, null)
|
||||
.setEventType(EventLoop.Type.KEY)
|
||||
.build();
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a message of a {@link MouseEvent}.
|
||||
*
|
||||
|
||||
@@ -17,6 +17,7 @@ package org.springframework.shell.component.view.event;
|
||||
|
||||
import java.time.Duration;
|
||||
import java.util.Arrays;
|
||||
import java.util.EnumSet;
|
||||
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
@@ -190,4 +191,70 @@ class DefaultEventLoopTests {
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
void keyEvents() {
|
||||
initDefault();
|
||||
|
||||
KeyEvent event = KeyEvent.of(KeyEvent.Key.a);
|
||||
Message<KeyEvent> message = ShellMessageBuilder.ofKeyEvent(event);
|
||||
|
||||
StepVerifier verifier1 = StepVerifier.create(loop.keyEvents())
|
||||
.expectNextCount(1)
|
||||
.thenCancel()
|
||||
.verifyLater();
|
||||
|
||||
loop.dispatch(message);
|
||||
verifier1.verify(Duration.ofSeconds(1));
|
||||
}
|
||||
|
||||
@Test
|
||||
void mouseEvents() {
|
||||
initDefault();
|
||||
|
||||
org.jline.terminal.MouseEvent jlineMouseEvent = new org.jline.terminal.MouseEvent(
|
||||
org.jline.terminal.MouseEvent.Type.Released,
|
||||
org.jline.terminal.MouseEvent.Button.Button1,
|
||||
EnumSet.noneOf(org.jline.terminal.MouseEvent.Modifier.class), 0, 0);
|
||||
MouseEvent event = MouseEvent.of(jlineMouseEvent);
|
||||
Message<MouseEvent> message = ShellMessageBuilder.ofMouseEvent(event);
|
||||
|
||||
StepVerifier verifier1 = StepVerifier.create(loop.mouseEvents())
|
||||
.expectNextCount(1)
|
||||
.thenCancel()
|
||||
.verifyLater();
|
||||
|
||||
loop.dispatch(message);
|
||||
verifier1.verify(Duration.ofSeconds(1));
|
||||
}
|
||||
|
||||
@Test
|
||||
void systemEvents() {
|
||||
initDefault();
|
||||
|
||||
Message<String> message = ShellMessageBuilder.ofRedraw();
|
||||
|
||||
StepVerifier verifier1 = StepVerifier.create(loop.systemEvents())
|
||||
.expectNextCount(1)
|
||||
.thenCancel()
|
||||
.verifyLater();
|
||||
|
||||
loop.dispatch(message);
|
||||
verifier1.verify(Duration.ofSeconds(1));
|
||||
}
|
||||
|
||||
@Test
|
||||
void signalEvents() {
|
||||
initDefault();
|
||||
|
||||
Message<String> message = ShellMessageBuilder.ofSignal("WINCH");
|
||||
|
||||
StepVerifier verifier1 = StepVerifier.create(loop.signalEvents())
|
||||
.expectNextCount(1)
|
||||
.thenCancel()
|
||||
.verifyLater();
|
||||
|
||||
loop.dispatch(message);
|
||||
verifier1.verify(Duration.ofSeconds(1));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user