GUI app for reading Flicker codes from screen
authorMichael Schierl <schierlm@gmx.de>
Wed, 6 Jun 2012 21:48:00 +0000 (23:48 +0200)
committerAndreas Schiermeier <andreas@schiermeier.name>
Sun, 25 Oct 2015 13:51:51 +0000 (14:51 +0100)
Match the flickering pixels with the dents in the program window
and observe the decoded data on stdout.

As this program uses a shape on a window with a title bar, which
is not officially supported by Java, this may break on some systems.

However, it was tested and working on Windows and Linux in Java 6/7.

chiptan/flicker/FlickerReader.java [new file with mode: 0644]

diff --git a/chiptan/flicker/FlickerReader.java b/chiptan/flicker/FlickerReader.java
new file mode 100644 (file)
index 0000000..fe2b52d
--- /dev/null
@@ -0,0 +1,161 @@
+// Small GUI app for reading Flicker codes from screen
+// Michael Schierl <schierlm@gmx.de>
+
+import java.awt.*;
+import java.awt.event.*;
+import java.awt.image.*;
+
+import com.sun.awt.AWTUtilities;
+
+public class FlickerReader extends Frame {
+
+       private int xFirst, dx;
+       Rectangle grabRect;
+
+       public FlickerReader() throws Exception {
+               setLayout(new BorderLayout());
+               Container panel = new Container();
+               add(panel, BorderLayout.CENTER);
+               setBackground(Color.LIGHT_GRAY);
+               setLocationRelativeTo(null);
+               setSize(200, 200);
+               ComponentAdapter ca = new ComponentAdapter() {
+                       @Override
+                       public void componentResized(ComponentEvent e) {
+                               updateShape();
+                       }
+
+                       @Override
+                       public void componentMoved(ComponentEvent e) {
+                               updateRect();
+                       }
+               };
+
+               panel.addComponentListener(ca);
+               addComponentListener(ca);
+
+               addWindowListener(new WindowAdapter() {
+                       @Override
+                       public void windowClosing(WindowEvent e) {
+                               System.exit(0);
+                       }
+               });
+
+               updateShape();
+               setVisible(true);
+               Thread.sleep(100);
+               Robot robot = new Robot();
+               int[] pixel = new int[3];
+               int whitecount = 0, blackcount = 0;
+               State state = State.SYNC;
+               // now start reading
+               while (true) {
+                       Thread.sleep(10);
+                       BufferedImage img = robot.createScreenCapture(grabRect);
+                       Raster rast = img.getData();
+                       pixel = rast.getPixel(xFirst, 0, pixel);
+                       if (pixel[0] == pixel[1] && pixel[1] == pixel[2]) {
+                               if (pixel[0] == 255) {
+                                       switch (state) {
+                                       case BLACK:
+                                               setTitle(whitecount + " / " + blackcount + " - FlickerReader");
+                                               // fall-through
+                                       case SYNC:
+                                               state = State.WHITE;
+                                               whitecount = 1;
+                                               blackcount = 0;
+                                               break;
+                                       case WHITE:
+                                               whitecount++;
+                                               break;
+                                       }
+                               } else if (pixel[0] == 0) {
+                                       switch (state) {
+                                       case SYNC:
+                                               break;
+                                       case BLACK:
+                                               blackcount++;
+                                               break;
+                                       case WHITE:
+                                               if (!readNibble(pixel, rast, xFirst, dx)) {
+                                                       state = State.SYNC;
+                                               } else {
+                                                       state = State.BLACK;
+                                               }
+                                               break;
+                                       }
+                               } else {
+                                       state = State.SYNC;
+                               }
+                       } else {
+                               state = State.SYNC;
+                       }
+                       if (state == State.SYNC && whitecount != 0) {
+                               setTitle("SYNC - FlickerReader");
+                               whitecount = 0;
+                       }
+               }
+       }
+
+       private void updateShape() {
+               updateRect();
+
+               int width = getWidth();
+               int halfdx = width / 12;
+               dx = halfdx * 2;
+               int border = (width - dx * 6) / 2;
+               xFirst = border + dx;
+
+               int h0 = getHeight();
+               int h1 = h0 - 40;
+               int h2 = h0 - 20;
+               int[] xPoints = new int[17];
+               int[] yPoints = new int[17];
+               for (int i = 1; i <= 11; i++) {
+                       xPoints[i + 2] = border + halfdx * i;
+                       yPoints[i + 2] = i % 2 == 1 ? h1 : h2;
+               }
+               xPoints[0] = xPoints[1] = 0;
+               xPoints[2] = xPoints[3];
+               xPoints[14] = xPoints[13];
+               xPoints[15] = xPoints[16] = width;
+
+               yPoints[0] = yPoints[16] = 0;
+               yPoints[1] = yPoints[2] = yPoints[14] = yPoints[15] = h0;
+
+               AWTUtilities.setWindowShape(this, new Polygon(xPoints, yPoints, 17));
+       }
+
+       private void updateRect() {
+               grabRect = getBounds();
+               grabRect.y = grabRect.y + grabRect.height - 20;
+               grabRect.height = 1;
+       }
+
+       private boolean readNibble(int[] pxl, Raster rast, int x, int dx) {
+               int nibble = 0;
+               for (int i = 0; i < 4; i++) {
+                       x += dx;
+                       rast.getPixel(x, 0, pxl);
+                       if (pxl[0] != pxl[1] || pxl[1] != pxl[2] || (pxl[0] != 0 && pxl[0] != 255))
+                               return false;
+                       if (pxl[0] == 255)
+                               nibble |= (1 << i);
+               }
+               System.out.print(Integer.toHexString(nibble));
+               return true;
+       }
+
+       // dirty hack for Java 6 which does not support shapes for decorated windows
+       public boolean isUndecorated() {
+               return true;
+       }
+
+       public static void main(String[] args) throws Exception {
+               new FlickerReader();
+       }
+
+       private static enum State {
+               SYNC, WHITE, BLACK
+       }
+}