sclass ScreenLens { double sleep = 0; // 0.2; int w = 300, h = 300; ImageSurface is; volatile BufferedImage image, imagePP; // pp = postProcessed bool keepAwayFromBorder = true, makeBot = false; bool showFPS = true; S botName = "Screen Lens."; Android3 bot; // exporting our functionality as bot to other VMs bool pack = true; new PerSecondCounter fps; javax.swing.Timer timer; O onImageChange; O postProcess; // func(BufferedImage) => BufferedImage ScreenLens start() { swingAndWait(r { is = alwaysOnTop(showImage(new RGBImage(w, h, Color.white))); timer = installTimer(is, toMS(sleep), r { Pt m = new Pt(mouseLocation()); Rect screen = screenRect(); if (keepAwayFromBorder) { m = new Pt(min(m.x, screen.x2()-w/2), min(m.y, screen.y2()-h/2)); m = new Pt(max(m.x, w/2), max(m.y, h/2)); } Rect r = intersectRects(screen, rectAround(m, w, h)); image = shootScreen2(r); imagePP = callPostProcessor(postProcess, image); is.setImage(imagePP); if (pack) { packFrame(lens.is); moveToTopRightCorner(getFrame(lens.is)); } pack = false; fps.inc(); if (showFPS) setFrameTitle(is, "Screen Lens (" + iround(fps.get()) + " fps)"); pcallF(onImageChange); }); }); addSizeChooser(); if (makeBot) bot = makeBot(botName, this); this; } void addSizeChooser() { final JTextField tfSize = jTextField(w); addToWindow(is, jRightAlignedLine(jlabel("Size:"), jMinWidth(50, tfSize), jlabel("pixels"))); onUpdate(tfSize, r { w = h = max(1, parseIntOpt(getTextTrim(tfSize))); pack = true; }); } S answer(S s) { new Matches m; if "get image" ret image == null ? "null" : structure(new RGBImage(image)); if "get post processed image" ret imagePP == null ? "null" : structure(new RGBImage(imagePP)); if "running" ret yn(timer.isRunning()); null; } }