aboutsummaryrefslogtreecommitdiffstats
path: root/tools/gbtype
diff options
context:
space:
mode:
Diffstat (limited to 'tools/gbtype')
-rwxr-xr-xtools/gbtype79
1 files changed, 79 insertions, 0 deletions
diff --git a/tools/gbtype b/tools/gbtype
new file mode 100755
index 0000000..f58a1f8
--- /dev/null
+++ b/tools/gbtype
@@ -0,0 +1,79 @@
+#!/usr/bin/env python3
+"""gbtype - inject shell input into a running gbhub Game Boy, no OSK needed.
+
+The Game Boy's link port *is* its console when nothing SLIP-frames the bytes,
+so text sent over the hub's control socket lands straight on the shell's stdin
+- exactly as if typed on the on-screen keyboard, but driven from your host.
+
+Start the hub first (in another terminal): sudo tools/gbhub --daemon
+
+ tools/gbtype 'ls -l' run 'ls -l' on GB0 (a trailing Enter is added)
+ tools/gbtype -g 1 ps target GB1 (the Nth joined Game Boy)
+ tools/gbtype -n abc type 'abc' but no Enter (leave it on the line)
+ tools/gbtype -r just press Enter
+ tools/gbtype -l list the connected Game Boys
+ printf 'ls\\ncat readme\\n' | tools/gbtype pipe a script via stdin
+
+Options must come before the command; the first non-option word starts the
+literal text (so 'gbtype ls -l' needs no quoting, and '-l' there is not --list).
+No root needed - the hub opens the control socket world-connectable."""
+import os, sys, socket
+
+CTL = "/tmp/gbhub.ctl"
+
+def usage(code=0):
+ (sys.stdout if code == 0 else sys.stderr).write(__doc__ + "\n")
+ sys.exit(code)
+
+def send(header, payload=b""):
+ if not os.path.exists(CTL):
+ sys.exit("gbtype: no hub control socket at %s\n"
+ " start it first: sudo tools/gbhub --daemon" % CTL)
+ s = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
+ try: s.connect(CTL)
+ except OSError as e: sys.exit("gbtype: cannot connect %s (%s)" % (CTL, e))
+ s.sendall(header + b"\n" + payload)
+ s.shutdown(socket.SHUT_WR) # end-of-payload marker for the hub
+ out = b""
+ while True:
+ try: d = s.recv(4096)
+ except Exception: break
+ if not d: break
+ out += d
+ s.close()
+ sys.stdout.write(out.decode(errors="replace"))
+
+def main():
+ args = sys.argv[1:]
+ idx = None
+ newline = True
+ i = 0
+ while i < len(args):
+ a = args[i]
+ if a in ("-h", "--help"): usage(0)
+ elif a in ("-l", "--list"): send(b"list"); return
+ elif a in ("-g", "--gb"):
+ i += 1
+ if i >= len(args): usage(1)
+ idx = args[i]
+ elif a in ("-n", "--no-enter"): newline = False
+ elif a in ("-r", "--enter"):
+ send(b"type" + (b" " + idx.encode() if idx else b""), b"\n"); return
+ elif a == "--": i += 1; break
+ elif a.startswith("-") and len(a) > 1:
+ sys.stderr.write("gbtype: unknown option %s\n" % a); usage(1)
+ else: break # first positional: rest is literal text
+ i += 1
+
+ words = args[i:]
+ if words:
+ payload = " ".join(words).encode() + (b"\n" if newline else b"")
+ else:
+ payload = sys.stdin.buffer.read() # piped script, sent verbatim
+ if newline and payload and not payload.endswith(b"\n"):
+ payload += b"\n"
+
+ send(b"type" + (b" " + idx.encode() if idx is not None else b""), payload)
+
+if __name__ == "__main__":
+ main()