Use stack of modes instead of just one
[kaka/cakelight.git] / src / kaka / cakelight / CakeLight.java
index afc7b26..0c1aa1a 100644 (file)
@@ -1,32 +1,77 @@
 package kaka.cakelight;
 
-import static kaka.cakelight.Main.timeIt;
+import kaka.cakelight.mode.Mode;
+import org.jnativehook.GlobalScreen;
+import org.jnativehook.NativeHookException;
+import org.jnativehook.keyboard.NativeKeyAdapter;
+import org.jnativehook.keyboard.NativeKeyEvent;
+import org.jnativehook.mouse.NativeMouseEvent;
+import org.jnativehook.mouse.NativeMouseMotionAdapter;
+
+import java.util.Objects;
+import java.util.Stack;
 
 public class CakeLight {
     private Configuration config;
-    private Mode mode;
+    private Stack<Mode> modes = new Stack<>();
+    private LedController ledController;
 
-    public CakeLight(Configuration config) {
+    public CakeLight(Configuration config, LedController ledController) {
         this.config = config;
+        this.ledController = ledController;
+        Color.calculateGammaCorrection(config.gamma);
     }
 
     public void setMode(Mode mode) {
         cleanup();
-        this.mode = mode;
-        mode.enter(config);
+        pushMode(mode);
     }
 
     public void cleanup() {
-        if (this.mode != null) {
-            this.mode.exit();
+        while (popMode());
+    }
+
+    public void pushMode(Mode mode) {
+        Objects.requireNonNull(mode);
+        if (!modes.isEmpty()) {
+            stopMode(modes.peek());
         }
+        modes.push(mode);
+        startMode(mode);
+        // TODO: create a composite fading mode of top of stack and new mode
+    }
+
+    public boolean popMode() {
+        if (!modes.isEmpty()) {
+            Mode mode = modes.pop();
+            stopMode(mode);
+            if (!modes.isEmpty()) {
+                startMode(modes.peek());
+            }
+            return true;
+        }
+        return false;
+        // TODO: create a composite fading mode of popped mode and top of stack, unless doing cleanup
+    }
+
+    private void startMode(Mode mode) {
+        mode.setFrameListener(ledController::onFrame);
+        mode.enter(config);
+    }
+
+    private void stopMode(Mode mode) {
+        mode.setFrameListener(ledFrame -> {}); // To avoid any frame being sent to the controller while the thread is exiting
+        mode.exit();
     }
 
     public void startLoop() {
+        Console console = Console.start(this, config);
+        PipeController.start(console);
+//        initNativeHook();
         // TODO
 //        FrameGrabber grabber = FrameGrabber.from(config);
 //        grabber.prepare();
-//        Frame frame = grabber.grabFrame();
+//        VideoFrame frame = grabber.grabFrame();
 //        double time = 0;
 //        for (int i = 0; i < 100; i++) {
 //            time += timeIt("frame", () -> grabber.grabFrame());
@@ -36,4 +81,29 @@ public class CakeLight {
 //     byte[] data = frame.getData();
 //     saveFile(data, "/home/kaka/test.img");
     }
+
+    private void initNativeHook() {
+        try {
+            GlobalScreen.registerNativeHook();
+            GlobalScreen.addNativeKeyListener(new NativeKeyAdapter() {
+                @Override
+                public void nativeKeyPressed(NativeKeyEvent e) {
+                    System.out.println("key code = " + e.getKeyCode() + ", key text = '" + NativeKeyEvent.getKeyText(e.getKeyCode()) + "'");
+                }
+            });
+            GlobalScreen.addNativeMouseMotionListener(new NativeMouseMotionAdapter() {
+                @Override
+                public void nativeMouseMoved(NativeMouseEvent e) {
+                    System.out.println("mouse point = " + e.getPoint());
+                }
+            });
+        } catch (NativeHookException e) {
+            e.printStackTrace();
+        }
+    }
+
+    public void turnOff() {
+        cleanup();
+        ledController.onFrame(LedFrame.from(config).fillColor(0, 0, 0));
+    }
 }