virtual terminal support with vtansi and getty, for machines with VRAM available
This commit is contained in:
parent
2df878f3e8
commit
eb95f9715e
@ -1,4 +1,6 @@
|
||||
local vtansi = {}
|
||||
local keyboardIgnore = {}
|
||||
vtansi.activeBuffers = {}
|
||||
vtansi.sequences = {
|
||||
[28] = "\n", -- newline
|
||||
[200] = "\27[A", -- up
|
||||
@ -8,9 +10,26 @@ vtansi.sequences = {
|
||||
[201] = "\27[5~", -- page up
|
||||
[209] = "\27[6~" -- page down
|
||||
}
|
||||
function vtansi.vtemu(gpu) -- table -- function -- takes GPU component proxy *gpu* and returns a function to write to it in a manner like an ANSI terminal
|
||||
vtansi.keys = {}
|
||||
vtansi.keys[0x38] = "lalt"
|
||||
vtansi.keys[0xB8] = "ralt"
|
||||
function vtansi.saveToBuffer(gpu,idx)
|
||||
gpu.bitblt(idx, nil, nil, nil, nil, 0)
|
||||
end
|
||||
function vtansi.loadFromBuffer(gpu,idx)
|
||||
gpu.bitblt(0, nil, nil, nil, nil, idx)
|
||||
end
|
||||
function vtansi.switchToBuffer(gpu,idx)
|
||||
-- copy screen to the active buffer
|
||||
vtansi.saveToBuffer(gpu,vtansi.activeBuffers[gpu.address])
|
||||
-- copy the new buffer to the screen
|
||||
vtansi.loadFromBuffer(gpu,idx)
|
||||
vtansi.activeBuffers[gpu.address] = idx
|
||||
end
|
||||
function vtansi.vtemu(gpu,bn) -- table number -- function -- takes GPU component proxy *gpu* and returns a function to write to it in a manner like an ANSI terminal, either allocating a new buffer or using *bn*.
|
||||
local colours = {0x0,0xFF0000,0x00FF00,0xFFFF00,0x0000FF,0xFF00FF,0x00B6FF,0xFFFFFF}
|
||||
local mx, my = gpu.maxResolution()
|
||||
local buffer = nil
|
||||
local cx, cy = 1, 1
|
||||
local pc = " "
|
||||
local lc = ""
|
||||
@ -21,8 +40,19 @@ function vtansi.vtemu(gpu) -- table -- function -- takes GPU component proxy *gp
|
||||
local bg, fg = 0, 0xFFFFFF
|
||||
|
||||
-- setup
|
||||
if gpu.getActiveBuffer then
|
||||
buffer = bn or gpu.allocateBuffer(mx,my)
|
||||
vtansi.activeBuffers[gpu.address] = vtansi.activeBuffers[gpu.address] or buffer
|
||||
local oldActiveBuffer = vtansi.activeBuffers[gpu.address]
|
||||
gpu.setActiveBuffer(buffer)
|
||||
gpu.setResolution(mx,my)
|
||||
gpu.fill(1,1,mx,my," ")
|
||||
gpu.setActiveBuffer(oldActiveBuffer)
|
||||
else
|
||||
gpu.setResolution(mx,my)
|
||||
gpu.fill(1,1,mx,my," ")
|
||||
end
|
||||
|
||||
local function checkCursor()
|
||||
if cx > mx and lw then
|
||||
cx, cy = 1, cy+1
|
||||
@ -37,6 +67,13 @@ function vtansi.vtemu(gpu) -- table -- function -- takes GPU component proxy *gp
|
||||
end
|
||||
|
||||
local function termwrite(s)
|
||||
if buffer then
|
||||
if vtansi.activeBuffers[gpu.address] == buffer then
|
||||
gpu.setActiveBuffer(0)
|
||||
else
|
||||
gpu.setActiveBuffer(buffer)
|
||||
end
|
||||
end
|
||||
local wb = ""
|
||||
local lb, ec = nil, nil
|
||||
local function flushwb()
|
||||
@ -161,13 +198,14 @@ function vtansi.vtemu(gpu) -- table -- function -- takes GPU component proxy *gp
|
||||
return rs, lb, ec
|
||||
end
|
||||
|
||||
return termwrite
|
||||
return termwrite, buffer
|
||||
end
|
||||
|
||||
function vtansi.vtsession(gpua,scra) -- string string -- table -- creates a process to handle the GPU and screen address combination *gpua*/*scra*. Returns read, write and "close" functions.
|
||||
function vtansi.vtsession(gpua,scra,bn) -- string string number -- function function function -- creates a process to handle the GPU and screen address combination *gpua*/*scra*, optionally using buffer number *bn* specifically. Returns read, write and "close" functions.
|
||||
local modifiers = {}
|
||||
local gpu = component.proxy(gpua)
|
||||
gpu.bind(scra)
|
||||
local write = vtansi.vtemu(gpu)
|
||||
-- gpu.bind(scra)
|
||||
local write, bn = vtansi.vtemu(gpu,bn)
|
||||
local kba = {}
|
||||
for k,v in ipairs(component.invoke(scra,"getKeyboards")) do
|
||||
kba[v]=true
|
||||
@ -176,7 +214,32 @@ function vtansi.vtsession(gpua,scra) -- string string -- table -- creates a proc
|
||||
os.spawn(function()
|
||||
while true do
|
||||
local ty,ka,ch,kc = coroutine.yield()
|
||||
if ty == "key_down" and kba[ka] then
|
||||
if kba[ka] and keyboardIgnore[ka] == bn then
|
||||
keyboardIgnore[ka] = nil
|
||||
end
|
||||
if kba[ka] and vtansi.keys[kc] then
|
||||
modifiers[vtansi.keys[kc]] = ty == "key_down"
|
||||
end
|
||||
if ty == "key_down" and kba[ka] and (bn == nil or vtansi.activeBuffers[gpua] == bn) then
|
||||
if bn and ty == "key_down" and kba[ka] and ch == 46 and kc == 52 and (modifiers.lalt or modifiers.ralt) then
|
||||
-- next buffer
|
||||
local allBuffers = gpu.buffers()
|
||||
for k,v in ipairs(allBuffers) do
|
||||
if v == vtansi.activeBuffers[gpu.address] and allBuffers[k+1] and not keyboardIgnore[ka] then
|
||||
keyboardIgnore[ka] = bn
|
||||
vtansi.switchToBuffer(gpu,allBuffers[k+1])
|
||||
end
|
||||
end
|
||||
elseif bn and ty == "key_down" and kba[ka] and ch == 44 and kc == 51 and (modifiers.lalt or modifiers.ralt) then
|
||||
-- previous buffer
|
||||
local allBuffers = gpu.buffers()
|
||||
for k,v in ipairs(allBuffers) do
|
||||
if v == vtansi.activeBuffers[gpu.address] and allBuffers[k-1] and not keyboardIgnore[ka] then
|
||||
keyboardIgnore[ka] = bn
|
||||
vtansi.switchToBuffer(gpu,allBuffers[k-1])
|
||||
end
|
||||
end
|
||||
else
|
||||
local outs
|
||||
if ch > 0 then
|
||||
outs = string.char(ch)
|
||||
@ -188,7 +251,8 @@ function vtansi.vtsession(gpua,scra) -- string string -- table -- creates a proc
|
||||
end
|
||||
end
|
||||
end
|
||||
end,string.format("ttyd[%s:%s]",gpua:sub(1,8),scra:sub(1,8)))
|
||||
end
|
||||
end,string.format("ttyd[%s:%s/%i]",gpua:sub(1,8),scra:sub(1,8),tonumber(bn) or 0))
|
||||
local function bread(n)
|
||||
coroutine.yield()
|
||||
local r = buf
|
||||
|
@ -37,21 +37,33 @@ local function spawnShell(fin,fout)
|
||||
io.input(fin)
|
||||
io.output(fout):setvbuf("no")
|
||||
print(_OSVERSION.." - "..tostring(math.floor(computer.totalMemory()/1024)).."K RAM")
|
||||
return os.spawn(function() local w,r = pcall(shell.interactive) if not w then syslog(r) end end, "shell: "..tostring(fin))
|
||||
print((os.getenv("HOSTNAME") or "unknown") .. " on " .. fin)
|
||||
-- return os.spawn(function() local w,r = pcall(shell.interactive) if not w then syslog(r) end end, "shell: "..tostring(fin))
|
||||
return os.spawn(shell.interactive, "shell: "..tostring(fin))
|
||||
end
|
||||
|
||||
local function allocate()
|
||||
for k,v in pairs(gpus) do
|
||||
dprint(k)
|
||||
dprint("Setting up display "..k)
|
||||
local sA = nextScreen(v[2])
|
||||
if v[1] == false and sA then
|
||||
local terminals = 1
|
||||
local gpu = component.proxy(k)
|
||||
gpu.bind(sA)
|
||||
if gpu.buffers then
|
||||
gpu.freeAllBuffers()
|
||||
local mw, mh = gpu.maxResolution()
|
||||
terminals = math.floor(gpu.freeMemory() / (mw * mh))
|
||||
end
|
||||
for i = 1, terminals do
|
||||
local r,w = vtansi.vtsession(k,sA)
|
||||
devfs.register("tty"..tostring(ttyn), function() return r,w,function() end end)
|
||||
gpus[k][1] = true
|
||||
screens[sA][1] = true
|
||||
pids["tty"..tostring(ttyn)] = {-1}
|
||||
ttyn = ttyn + 1
|
||||
end
|
||||
gpus[k][1] = true
|
||||
screens[sA][1] = true
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@ -59,14 +71,15 @@ function start()
|
||||
basepid = os.spawn(function()
|
||||
scan()
|
||||
allocate()
|
||||
dprint("screens ready")
|
||||
dprint("Display setup complete.")
|
||||
while true do
|
||||
coroutine.yield()
|
||||
for k,v in pairs(pids) do
|
||||
if not os.taskInfo(v[1]) then
|
||||
dprint("Spawning new shell for "..k)
|
||||
pids[k][1] = spawnShell(v[2] or "/dev/"..k, v[3] or "/dev/"..k)
|
||||
pids[k][2], pids[k][3] = pids[k][2] or io.input(), pids[k][3] or io.output()
|
||||
pids[k][2], pids[k][3] = pids[k][2] or "/dev/"..k, pids[k][3] or "/dev/"..k
|
||||
coroutine.yield()
|
||||
end
|
||||
end
|
||||
end
|
||||
|
Loading…
Reference in New Issue
Block a user