Operating system for OpenComputers
您最多选择25个主题 主题必须以字母或数字开头,可以包含连字符 (-),并且长度不得超过35个字符

275 行
7.3KB

  1. local vtansi = {}
  2. local keyboardIgnore = {}
  3. vtansi.activeBuffers = {}
  4. vtansi.sequences = {
  5. [28] = "\n", -- newline
  6. [200] = "\27[A", -- up
  7. [203] = "\27[D", -- left
  8. [205] = "\27[C", -- right
  9. [208] = "\27[B", -- down
  10. [201] = "\27[5~", -- page up
  11. [209] = "\27[6~" -- page down
  12. }
  13. vtansi.keys = {}
  14. vtansi.keys[0x38] = "lalt"
  15. vtansi.keys[0xB8] = "ralt"
  16. function vtansi.saveToBuffer(gpu,idx)
  17. gpu.bitblt(idx, nil, nil, nil, nil, 0)
  18. end
  19. function vtansi.loadFromBuffer(gpu,idx)
  20. gpu.bitblt(0, nil, nil, nil, nil, idx)
  21. end
  22. function vtansi.switchToBuffer(gpu,idx)
  23. -- copy screen to the active buffer
  24. vtansi.saveToBuffer(gpu,vtansi.activeBuffers[gpu.address])
  25. -- copy the new buffer to the screen
  26. vtansi.loadFromBuffer(gpu,idx)
  27. vtansi.activeBuffers[gpu.address] = idx
  28. end
  29. 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*.
  30. local colours = {0x0,0xFF0000,0x00FF00,0xFFFF00,0x0000FF,0xFF00FF,0x00B6FF,0xFFFFFF}
  31. local mx, my = gpu.maxResolution()
  32. local buffer = nil
  33. local cx, cy = 1, 1
  34. local pc = " "
  35. local lc = ""
  36. local mode = 0 -- 0 normal, 1 escape, 2 command
  37. local lw = true
  38. local sx, sy = 1,1
  39. local cs = ""
  40. local bg, fg = 0, 0xFFFFFF
  41. -- setup
  42. if gpu.getActiveBuffer then
  43. buffer = bn or gpu.allocateBuffer(mx,my)
  44. vtansi.activeBuffers[gpu.address] = vtansi.activeBuffers[gpu.address] or buffer
  45. local oldActiveBuffer = vtansi.activeBuffers[gpu.address]
  46. gpu.setActiveBuffer(buffer)
  47. gpu.setResolution(mx,my)
  48. gpu.fill(1,1,mx,my," ")
  49. gpu.setActiveBuffer(oldActiveBuffer)
  50. else
  51. gpu.setResolution(mx,my)
  52. gpu.fill(1,1,mx,my," ")
  53. end
  54. local function checkCursor()
  55. if cx > mx and lw then
  56. cx, cy = 1, cy+1
  57. end
  58. if cy > my then
  59. gpu.copy(1,2,mx,my-1,0,-1)
  60. gpu.fill(1,my,mx,1," ")
  61. cy=my
  62. end
  63. if cy < 1 then cy = 1 end
  64. if cx < 1 then cx = 1 end
  65. end
  66. local function termwrite(s)
  67. if buffer then
  68. if vtansi.activeBuffers[gpu.address] == buffer then
  69. gpu.setActiveBuffer(0)
  70. else
  71. gpu.setActiveBuffer(buffer)
  72. end
  73. end
  74. local wb = ""
  75. local lb, ec = nil, nil
  76. local function flushwb()
  77. while wb:len() > 0 do
  78. checkCursor()
  79. local wl = wb:sub(1,mx-cx+1)
  80. wb = wb:sub(wl:len()+1)
  81. gpu.set(cx, cy, wl)
  82. cx = cx + wl:len()
  83. end
  84. end
  85. local rs = ""
  86. s=s:gsub("\8","\27[D")
  87. pc = gpu.get(cx,cy)
  88. gpu.setForeground(fg)
  89. gpu.setBackground(bg)
  90. gpu.set(cx,cy,pc)
  91. for cc in s:gmatch(".") do
  92. if mode == 0 then
  93. if cc == "\n" then
  94. flushwb()
  95. cx,cy = 1, cy+1
  96. checkCursor()
  97. elseif cc == "\t" then
  98. wb=wb..(" "):rep((((cx//8)+1) * 8) - cx + 1)
  99. elseif cc == "\27" then
  100. flushwb()
  101. mode = 1
  102. else
  103. wb = wb .. cc
  104. end
  105. elseif mode == 1 then
  106. if cc == "[" then
  107. mode = 2
  108. else
  109. mode = 0
  110. end
  111. elseif mode == 2 then
  112. if cc:match("[%d;]") then
  113. cs = cs .. cc
  114. else
  115. mode = 0
  116. local tA = {}
  117. for s in cs:gmatch("%d+") do
  118. tA[#tA+1] = tonumber(s)
  119. end
  120. if cc == "H" then
  121. cx, cy = math.min(mx,tA[1] or 1), math.min(my,tA[2] or 1)
  122. elseif cc == "A" then
  123. for i = 1, (tA[1] or 1) do
  124. cy = cy - 1
  125. checkCursor()
  126. end
  127. elseif cc == "B" then
  128. for i = 1, (tA[1] or 1) do
  129. cy = cy + 1
  130. checkCursor()
  131. end
  132. elseif cc == "C" then
  133. for i = 1, (tA[1] or 1) do
  134. cx = cx + 1
  135. checkCursor()
  136. end
  137. elseif cc == "D" then
  138. for i = 1, (tA[1] or 1) do
  139. cx = cx - 1
  140. checkCursor()
  141. end
  142. elseif cc == "s" then
  143. sx, sy = cx, cy
  144. elseif cc == "u" then
  145. cx, cy = sx, sy
  146. elseif cc == "n" and tA[1] == 6 then
  147. rs = string.format("%s\27[%d;%dR",rs,cx,cy)
  148. dprint(string.format("reporting %d;%d as current cursor position",cx,cy))
  149. elseif cc == "K" and tA[1] == 1 then
  150. gpu.fill(1,cy,cx,1," ")
  151. elseif cc == "K" and tA[1] == 2 then
  152. gpu.fill(cx,cy,mx,1," ")
  153. elseif cc == "K" then
  154. gpu.fill(1,cy,mx,1," ")
  155. elseif cc == "J" and tA[1] == 1 then
  156. gpu.fill(1,1,mx,cy," ")
  157. elseif cc == "J" and tA[1] == 2 then
  158. gpu.fill(1,1,mx,my," ")
  159. cx, cy = 1, 1
  160. elseif cc == "J" then
  161. gpu.fill(1,cy,mx,my," ")
  162. elseif cc == "m" then
  163. for _,num in ipairs(tA) do
  164. if num == 0 then
  165. fg,bg,ec,lb = 0xFFFFFF,0,false,true
  166. elseif num == 7 then
  167. local nfg,nbg = bg, fg
  168. fg, bg = nfg, nbg
  169. elseif num > 29 and num < 38 then
  170. fg = colours[num-29]
  171. elseif num > 39 and num < 48 then
  172. bg = colours[num-39]
  173. elseif num == 100 or num == 8 then -- disable local echo
  174. ec = false
  175. elseif num == 101 then -- disable line mode
  176. lb = false
  177. end
  178. end
  179. gpu.setForeground(fg)
  180. gpu.setBackground(bg)
  181. end
  182. cs = ""
  183. checkCursor()
  184. end
  185. end
  186. end
  187. flushwb()
  188. checkCursor()
  189. pc = gpu.get(cx,cy)
  190. gpu.setForeground(bg)
  191. gpu.setBackground(fg)
  192. gpu.set(cx,cy,pc)
  193. gpu.setForeground(fg)
  194. gpu.setBackground(bg)
  195. return rs, lb, ec
  196. end
  197. return termwrite, buffer
  198. end
  199. 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.
  200. local modifiers = {}
  201. local gpu = component.proxy(gpua)
  202. -- gpu.bind(scra)
  203. local write, bn = vtansi.vtemu(gpu,bn)
  204. local kba = {}
  205. for k,v in ipairs(component.invoke(scra,"getKeyboards")) do
  206. kba[v]=true
  207. end
  208. local buf, lbuf, echo = "", false, false
  209. os.spawn(function()
  210. while true do
  211. local ty,ka,ch,kc = coroutine.yield()
  212. if kba[ka] and keyboardIgnore[ka] == bn then
  213. keyboardIgnore[ka] = nil
  214. end
  215. if kba[ka] and vtansi.keys[kc] then
  216. modifiers[vtansi.keys[kc]] = ty == "key_down"
  217. end
  218. if ty == "key_down" and kba[ka] and (bn == nil or vtansi.activeBuffers[gpua] == bn) then
  219. if bn and ty == "key_down" and kba[ka] and ch == 46 and kc == 52 and (modifiers.lalt or modifiers.ralt) then
  220. -- next buffer
  221. local allBuffers = gpu.buffers()
  222. for k,v in ipairs(allBuffers) do
  223. if v == vtansi.activeBuffers[gpu.address] and allBuffers[k+1] and not keyboardIgnore[ka] then
  224. keyboardIgnore[ka] = bn
  225. vtansi.switchToBuffer(gpu,allBuffers[k+1])
  226. end
  227. end
  228. elseif bn and ty == "key_down" and kba[ka] and ch == 44 and kc == 51 and (modifiers.lalt or modifiers.ralt) then
  229. -- previous buffer
  230. local allBuffers = gpu.buffers()
  231. for k,v in ipairs(allBuffers) do
  232. if v == vtansi.activeBuffers[gpu.address] and allBuffers[k-1] and not keyboardIgnore[ka] then
  233. keyboardIgnore[ka] = bn
  234. vtansi.switchToBuffer(gpu,allBuffers[k-1])
  235. end
  236. end
  237. else
  238. local outs
  239. if ch > 0 then
  240. outs = string.char(ch)
  241. end
  242. outs = vtansi.sequences[kc] or outs
  243. if outs then
  244. if echo then write(outs) end
  245. buf=buf..outs
  246. end
  247. end
  248. end
  249. end
  250. end,string.format("ttyd[%s:%s/%i]",gpua:sub(1,8),scra:sub(1,8),tonumber(bn) or 0))
  251. local function bread(n)
  252. coroutine.yield()
  253. local r = buf
  254. buf = ""
  255. return r
  256. end
  257. local function bwrite(d)
  258. local ba, lb, ec = write(d)
  259. buf = buf .. ba
  260. if lb ~= nil then
  261. lbuf = lb
  262. end
  263. if ec ~= nil then
  264. echo = ec
  265. end
  266. end
  267. return bread, bwrite, function() io.write("\27[2J\27[H") end
  268. end
  269. return vtansi