!7 srecord MouseEvt(bool mouseDown, Pt p) { long time = sysNow(); } module MiniVNC > DynImageSurface { bool enabled, usePossiblyBrokenVersion = true; S computerID; int width = 256; double videoInterval = 2.0, mouseInterval = 0.1; transient int discardEventsAfter = 10000; transient Pt mousePosition; transient bool sentMouseButton; transient L events = syncList(); transient Pt sentMousePosition; S switchableFields() { ret "usePossiblyBrokenVersion videoInterval"; } start { doEvery(videoInterval, r grab); doEvery(mouseInterval, r moveMouse); } visualize { JComponent c = super.visualize(); enableDoubleBuffering(); imageSurfaceOnMouseMove(imageSurface, voidfunc(Pt p) { mousePosition = p }); disableImageSurfaceSelector(imageSurface); addMouseListener(imageSurface, new MouseAdapter { public void mousePressed(MouseEvent evt) { if (!actuallyEnabled() || evt.getButton() != MouseEvent.BUTTON1) return; events.add(MouseEvt(true, imageSurface.pointFromEvent(evt))); } public void mouseReleased(MouseEvent evt) { if (!actuallyEnabled() || evt.getButton() != MouseEvent.BUTTON1) return; events.add(MouseEvt(false, imageSurface.pointFromEvent(evt))); } }); ret northAndCenterWithMargins(vstackWithSpacing( centerAndEastWithMargins( withLabel("Computer to control:", dm_onlineComputerSelectorComboBox(dm_fieldLiveValue('computerID))), dm_fieldCheckBox('enabled)), jRightAlignedLine(jLabel("Resize to width (pixels):"), jMinWidth(100, jLiveValueIntTextField(dm_fieldLiveValue('width))))), c); } bool actuallyEnabled() { ret enabled && possibleComputerID(computerID) && dm_isVisible(); } void grab enter { if (!actuallyEnabled()) ret; time "Get Screenshot" { setImage(dm_scaledDownScreenshotFromOtherMachine(computerID, width, +usePossiblyBrokenVersion)); } } void moveMouse enter { if (!actuallyEnabled()) { sentMousePosition = null; sentMouseButton = false; ret; } LinkedList events = cloneAndClearAsLinkedList(this.events); // drop old events (if network was down) bool sendMouseUp = false; while (nempty(events) && elapsedMS(first(events).time) >= discardEventsAfter) { if (!first(events).mouseDown) set sendMouseUp; // don't drop that popFirst(events); } if (sendMouseUp) dm_evalOnOtherMachine(computerID, "robot_leftMouseUp()"); // send mouse click/release events for (MouseEvt e : events) { dm_evalOnOtherMachine(computerID, "robot_leftMouseButtonPressOrRelease_scaled(" + e.mouseDown + ", " + e.p.x + ", " + e.p.y + ", " + width + ")"); sentMousePosition = e.p; sentMouseButton = e.mouseDown; } // send mouse position Pt p = mousePosition; if (neq(p, sentMousePosition)) { sentMousePosition = p; if (p != null) { time "Move Mouse On Other Machine" { dm_evalOnOtherMachine(computerID, "dm_moveMouseImmediate_direct_scaled(" + p.x + ", " + p.y + ", " + width + ")"); } } } } }