Last active
August 4, 2025 02:00
-
-
Save Vftdan/ab61531879c3660911537e3c73d7ef71 to your computer and use it in GitHub Desktop.
ComputerCraft monitor & keyboard environment
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| local keyboardEvents = {["char"] = true, ["key"] = true, ["key_up"] = true} | |
| local touchButtonId = 1 | |
| local useParentKeyboard = true | |
| local useTmKeyboards = {} | |
| local monName = nil | |
| local scale = nil | |
| local seat = {monitor = nil, co = nil, monitorName = nil} | |
| local args = {...} | |
| local argi = 0 | |
| local posArg = #args + 1 | |
| while argi < #args do | |
| argi = argi + 1 | |
| local opt = args[argi] | |
| if opt == "--monitor" or opt == "-m" then | |
| argi = argi + 1 | |
| monName = args[argi] | |
| if not monName then | |
| printError("Monitor name expected") | |
| return | |
| end | |
| elseif opt == "--no-parent-keys" or opt == "-n" then | |
| useParentKeyboard = false | |
| elseif opt == "--keyboard" or opt == "-k" then | |
| argi = argi + 1 | |
| local kbName = args[argi] | |
| if not kbName then | |
| printError("Keyboard device name expected") | |
| return | |
| end | |
| useTmKeyboards[kbName] = true | |
| elseif opt == "--scale" or opt == "-s" then | |
| argi = argi + 1 | |
| local scaleStr = args[argi] | |
| if not scaleStr then | |
| printError("Scale value expected") | |
| return | |
| end | |
| scale = tonumber(scaleStr) | |
| if scale == nil then | |
| printError("Scale is not a number") | |
| return | |
| elseif scale < 0.5 or scale > 5 then | |
| printError("Monitor scale is out of range") | |
| return | |
| end | |
| elseif opt == "--button" or opt == "-b" then | |
| argi = argi + 1 | |
| local btnStr = args[argi] | |
| if not btnStr then | |
| printError("Mouse button id expected") | |
| return | |
| end | |
| if btnStr == "left" then | |
| touchButtonId = 1 | |
| elseif btnStr == "right" then | |
| touchButtonId = 2 | |
| elseif btnStr == "middle" then | |
| touchButtonId = 3 | |
| else | |
| touchButtonId = tonumber(btnStr) | |
| if not touchButtonId then | |
| printError("Invalid mouse button") | |
| return | |
| end | |
| if touchButtonId < 1 or touchButtonId > 3 then | |
| printError("Mouse button is out of range") | |
| return | |
| end | |
| end | |
| elseif opt == "--help" or opt == "-h" then | |
| print("Usage: startseat [OPTIONS] [--] [COMMAND]") | |
| print("Options:") | |
| print(" -m, --monitor <NAME|auto> Use this monitor instead of the parent terminal.") | |
| print(" -n, --no-parent-keys Don't pass parent terminal keyboard events through.") | |
| print(" -k, --keyboard <NAME|all> Convert Tom's Peripherals keyboard events into terminal events.") | |
| print(" -s, --scale <NUM> Set the monitor scale.") | |
| print(" -b, --button <NUM|left|right|middle> Convert monitor touches to this mouse button.") | |
| return | |
| elseif opt == "--" then | |
| posArg = argi + 1 | |
| break | |
| elseif opt:sub(1, 1) == "-" then | |
| printError("Unknown option: " .. opt) | |
| return | |
| else | |
| posArg = argi | |
| break | |
| end | |
| end | |
| if scale and not monName then | |
| printError("Cannot set scale when not using a monitor") | |
| return | |
| end | |
| local cmd = {table.unpack(args, posArg)} | |
| if monName then | |
| if monName == "auto" then | |
| seat.monitor = peripheral.find("monitor") | |
| if not seat.monitor then | |
| printError("No monitors attached") | |
| return | |
| end | |
| seat.monitorName = peripheral.getName(seat.monitor) | |
| else | |
| if peripheral.getType(monName) ~= "monitor" then | |
| printError("Not a monitor: " .. monName) | |
| return | |
| end | |
| seat.monitor = peripheral.wrap(monName) | |
| seat.monitorName = monName | |
| end | |
| if scale then | |
| seat.monitor.setTextScale(scale) | |
| end | |
| else | |
| local w, h = term.getSize() | |
| seat.monitor = window.create(term.current(), 1, 1, w, h) | |
| end | |
| seat.co = coroutine.create(function() | |
| local prg = "shell" | |
| if multishell then | |
| prg = "multishell" | |
| end | |
| local prgPath = shell.resolveProgram(prg) | |
| os.run({shell = shell}, prgPath, table.unpack(cmd)) | |
| end) | |
| local function resume(seat, ...) | |
| local oldTerm = term.redirect(seat.monitor) | |
| local ok, wantEvent = coroutine.resume(seat.co, ...) | |
| term.redirect(oldTerm) | |
| if not ok then | |
| printError(wantEvent) | |
| end | |
| return wantEvent | |
| end | |
| local function notDead(co) | |
| return coroutine.status(co) ~= "dead" | |
| end | |
| local function eventLoop(seat) | |
| local mouseClicks = {} | |
| local wantEvent = resume(seat) | |
| while notDead(seat.co) do | |
| local ev = table.pack(os.pullEventRaw()) | |
| local virtEv = ev | |
| if ev[1] == "timer" and mouseClicks[ev[2]] then | |
| local click = mouseClicks[ev[2]] | |
| virtEv = table.pack("mouse_up", table.unpack(click, 1, click.n)) | |
| elseif ev[1] == "monitor_touch" and ev[2] == seat.monitorName then | |
| local click = table.pack(touchButtonId, table.unpack(ev, 3, ev.n)) | |
| mouseClicks[os.startTimer(0.1)] = click | |
| virtEv = table.pack("mouse_click", table.unpack(click, 1, click.n)) | |
| elseif ev[1] == "monitor_resize" and ev[2] == seat.monitorName then | |
| virtEv = table.pack("term_resize") | |
| elseif ev[1] == "term_resize" then | |
| if seat.monitorName then | |
| virtEv = nil | |
| else | |
| local w, h = term.getSize() | |
| seat.monitor.reposition(1, 1, w, h, term.current()) | |
| end | |
| elseif not useParentKeyboard and ev[1] and keyboardEvents[ev[1]] then | |
| virtEv = nil | |
| elseif ev[1] and ev[2] and ev[1]:find("^tm_keyboard_") and (useTmKeyboards.all or useTmKeyboards[ev[2]]) then | |
| virtEv = table.pack(ev[1]:match("^tm_keyboard_(.+)$"), table.unpack(ev, 3, ev.n)) | |
| end | |
| if virtEv then | |
| if not wantEvent or virtEv[1] == wantEvent then | |
| wantEvent = resume(seat, table.unpack(virtEv, 1, virtEv.n)) | |
| end | |
| end | |
| end | |
| end | |
| eventLoop(seat) | |
| -- vim: ts=4 et |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment