From 39581003916b70e098337eae59a7cfc654b14ab6 Mon Sep 17 00:00:00 2001 From: MrLetsplay Date: Wed, 10 Jan 2024 20:30:41 +0100 Subject: [PATCH] initial commit --- .gitignore | 5 + .project | 23 +++ pom.xml | 63 ++++++++ .../me/mrletsplay/streamdeck/Soundboard.java | 86 ++++++++++ .../me/mrletsplay/streamdeck/StreamDeck.java | 37 +++++ .../mrletsplay/streamdeck/action/Action.java | 14 ++ .../streamdeck/action/ActionParameter.java | 14 ++ .../action/ActionSerializationException.java | 25 +++ .../streamdeck/action/ActionSerializer.java | 112 +++++++++++++ .../streamdeck/action/DeckAction.java | 40 +++++ .../action/impl/PlaySoundAction.java | 18 +++ .../action/impl/PressKeyAction.java | 33 ++++ .../streamdeck/api/StreamDeckAPI.java | 149 ++++++++++++++++++ .../me/mrletsplay/streamdeck/deck/Deck.java | 26 +++ .../streamdeck/deck/DeckButton.java | 37 +++++ .../exception/InitializationException.java | 23 +++ .../exception/SoundboardException.java | 23 +++ 17 files changed, 728 insertions(+) create mode 100644 .gitignore create mode 100644 .project create mode 100644 pom.xml create mode 100644 src/main/java/me/mrletsplay/streamdeck/Soundboard.java create mode 100644 src/main/java/me/mrletsplay/streamdeck/StreamDeck.java create mode 100644 src/main/java/me/mrletsplay/streamdeck/action/Action.java create mode 100644 src/main/java/me/mrletsplay/streamdeck/action/ActionParameter.java create mode 100644 src/main/java/me/mrletsplay/streamdeck/action/ActionSerializationException.java create mode 100644 src/main/java/me/mrletsplay/streamdeck/action/ActionSerializer.java create mode 100644 src/main/java/me/mrletsplay/streamdeck/action/DeckAction.java create mode 100644 src/main/java/me/mrletsplay/streamdeck/action/impl/PlaySoundAction.java create mode 100644 src/main/java/me/mrletsplay/streamdeck/action/impl/PressKeyAction.java create mode 100644 src/main/java/me/mrletsplay/streamdeck/api/StreamDeckAPI.java create mode 100644 src/main/java/me/mrletsplay/streamdeck/deck/Deck.java create mode 100644 src/main/java/me/mrletsplay/streamdeck/deck/DeckButton.java create mode 100644 src/main/java/me/mrletsplay/streamdeck/exception/InitializationException.java create mode 100644 src/main/java/me/mrletsplay/streamdeck/exception/SoundboardException.java diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..746a89c --- /dev/null +++ b/.gitignore @@ -0,0 +1,5 @@ +/.settings +/bin +/.classpath +/TEST +/target/ diff --git a/.project b/.project new file mode 100644 index 0000000..284d04f --- /dev/null +++ b/.project @@ -0,0 +1,23 @@ + + + DesktopStreamDeck + + + + + + org.eclipse.jdt.core.javabuilder + + + + + org.eclipse.m2e.core.maven2Builder + + + + + + org.eclipse.m2e.core.maven2Nature + org.eclipse.jdt.core.javanature + + diff --git a/pom.xml b/pom.xml new file mode 100644 index 0000000..6bf3df4 --- /dev/null +++ b/pom.xml @@ -0,0 +1,63 @@ + + 4.0.0 + me.mrletsplay + StreamDeckDesktop + 1.0-SNAPSHOT + + src/main/java + + + maven-compiler-plugin + 3.8.1 + + 17 + + + + org.apache.maven.plugins + maven-jar-plugin + 3.2.0 + + + + me.mrletsplay.streamdeck.StreamDeck + + + + + + org.apache.maven.plugins + maven-shade-plugin + 2.4.3 + + + package + + shade + + + + + + + + + Graphite-Official + https://maven.graphite-official.com/releases + + + + + me.mrletsplay + SimpleHTTPServer + 2.0-SNAPSHOT + + + me.mrletsplay + MrCore + 4.4 + + + diff --git a/src/main/java/me/mrletsplay/streamdeck/Soundboard.java b/src/main/java/me/mrletsplay/streamdeck/Soundboard.java new file mode 100644 index 0000000..2ebc1ee --- /dev/null +++ b/src/main/java/me/mrletsplay/streamdeck/Soundboard.java @@ -0,0 +1,86 @@ +package me.mrletsplay.streamdeck; + +import java.io.File; +import java.io.IOException; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.atomic.AtomicBoolean; + +import javax.sound.sampled.AudioInputStream; +import javax.sound.sampled.AudioSystem; +import javax.sound.sampled.Clip; +import javax.sound.sampled.FloatControl; +import javax.sound.sampled.LineEvent; +import javax.sound.sampled.LineUnavailableException; +import javax.sound.sampled.UnsupportedAudioFileException; + +import me.mrletsplay.streamdeck.exception.InitializationException; +import me.mrletsplay.streamdeck.exception.SoundboardException; + +public class Soundboard { + + private static ExecutorService executor; + + public static void initialize() throws InitializationException { + executor = Executors.newCachedThreadPool(); + } + + public static void finish() { + executor.shutdown(); + } + + public static void play(String path) throws SoundboardException { + AudioInputStream s; + try { + s = AudioSystem.getAudioInputStream(new File("TEST/test.wav")); + } catch (UnsupportedAudioFileException | IOException e) { + throw new SoundboardException(e); + } + + executor.submit(() -> { + try(Clip clip = AudioSystem.getClip()) { + Object wait = new Object(); + AtomicBoolean playing = new AtomicBoolean(true); + clip.addLineListener(event -> { + if(event.getType() == LineEvent.Type.STOP || event.getType() == LineEvent.Type.CLOSE) { + playing.set(false); + wait.notify(); + } + }); + + clip.open(s); + clip.setFramePosition(0); + +// FloatControl gain = (FloatControl) clip.getControl(FloatControl.Type.MASTER_GAIN); +// gain.setValue(20f * (float) Math.log10(0.2)); + + clip.start(); + + while(playing.get()) { wait.wait(); }; + } catch (LineUnavailableException | IOException | InterruptedException e) { + e.printStackTrace(); + } + }); + } + + public static void test() throws IOException, UnsupportedAudioFileException, LineUnavailableException { + AudioInputStream s = AudioSystem.getAudioInputStream(new File("TEST/test.wav")); + try(Clip c = AudioSystem.getClip()) { + AtomicBoolean e = new AtomicBoolean(true); + c.addLineListener(event -> { + if(event.getType() == LineEvent.Type.STOP) e.set(false); + }); + c.open(s); + + c.setFramePosition(0); + FloatControl gain = (FloatControl) c.getControl(FloatControl.Type.MASTER_GAIN); + gain.setValue(20f * (float) Math.log10(0.2)); + c.start(); + + c.loop(10); + + while(e.get()); + } + } + +} diff --git a/src/main/java/me/mrletsplay/streamdeck/StreamDeck.java b/src/main/java/me/mrletsplay/streamdeck/StreamDeck.java new file mode 100644 index 0000000..38cf62d --- /dev/null +++ b/src/main/java/me/mrletsplay/streamdeck/StreamDeck.java @@ -0,0 +1,37 @@ +package me.mrletsplay.streamdeck; + +import me.mrletsplay.simplehttpserver.http.server.HttpServer; +import me.mrletsplay.streamdeck.action.ActionSerializer; +import me.mrletsplay.streamdeck.api.StreamDeckAPI; +import me.mrletsplay.streamdeck.deck.Deck; +import me.mrletsplay.streamdeck.exception.InitializationException; + +public class StreamDeck { + + private static Deck deck; + + public static void main(String[] args) throws InitializationException { + deck = new Deck(20); + + ActionSerializer.initialize(); + Soundboard.initialize(); + + HttpServer server = new HttpServer(HttpServer.newConfigurationBuilder() + .hostBindAll() + .port(5734) + .create()); + + new StreamDeckAPI().register(server.getDocumentProvider()); + + server.start(); + + Runtime.getRuntime().addShutdownHook(new Thread(() -> { + Soundboard.finish(); + })); + } + + public static Deck getDeck() { + return deck; + } + +} diff --git a/src/main/java/me/mrletsplay/streamdeck/action/Action.java b/src/main/java/me/mrletsplay/streamdeck/action/Action.java new file mode 100644 index 0000000..c017db0 --- /dev/null +++ b/src/main/java/me/mrletsplay/streamdeck/action/Action.java @@ -0,0 +1,14 @@ +package me.mrletsplay.streamdeck.action; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Target(ElementType.TYPE) +@Retention(RetentionPolicy.RUNTIME) +public @interface Action { + + String value(); + +} diff --git a/src/main/java/me/mrletsplay/streamdeck/action/ActionParameter.java b/src/main/java/me/mrletsplay/streamdeck/action/ActionParameter.java new file mode 100644 index 0000000..fef38be --- /dev/null +++ b/src/main/java/me/mrletsplay/streamdeck/action/ActionParameter.java @@ -0,0 +1,14 @@ +package me.mrletsplay.streamdeck.action; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Target(ElementType.FIELD) +@Retention(RetentionPolicy.RUNTIME) +public @interface ActionParameter { + + String name() default ""; + +} diff --git a/src/main/java/me/mrletsplay/streamdeck/action/ActionSerializationException.java b/src/main/java/me/mrletsplay/streamdeck/action/ActionSerializationException.java new file mode 100644 index 0000000..90142e5 --- /dev/null +++ b/src/main/java/me/mrletsplay/streamdeck/action/ActionSerializationException.java @@ -0,0 +1,25 @@ +package me.mrletsplay.streamdeck.action; + +public class ActionSerializationException extends Exception { + + private static final long serialVersionUID = 5454427202803805714L; + + public ActionSerializationException() { + super(); + } + + public ActionSerializationException(String message, Throwable cause) { + super(message, cause); + } + + public ActionSerializationException(String message) { + super(message); + } + + public ActionSerializationException(Throwable cause) { + super(cause); + } + + + +} diff --git a/src/main/java/me/mrletsplay/streamdeck/action/ActionSerializer.java b/src/main/java/me/mrletsplay/streamdeck/action/ActionSerializer.java new file mode 100644 index 0000000..728b148 --- /dev/null +++ b/src/main/java/me/mrletsplay/streamdeck/action/ActionSerializer.java @@ -0,0 +1,112 @@ +package me.mrletsplay.streamdeck.action; + +import java.lang.reflect.Constructor; +import java.lang.reflect.Field; +import java.lang.reflect.InvocationTargetException; +import java.util.Collections; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; + +import me.mrletsplay.mrcore.json.JSONObject; +import me.mrletsplay.mrcore.json.JSONType; +import me.mrletsplay.simplehttpserver.http.validation.JsonObjectValidator; +import me.mrletsplay.streamdeck.action.impl.PlaySoundAction; +import me.mrletsplay.streamdeck.action.impl.PressKeyAction; +import me.mrletsplay.streamdeck.exception.InitializationException; + +public class ActionSerializer { + + public static final JsonObjectValidator + ACTION_VALIDATOR = new JsonObjectValidator() + .require("type", JSONType.STRING) + .require("data", JSONType.OBJECT); + + private static final List> ACTIONS = List.of( + PlaySoundAction.class, + PressKeyAction.class + ); + + private static Map> nameToAction; + + public static void initialize() throws InitializationException { + Map> nta = new LinkedHashMap<>(); + for(var actionClass : ACTIONS) { + Action ac = actionClass.getAnnotation(Action.class); + if(ac == null) throw new InitializationException("Class " + actionClass.getName() + " is missing the @Action annotation"); + + nta.put(ac.value(), actionClass); + } + + nameToAction = Collections.unmodifiableMap(nta); + } + + public static JSONObject serializeAction(DeckAction action) throws ActionSerializationException { + if(nameToAction == null) throw new ActionSerializationException("ActionSerializer is not initialized"); + + Class actionClass = action.getClass(); + if(!ACTIONS.contains(actionClass)) throw new ActionSerializationException("Class " + actionClass.getName() + " is not a registered action class"); + + Action ac = actionClass.getAnnotation(Action.class); + + JSONObject object = new JSONObject(); + object.put("type", ac.value()); + + JSONObject data = new JSONObject(); + for(Field f : action.getClass().getDeclaredFields()) { + ActionParameter parameter = f.getAnnotation(ActionParameter.class); + if(parameter == null) continue; + + String name = !parameter.name().isEmpty() ? parameter.name() : f.getName(); + try { + f.setAccessible(true); + data.put(name, f.get(action)); + } catch (IllegalArgumentException | IllegalAccessException e) { + throw new ActionSerializationException(e); + } + } + + action.serialize(data); + + return object; + } + + public static DeckAction deserializeAction(JSONObject action) throws ActionSerializationException { + if(nameToAction == null) throw new ActionSerializationException("ActionSerializer is not initialized"); + + String actionType = action.optString("type").orElseThrow(() -> new ActionSerializationException("Missing action type")); + Class actionClass = nameToAction.get(actionType); + if(actionClass == null) throw new ActionSerializationException("Action doesn't exist"); + + JSONObject data = action.optJSONObject("data").orElseThrow(() -> new ActionSerializationException("Missing data")); + + try { + Constructor constr = actionClass.getDeclaredConstructor(); + constr.setAccessible(true); + DeckAction a = constr.newInstance(); + + for(Field f : action.getClass().getDeclaredFields()) { + ActionParameter parameter = f.getAnnotation(ActionParameter.class); + if(parameter == null) continue; + + String name = !parameter.name().isEmpty() ? parameter.name() : f.getName(); + try { + f.setAccessible(true); + + // TODO: allow JSONSerializable + f.set(a, JSONType.castJSONValueTo(data.get(name), f.getType())); + } catch (IllegalArgumentException | IllegalAccessException e) { + throw new ActionSerializationException(e); + } + } + + a.deserialize(data); + } catch (InstantiationException | IllegalAccessException | IllegalArgumentException | InvocationTargetException | NoSuchMethodException | SecurityException e) { + throw new ActionSerializationException(e); + } + + + return null; + } + +} diff --git a/src/main/java/me/mrletsplay/streamdeck/action/DeckAction.java b/src/main/java/me/mrletsplay/streamdeck/action/DeckAction.java new file mode 100644 index 0000000..2ab638a --- /dev/null +++ b/src/main/java/me/mrletsplay/streamdeck/action/DeckAction.java @@ -0,0 +1,40 @@ +package me.mrletsplay.streamdeck.action; + +import java.util.Collections; +import java.util.List; + +import me.mrletsplay.mrcore.json.JSONObject; + +public interface DeckAction { + + /** + * Useful if parameters can't be directly mapped to JSON types.
+ * By default, this does nothing but may be implemented if needed + * @param data The action data + * @throws ActionSerializationException If the action can't be deserialized + */ + public default void deserialize(JSONObject data) throws ActionSerializationException {} + + /** + * Must be implemented to correspond to {@link #deserialize(JSONObject)}.
+ * By default, this does nothing but may be implemented if needed + * @param data The action data + * @throws ActionSerializationException If the action can't be serialized + */ + public default void serialize(JSONObject data) throws ActionSerializationException {} + + /** + * Validates the action and returns a list of errors, or an empty list if there are no errors.
+ * By default, this does nothing but may be implemented to add further validation + * @return A list of errors, or an empty list if there are no errors + */ + public default List validate() { + return Collections.emptyList(); + } + + /** + * Runs the action + */ + public void run(); + +} diff --git a/src/main/java/me/mrletsplay/streamdeck/action/impl/PlaySoundAction.java b/src/main/java/me/mrletsplay/streamdeck/action/impl/PlaySoundAction.java new file mode 100644 index 0000000..485c578 --- /dev/null +++ b/src/main/java/me/mrletsplay/streamdeck/action/impl/PlaySoundAction.java @@ -0,0 +1,18 @@ +package me.mrletsplay.streamdeck.action.impl; + +import me.mrletsplay.streamdeck.action.Action; +import me.mrletsplay.streamdeck.action.ActionParameter; +import me.mrletsplay.streamdeck.action.DeckAction; + +@Action("play_sound") +public final class PlaySoundAction implements DeckAction { + + @ActionParameter + private String soundPath; + + @Override + public void run() { + + } + +} diff --git a/src/main/java/me/mrletsplay/streamdeck/action/impl/PressKeyAction.java b/src/main/java/me/mrletsplay/streamdeck/action/impl/PressKeyAction.java new file mode 100644 index 0000000..58a7da1 --- /dev/null +++ b/src/main/java/me/mrletsplay/streamdeck/action/impl/PressKeyAction.java @@ -0,0 +1,33 @@ +package me.mrletsplay.streamdeck.action.impl; + +import java.awt.AWTException; +import java.awt.Robot; + +import me.mrletsplay.streamdeck.action.Action; +import me.mrletsplay.streamdeck.action.ActionParameter; +import me.mrletsplay.streamdeck.action.DeckAction; + +@Action("press_key") +public final class PressKeyAction implements DeckAction { + + private static Robot robot; + + static { + try { + robot = new Robot(); + } catch (AWTException e) { + throw new RuntimeException(e); + } + } + + @ActionParameter + private int key; + + @Override + public void run() { + robot.keyPress(key); + robot.delay(100); + robot.keyRelease(key); + } + +} diff --git a/src/main/java/me/mrletsplay/streamdeck/api/StreamDeckAPI.java b/src/main/java/me/mrletsplay/streamdeck/api/StreamDeckAPI.java new file mode 100644 index 0000000..057c0a7 --- /dev/null +++ b/src/main/java/me/mrletsplay/streamdeck/api/StreamDeckAPI.java @@ -0,0 +1,149 @@ +package me.mrletsplay.streamdeck.api; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.util.Base64; + +import javax.imageio.ImageIO; + +import me.mrletsplay.mrcore.json.JSONArray; +import me.mrletsplay.mrcore.json.JSONObject; +import me.mrletsplay.mrcore.json.JSONType; +import me.mrletsplay.simplehttpserver.http.HttpRequestMethod; +import me.mrletsplay.simplehttpserver.http.HttpStatusCodes; +import me.mrletsplay.simplehttpserver.http.endpoint.Endpoint; +import me.mrletsplay.simplehttpserver.http.endpoint.EndpointCollection; +import me.mrletsplay.simplehttpserver.http.header.DefaultClientContentTypes; +import me.mrletsplay.simplehttpserver.http.request.HttpRequestContext; +import me.mrletsplay.simplehttpserver.http.response.JsonResponse; +import me.mrletsplay.simplehttpserver.http.validation.JsonArrayValidator; +import me.mrletsplay.simplehttpserver.http.validation.JsonObjectValidator; +import me.mrletsplay.simplehttpserver.http.validation.result.ValidationResult; +import me.mrletsplay.streamdeck.StreamDeck; +import me.mrletsplay.streamdeck.action.ActionSerializationException; +import me.mrletsplay.streamdeck.action.ActionSerializer; +import me.mrletsplay.streamdeck.action.DeckAction; +import me.mrletsplay.streamdeck.deck.DeckButton; + +public class StreamDeckAPI implements EndpointCollection { + + private static final JsonObjectValidator + BUTTON_VALIDATOR = new JsonObjectValidator() + .require("id", JSONType.INTEGER) + .optional("icon", JSONType.STRING) + .optionalObject("action", ActionSerializer.ACTION_VALIDATOR), + STATE_VALIDATOR = new JsonObjectValidator() + .requireArray("buttons", new JsonArrayValidator() + .requireElementObjects(BUTTON_VALIDATOR)); + + private static JsonResponse error(String errorMessage) { + JSONObject error = new JSONObject(); + error.put("error", errorMessage); + return new JsonResponse(error); + } + + @Endpoint(method = HttpRequestMethod.GET, path = "/actions") + public void getActions() { + // TODO + } + + @Endpoint(method = HttpRequestMethod.GET, path = "/state") + public void getState() { + HttpRequestContext ctx = HttpRequestContext.getCurrentContext(); + JSONObject state = new JSONObject(); + + JSONArray buttons = new JSONArray(); + for(DeckButton button : StreamDeck.getDeck().getButtons()) { + JSONObject buttonObj = new JSONObject(); + buttonObj.put("id", button.getId()); + + if(button.getIcon() == null) { + buttonObj.put("icon", null); + }else { + try { + ByteArrayOutputStream bOut = new ByteArrayOutputStream(); + ImageIO.write(button.getIcon(), "PNG", bOut); + }catch(IOException e) { + ctx.respond(HttpStatusCodes.INTERNAL_SERVER_ERROR_500, error("Failed to serialize icon: " + e.getMessage())); + return; + } + } + + if(button.getAction() == null) { + buttonObj.put("action", null); + }else { + try { + buttonObj.put("action", ActionSerializer.serializeAction(button.getAction())); + }catch(ActionSerializationException e) { + ctx.respond(HttpStatusCodes.INTERNAL_SERVER_ERROR_500, error("Failed to serialize action " + e.getMessage())); + return; + } + } + + buttons.add(buttonObj); + } + + state.put("buttons", buttons); + + ctx.respond(HttpStatusCodes.OK_200, new JsonResponse(buttons)); + } + + @Endpoint(method = HttpRequestMethod.PATCH, path = "/state") + public void updateState() { + HttpRequestContext ctx = HttpRequestContext.getCurrentContext(); + JSONObject content; + if((content = ctx.expectContent(DefaultClientContentTypes.JSON_OBJECT)) == null) { + ctx.respond(HttpStatusCodes.BAD_REQUEST_400, error("Invalid content")); + return; + } + + ValidationResult result = STATE_VALIDATOR.validate(content); + if(!result.isOk()) { + ctx.respond(HttpStatusCodes.BAD_REQUEST_400, result.asJsonResponse()); + return; + } + + for(Object o : content.getJSONArray("buttons")) { + JSONObject buttonObj = (JSONObject) o; + int id = buttonObj.getInt("id"); + DeckButton button = StreamDeck.getDeck().getButton(id); + + if(buttonObj.has("icon")) { + String icon = buttonObj.getString("icon"); + if(icon == null) { + button.setIcon(null); + }else { + try { + button.setIcon(ImageIO.read(new ByteArrayInputStream(Base64.getDecoder().decode(icon)))); + } catch (IOException | IllegalArgumentException e) { + ctx.respond(HttpStatusCodes.BAD_REQUEST_400, error("Invalid icon")); + } + } + } + + if(buttonObj.has("action")) { + JSONObject action = buttonObj.getJSONObject("action"); + if(action == null) { + button.setAction(null); + }else { + DeckAction newAction; + try { + newAction = ActionSerializer.deserializeAction(action); + } catch (ActionSerializationException e) { + ctx.respond(HttpStatusCodes.BAD_REQUEST_400, error("Invalid action: " + e.getMessage())); + return; + } + + button.setAction(newAction); + } + } + } + } + + @Override + public String getBasePath() { + return "/api"; + } + +} diff --git a/src/main/java/me/mrletsplay/streamdeck/deck/Deck.java b/src/main/java/me/mrletsplay/streamdeck/deck/Deck.java new file mode 100644 index 0000000..67f284f --- /dev/null +++ b/src/main/java/me/mrletsplay/streamdeck/deck/Deck.java @@ -0,0 +1,26 @@ +package me.mrletsplay.streamdeck.deck; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +public class Deck { + + private List buttons; + + public Deck(int buttonCount) { + List buttons = new ArrayList<>(buttonCount); + for(int i = 0; i < buttonCount; i++) buttons.add(new DeckButton(i)); + this.buttons = Collections.unmodifiableList(buttons); + } + + public List getButtons() { + return buttons; + } + + public DeckButton getButton(int id) { + if(id < 0 || id >= buttons.size()) return null; + return buttons.get(id); + } + +} diff --git a/src/main/java/me/mrletsplay/streamdeck/deck/DeckButton.java b/src/main/java/me/mrletsplay/streamdeck/deck/DeckButton.java new file mode 100644 index 0000000..87b4855 --- /dev/null +++ b/src/main/java/me/mrletsplay/streamdeck/deck/DeckButton.java @@ -0,0 +1,37 @@ +package me.mrletsplay.streamdeck.deck; + +import java.awt.image.BufferedImage; + +import me.mrletsplay.streamdeck.action.DeckAction; + +public class DeckButton { + + private int id; + private BufferedImage icon; + private DeckAction action; + + public DeckButton(int id) { + this.id = id; + } + + public int getId() { + return id; + } + + public void setIcon(BufferedImage icon) { + this.icon = icon; + } + + public BufferedImage getIcon() { + return icon; + } + + public void setAction(DeckAction action) { + this.action = action; + } + + public DeckAction getAction() { + return action; + } + +} diff --git a/src/main/java/me/mrletsplay/streamdeck/exception/InitializationException.java b/src/main/java/me/mrletsplay/streamdeck/exception/InitializationException.java new file mode 100644 index 0000000..8dd00a7 --- /dev/null +++ b/src/main/java/me/mrletsplay/streamdeck/exception/InitializationException.java @@ -0,0 +1,23 @@ +package me.mrletsplay.streamdeck.exception; + +public class InitializationException extends Exception { + + private static final long serialVersionUID = 8812199845001173928L; + + public InitializationException() { + super(); + } + + public InitializationException(String message, Throwable cause) { + super(message, cause); + } + + public InitializationException(String message) { + super(message); + } + + public InitializationException(Throwable cause) { + super(cause); + } + +} diff --git a/src/main/java/me/mrletsplay/streamdeck/exception/SoundboardException.java b/src/main/java/me/mrletsplay/streamdeck/exception/SoundboardException.java new file mode 100644 index 0000000..68bc789 --- /dev/null +++ b/src/main/java/me/mrletsplay/streamdeck/exception/SoundboardException.java @@ -0,0 +1,23 @@ +package me.mrletsplay.streamdeck.exception; + +public class SoundboardException extends Exception { + + private static final long serialVersionUID = 8790973950212930162L; + + public SoundboardException() { + super(); + } + + public SoundboardException(String message, Throwable cause) { + super(message, cause); + } + + public SoundboardException(String message) { + super(message); + } + + public SoundboardException(Throwable cause) { + super(cause); + } + +}