mirror of
https://github.com/20kdc/OC-KittenOS.git
synced 2024-11-27 04:48:05 +11:00
some boring stuff, like better multimonitor & keyboard support
This commit is contained in:
parent
53db9fd2cb
commit
87932ab26c
1
.gitignore
vendored
1
.gitignore
vendored
@ -3,6 +3,7 @@
|
|||||||
|
|
||||||
# leaving in preSH.tar.gz for anyone who's interested
|
# leaving in preSH.tar.gz for anyone who's interested
|
||||||
# in how NOT to do compression
|
# in how NOT to do compression
|
||||||
|
code.tar
|
||||||
work.tar
|
work.tar
|
||||||
work
|
work
|
||||||
work/
|
work/
|
||||||
|
@ -2,24 +2,30 @@
|
|||||||
-- No warranty is provided, implied or otherwise.
|
-- No warranty is provided, implied or otherwise.
|
||||||
|
|
||||||
-- 'neolithic': Text Editor
|
-- 'neolithic': Text Editor
|
||||||
-- This was textedit (femto) from KittenOS brought kicking and screaming into the NEO world
|
-- This was textedit (femto) from KittenOS 'ported' to NEO.
|
||||||
-- It also has fixes for bugs involving wide text, and runs faster due to the chars -> lines change.
|
-- It also has fixes for bugs involving wide text, and runs faster due to the chars -> lines change.
|
||||||
|
|
||||||
-- needs translation??? figure out how to do translation in the new system NICELY
|
local mapping, _ = unicode.keymap("ASQCVDJK")
|
||||||
|
local mappingFinal = {}
|
||||||
|
for i = 1, #mapping do
|
||||||
|
mappingFinal[i] = unicode.sub(mapping, i, i)
|
||||||
|
end
|
||||||
local lines = {
|
local lines = {
|
||||||
"Neolithic: Text Editor",
|
"Neolithic: Text Editor",
|
||||||
"^A, ^S, ^Q: Load, Save, New",
|
"Keymap " .. unicode.getKeymap() .. ", to correct, type",
|
||||||
"^C, ^V, ^D: Copy, Paste, Delete Line",
|
"\"A Cruel Jump's Kinesis: DVSQuest\"",
|
||||||
|
"Then, restart the text editor.",
|
||||||
|
"^" .. mappingFinal[1] .. ", ^" .. mappingFinal[2] .. ", ^" .. mappingFinal[3] .. ": Load, Save, New",
|
||||||
|
"^" .. mappingFinal[4] .. ", ^" .. mappingFinal[5] .. ", ^" .. mappingFinal[6] .. ": Copy, Paste, Delete Line",
|
||||||
-- These two are meant to replace similar functionality in GNU Nano
|
-- These two are meant to replace similar functionality in GNU Nano
|
||||||
-- (which I consider the best console text editor out there - Neolithic is an *imitation* and a poor one at that),
|
-- (which I consider the best console text editor out there - Neolithic is an *imitation* and a poor one at that),
|
||||||
-- except fixing a UI flaw by instead making J responsible for resetting the append flag,
|
-- except fixing a UI flaw by instead making J responsible for resetting the append flag,
|
||||||
-- so the user can more or less arbitrarily mash together lines
|
-- so the user can more or less arbitrarily mash together lines
|
||||||
"^J: Reset 'append' flag for Cut Lines",
|
"^" .. mappingFinal[7] .. ": Reset 'append' flag for Cut Lines",
|
||||||
"^K: Cut Line(s)",
|
"^" .. mappingFinal[8] .. ": Cut Line(s)",
|
||||||
"^<arrows>: Resize Win",
|
"^<arrows>: Resize Win",
|
||||||
"'^' is Control.",
|
"'^' is Control.",
|
||||||
"Wide text can be pasted in,",
|
"Wide text & clipboard supported.",
|
||||||
" using your 'actual' clipboard.",
|
|
||||||
"For example, this.",
|
"For example, this.",
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -172,12 +172,13 @@ local function updateRegion(monitorId, x, y, w, h, surfaceSpanCache)
|
|||||||
end
|
end
|
||||||
|
|
||||||
local function updateStatus()
|
local function updateStatus()
|
||||||
statusLine = "Λ-¶: menu, ◣-Λ-C: Session hardkill"
|
statusLine = "Λ-¶: menu (launch 'pass' to logout)"
|
||||||
if surfaces[1] then
|
if surfaces[1] then
|
||||||
if #monitors > 1 then
|
if #monitors > 1 then
|
||||||
statusLine = "Λ-+: move, Λ-Z: switch, Λ-X: swMonitor"
|
-- 123456789X123456789X123456789X123456789X123456789X
|
||||||
|
statusLine = "Λ-+: move, Λ-Z: switch, Λ-X: swMonitor, Λ-C: close"
|
||||||
else
|
else
|
||||||
statusLine = "Λ-+: move, Λ-Z: switch"
|
statusLine = "Λ-+: move, Λ-Z: switch, Λ-C: close"
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
statusLine = unicode.safeTextFormat(statusLine)
|
statusLine = unicode.safeTextFormat(statusLine)
|
||||||
@ -370,12 +371,13 @@ everestProvider(function (pkg, pid, sendSig)
|
|||||||
end
|
end
|
||||||
local m = 0
|
local m = 0
|
||||||
if renderingAllowed() then m = 1 end
|
if renderingAllowed() then m = 1 end
|
||||||
|
if surfaces[1] then m = surfaces[1][1] end
|
||||||
local surf = {m, 1, 1, w, h}
|
local surf = {m, 1, 1, w, h}
|
||||||
local focusState = false
|
local focusState = false
|
||||||
local llid = lid
|
local llid = lid
|
||||||
lid = lid + 1
|
lid = lid + 1
|
||||||
local specialDragHandler
|
local specialDragHandler
|
||||||
surf[6] = function (ev, a, b, c)
|
surf[6] = function (ev, a, b, c, d, e)
|
||||||
-- Must forward surface events
|
-- Must forward surface events
|
||||||
if ev == "focus" then
|
if ev == "focus" then
|
||||||
focusState = a
|
focusState = a
|
||||||
@ -401,6 +403,13 @@ everestProvider(function (pkg, pid, sendSig)
|
|||||||
end
|
end
|
||||||
b = b - 1
|
b = b - 1
|
||||||
end
|
end
|
||||||
|
if ev == "scroll" then
|
||||||
|
b = b - 1
|
||||||
|
end
|
||||||
|
if ev == "drop" then
|
||||||
|
specialDragHandler = nil
|
||||||
|
b = b - 1
|
||||||
|
end
|
||||||
if ev == "line" then
|
if ev == "line" then
|
||||||
if a == 1 then
|
if a == 1 then
|
||||||
local lw = surf[4]
|
local lw = surf[4]
|
||||||
@ -426,7 +435,7 @@ everestProvider(function (pkg, pid, sendSig)
|
|||||||
handleSpan(surf, surf[4], a, " ", 0, 0)
|
handleSpan(surf, surf[4], a, " ", 0, 0)
|
||||||
a = a - 1
|
a = a - 1
|
||||||
end
|
end
|
||||||
sendSig(llid, ev, a, b, c)
|
sendSig(llid, ev, a, b, c, d, e)
|
||||||
end
|
end
|
||||||
local osrf = surfaces[1]
|
local osrf = surfaces[1]
|
||||||
table.insert(surfaces, 1, surf)
|
table.insert(surfaces, 1, surf)
|
||||||
@ -580,19 +589,20 @@ while true do
|
|||||||
for k, v in ipairs(monitors) do
|
for k, v in ipairs(monitors) do
|
||||||
if v[2] == s[2] then
|
if v[2] == s[2] then
|
||||||
local x, y = math.floor(s[3]), math.floor(s[4])
|
local x, y = math.floor(s[3]), math.floor(s[4])
|
||||||
|
local ix, iy = s[3] - x, s[4] - y
|
||||||
local sid, lx, ly = surfaceAt(k, x, y)
|
local sid, lx, ly = surfaceAt(k, x, y)
|
||||||
if sid then
|
if sid then
|
||||||
local os = surfaces[1]
|
local os = surfaces[1]
|
||||||
local ns = table.remove(surfaces, sid)
|
local ns = table.remove(surfaces, sid)
|
||||||
table.insert(surfaces, 1, ns)
|
table.insert(surfaces, 1, ns)
|
||||||
changeFocus(os)
|
changeFocus(os)
|
||||||
ns[6]("touch", lx, ly)
|
ns[6]("touch", lx, ly, ix, iy, s[5])
|
||||||
end
|
end
|
||||||
break
|
break
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
if s[1] == "h.drag" then
|
if s[1] == "h.drag" or s[1] == "h.drop" or s[1] == "h.scroll" then
|
||||||
-- Pass to focus surface, even if out of bounds
|
-- Pass to focus surface, even if out of bounds
|
||||||
local focus = surfaces[1]
|
local focus = surfaces[1]
|
||||||
if focus then
|
if focus then
|
||||||
@ -600,7 +610,9 @@ while true do
|
|||||||
if v[2] == s[2] then
|
if v[2] == s[2] then
|
||||||
if k == focus[1] then
|
if k == focus[1] then
|
||||||
local x, y = (math.floor(s[3]) - focus[2]) + 1, (math.floor(s[4]) - focus[3]) + 1
|
local x, y = (math.floor(s[3]) - focus[2]) + 1, (math.floor(s[4]) - focus[3]) + 1
|
||||||
focus[6]("drag", x, y)
|
local ix, iy = s[3] - math.floor(s[3]), s[4] - math.floor(s[4])
|
||||||
|
-- Ok, so let's see...
|
||||||
|
focus[6](s[1]:sub(3), x, y, ix, iy, s[5])
|
||||||
end
|
end
|
||||||
break
|
break
|
||||||
end
|
end
|
||||||
|
@ -3,9 +3,10 @@
|
|||||||
|
|
||||||
-- s-donkonit : config, shutdown, screens
|
-- s-donkonit : config, shutdown, screens
|
||||||
|
|
||||||
-- Doesn't matter what calls this service, because there's a mutex here.
|
|
||||||
local donkonitSPProvider = neo.requireAccess("r.neo.sys.manage", "creating NEO core APIs") -- Restrict to s-
|
local donkonitSPProvider = neo.requireAccess("r.neo.sys.manage", "creating NEO core APIs") -- Restrict to s-
|
||||||
|
-- Doesn't matter what calls this service, because there's a mutex here.
|
||||||
local donkonitRDProvider = neo.requireAccess("r.neo.sys.screens", "creating NEO core APIs")
|
local donkonitRDProvider = neo.requireAccess("r.neo.sys.screens", "creating NEO core APIs")
|
||||||
|
local glacierDCProvider = neo.requireAccess("r.neo.sys.randr", "creating NEO core APIs")
|
||||||
|
|
||||||
local computer = neo.requireAccess("k.computer", "shutting down")
|
local computer = neo.requireAccess("k.computer", "shutting down")
|
||||||
local fs = neo.requireAccess("c.filesystem", "settings I/O")
|
local fs = neo.requireAccess("c.filesystem", "settings I/O")
|
||||||
@ -21,6 +22,7 @@ end
|
|||||||
|
|
||||||
-- keys are pids
|
-- keys are pids
|
||||||
local targs = {} -- settings notify targs
|
local targs = {} -- settings notify targs
|
||||||
|
local targsDC = {} -- displaycontrol settings notify targs
|
||||||
local targsSD = {} -- shutdown notify targs
|
local targsSD = {} -- shutdown notify targs
|
||||||
local targsST = {} -- saving throws
|
local targsST = {} -- saving throws
|
||||||
|
|
||||||
@ -70,9 +72,9 @@ local function saveSettings()
|
|||||||
st.close()
|
st.close()
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Monitor management stuff
|
-- [i] = screenProxy
|
||||||
local monitorPool = {}
|
local monitorPool = {}
|
||||||
-- {gpu, claimedLoseCallback}
|
-- [screenAddr] = {gpu, claimedLoseCallback}
|
||||||
local monitorClaims = {}
|
local monitorClaims = {}
|
||||||
|
|
||||||
local function announceFreeMonitor(address, except)
|
local function announceFreeMonitor(address, except)
|
||||||
@ -97,17 +99,38 @@ local function getGPU(monitor)
|
|||||||
return bestG
|
return bestG
|
||||||
end
|
end
|
||||||
|
|
||||||
|
local function sRattle(name, val)
|
||||||
|
for _, v in pairs(targs) do
|
||||||
|
v("set_setting", name, val)
|
||||||
|
end
|
||||||
|
if name:sub(1, 4) == "scr." then
|
||||||
|
for k, v in pairs(targsDC) do
|
||||||
|
if not targs[k] then
|
||||||
|
v("set_setting", name, val)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Settings integration w/ monitors
|
||||||
|
local function getMonitorSettings(a)
|
||||||
|
local w = tonumber(settings["scr.w." .. a]) or 80
|
||||||
|
local h = tonumber(settings["scr.h." .. a]) or 25
|
||||||
|
local d = tonumber(settings["scr.d." .. a]) or 8
|
||||||
|
w, h, d = math.floor(w), math.floor(h), math.floor(d)
|
||||||
|
return w, h, d
|
||||||
|
end
|
||||||
local function setupMonitor(gpu, monitor)
|
local function setupMonitor(gpu, monitor)
|
||||||
local maxW, maxH = gpu.maxResolution()
|
local maxW, maxH = gpu.maxResolution()
|
||||||
local maxD = gpu.maxDepth()
|
local maxD = gpu.maxDepth()
|
||||||
local w = tonumber(settings["scr.w." .. monitor.address]) or 80
|
local w, h, d = getMonitorSettings(monitor.address)
|
||||||
local h = tonumber(settings["scr.h." .. monitor.address]) or 25
|
|
||||||
local d = tonumber(settings["scr.d." .. monitor.address]) or 8
|
|
||||||
w, h, d = math.floor(w), math.floor(h), math.floor(d)
|
|
||||||
w, h, d = math.min(w, maxW), math.min(h, maxH), math.min(d, maxD)
|
w, h, d = math.min(w, maxW), math.min(h, maxH), math.min(d, maxD)
|
||||||
settings["scr.w." .. monitor.address] = tostring(w)
|
settings["scr.w." .. monitor.address] = tostring(w)
|
||||||
settings["scr.h." .. monitor.address] = tostring(h)
|
settings["scr.h." .. monitor.address] = tostring(h)
|
||||||
settings["scr.d." .. monitor.address] = tostring(d)
|
settings["scr.d." .. monitor.address] = tostring(d)
|
||||||
|
sRattle("scr.w." .. monitor.address, tostring(w))
|
||||||
|
sRattle("scr.h." .. monitor.address, tostring(h))
|
||||||
|
sRattle("scr.d." .. monitor.address, tostring(d))
|
||||||
gpu.setResolution(w, h)
|
gpu.setResolution(w, h)
|
||||||
gpu.setDepth(d)
|
gpu.setDepth(d)
|
||||||
pcall(saveSettings)
|
pcall(saveSettings)
|
||||||
@ -132,18 +155,17 @@ donkonitSPProvider(function (pkg, pid, sendSig)
|
|||||||
local val = nil
|
local val = nil
|
||||||
if name == "password" then val = "" end
|
if name == "password" then val = "" end
|
||||||
settings[name] = val
|
settings[name] = val
|
||||||
for _, v in pairs(targs) do
|
sRattle(name, val)
|
||||||
v("set_setting", name, val)
|
|
||||||
end
|
|
||||||
pcall(saveSettings)
|
pcall(saveSettings)
|
||||||
end,
|
end,
|
||||||
setSetting = function (name, val)
|
setSetting = function (name, val)
|
||||||
if type(name) ~= "string" then error("Setting name must be string") end
|
if type(name) ~= "string" then error("Setting name must be string") end
|
||||||
if type(val) ~= "string" then error("Setting value must be string") end
|
if type(val) ~= "string" then error("Setting value must be string") end
|
||||||
settings[name] = val
|
settings[name] = val
|
||||||
for _, v in pairs(targs) do
|
-- NOTE: Either a monitor is under application control,
|
||||||
v("set_setting", name, val)
|
-- or it's not under any control.
|
||||||
end
|
-- Monitor settings are applied on the transition to control.
|
||||||
|
sRattle(name, val)
|
||||||
pcall(saveSettings)
|
pcall(saveSettings)
|
||||||
--saveSettings()
|
--saveSettings()
|
||||||
end,
|
end,
|
||||||
@ -249,10 +271,11 @@ loadSettings()
|
|||||||
local function rescanDevs()
|
local function rescanDevs()
|
||||||
monitorPool = {}
|
monitorPool = {}
|
||||||
local hasGPU = gpus.list()()
|
local hasGPU = gpus.list()()
|
||||||
|
for k, v in pairs(monitorClaims) do
|
||||||
|
v[2](true)
|
||||||
|
end
|
||||||
|
monitorClaims = {}
|
||||||
for m in screens.list() do
|
for m in screens.list() do
|
||||||
if monitorClaims[m.address] then
|
|
||||||
monitorClaims[m.address][2](true)
|
|
||||||
end
|
|
||||||
table.insert(monitorPool, m)
|
table.insert(monitorPool, m)
|
||||||
if hasGPU then
|
if hasGPU then
|
||||||
announceFreeMonitor(m.address)
|
announceFreeMonitor(m.address)
|
||||||
@ -265,6 +288,45 @@ rescanDevs()
|
|||||||
saveSettings()
|
saveSettings()
|
||||||
-- --
|
-- --
|
||||||
|
|
||||||
|
glacierDCProvider(function (pkg, pid, sendSig)
|
||||||
|
targsDC[pid] = sendSig
|
||||||
|
return {
|
||||||
|
getKnownMonitors = function ()
|
||||||
|
local tbl = {}
|
||||||
|
-- yes, this should work fine so long as GMS is the *last* one #luaquirks
|
||||||
|
for k, v in ipairs(monitorPool) do
|
||||||
|
tbl[k] = {v.address, false, getMonitorSettings(v.address)}
|
||||||
|
end
|
||||||
|
for k, v in pairs(monitorClaims) do
|
||||||
|
table.insert(tbl, {k, true, getMonitorSettings(v.address)})
|
||||||
|
end
|
||||||
|
end,
|
||||||
|
changeMonitorSetup = function (ma, w, h, d)
|
||||||
|
neo.ensureType(ma, "string")
|
||||||
|
neo.ensureType(w, "number")
|
||||||
|
neo.ensureType(h, "number")
|
||||||
|
neo.ensureType(d, "number")
|
||||||
|
w = math.floor(w)
|
||||||
|
h = math.floor(h)
|
||||||
|
d = math.floor(d)
|
||||||
|
if w < 1 then error("Invalid width") end
|
||||||
|
if h < 1 then error("Invalid height") end
|
||||||
|
if d < 1 then error("Invalid depth") end
|
||||||
|
w, h, d = tostring(w), tostring(h), tostring(d)
|
||||||
|
settings["scr.w." .. ma] = w
|
||||||
|
settings["scr.h." .. ma] = h
|
||||||
|
settings["scr.d." .. ma] = d
|
||||||
|
sRattle("scr.w." .. ma, w)
|
||||||
|
sRattle("scr.h." .. ma, h)
|
||||||
|
sRattle("scr.d." .. ma, d)
|
||||||
|
pcall(saveSettings)
|
||||||
|
end,
|
||||||
|
forceRescan = rescanDevs
|
||||||
|
}
|
||||||
|
end)
|
||||||
|
|
||||||
|
-- main loop
|
||||||
|
|
||||||
while true do
|
while true do
|
||||||
local s = {coroutine.yield()}
|
local s = {coroutine.yield()}
|
||||||
if s[1] == "k.timer" then
|
if s[1] == "k.timer" then
|
||||||
@ -272,13 +334,19 @@ while true do
|
|||||||
shutdownFin(shutdownMode)
|
shutdownFin(shutdownMode)
|
||||||
end
|
end
|
||||||
if s[1] == "h.component_added" then
|
if s[1] == "h.component_added" then
|
||||||
rescanDevs()
|
-- Before doing anything, is it worth it?
|
||||||
|
if s[3] == "gpu" or s[3] == "screen" then
|
||||||
|
rescanDevs()
|
||||||
|
end
|
||||||
end
|
end
|
||||||
if s[1] == "h.component_removed" then
|
if s[1] == "h.component_removed" then
|
||||||
rescanDevs()
|
if s[3] == "gpu" or s[3] == "screen" then
|
||||||
|
rescanDevs()
|
||||||
|
end
|
||||||
end
|
end
|
||||||
if s[1] == "k.procdie" then
|
if s[1] == "k.procdie" then
|
||||||
targs[s[3]] = nil
|
targs[s[3]] = nil
|
||||||
|
targsDC[s[3]] = nil
|
||||||
targsSD[s[3]] = nil
|
targsSD[s[3]] = nil
|
||||||
if targsST[s[3]] then
|
if targsST[s[3]] then
|
||||||
if s[4] then
|
if s[4] then
|
||||||
|
@ -276,11 +276,28 @@ end
|
|||||||
|
|
||||||
local function initializeSystem()
|
local function initializeSystem()
|
||||||
-- System has just booted, bristol is in charge
|
-- System has just booted, bristol is in charge
|
||||||
-- Firstly, initialize hardware to something sensible since we don't know scrcfg
|
-- Firstly, since we don't know scrcfg, let's work out something sensible.
|
||||||
gpu = neo.requestAccess("c.gpu").list()()
|
-- Note that we should try to keep going with this if there's no reason to do otherwise.
|
||||||
if gpu then
|
local gpuAc = neo.requestAccess("c.gpu")
|
||||||
screen = neo.requestAccess("c.screen").list()()
|
local screenAc = neo.requestAccess("c.screen")
|
||||||
if not screen then gpu = nil end
|
-- time to setup gpu/screen variables!
|
||||||
|
if gpuAc and screenAc then
|
||||||
|
local scrBestWHD = 0
|
||||||
|
for s in screenAc.list() do
|
||||||
|
for g in gpuAc.list() do
|
||||||
|
g.bind(s.address)
|
||||||
|
local w, h = g.maxResolution()
|
||||||
|
local whd = w * h * g.maxDepth()
|
||||||
|
if whd > scrBestWHD then
|
||||||
|
screen = s
|
||||||
|
gpu = g
|
||||||
|
scrBestWHD = whd
|
||||||
|
end
|
||||||
|
end
|
||||||
|
if screen then
|
||||||
|
break
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
if gpu then
|
if gpu then
|
||||||
screen = screen.address
|
screen = screen.address
|
||||||
|
182
code/init.lua
182
code/init.lua
@ -2,11 +2,7 @@
|
|||||||
-- This is released into the public domain.
|
-- This is released into the public domain.
|
||||||
-- No warranty is provided, implied or otherwise.
|
-- No warranty is provided, implied or otherwise.
|
||||||
|
|
||||||
-- NOTE: If it's not "local", it's because k.root ought to access it.
|
-- NOTE: local is considered unnecessary in kernel since 21 March
|
||||||
-- List of things that apply:
|
|
||||||
-- primaryDisk, timers, libraries, processes, accesses, wrapMeta,
|
|
||||||
-- distEvent, baseProcEnv, loadLibraryInner, retrieveAccess,
|
|
||||||
-- start
|
|
||||||
|
|
||||||
-- Debugging option, turns process errors into actual errors (!)
|
-- Debugging option, turns process errors into actual errors (!)
|
||||||
local criticalFailure = false
|
local criticalFailure = false
|
||||||
@ -14,9 +10,9 @@ local criticalFailure = false
|
|||||||
local readBufSize = 2048
|
local readBufSize = 2048
|
||||||
|
|
||||||
-- A function used for logging, usable by programs.
|
-- A function used for logging, usable by programs.
|
||||||
|
local emergencyFunction = function () end
|
||||||
-- Comment this out if you don't want programs to have
|
-- Comment this out if you don't want programs to have
|
||||||
-- access to ocemu's logger.
|
-- access to ocemu's logger.
|
||||||
local emergencyFunction = function () end
|
|
||||||
local ocemu = component.list("ocemu", true)()
|
local ocemu = component.list("ocemu", true)()
|
||||||
if ocemu then
|
if ocemu then
|
||||||
ocemu = component.proxy(ocemu)
|
ocemu = component.proxy(ocemu)
|
||||||
@ -77,7 +73,13 @@ function unicode.undoSafeTextFormat(s)
|
|||||||
for i = 1, unicode.len(s) do
|
for i = 1, unicode.len(s) do
|
||||||
if not ignoreNext then
|
if not ignoreNext then
|
||||||
local ch = unicode.sub(s, i, i)
|
local ch = unicode.sub(s, i, i)
|
||||||
ignoreNext = unicode.charWidth(ch) ~= 1
|
if unicode.charWidth(ch) ~= 1 then
|
||||||
|
if unicode.sub(s, i + 1, i + 1) ~= " " then
|
||||||
|
ch = " "
|
||||||
|
else
|
||||||
|
ignoreNext = true
|
||||||
|
end
|
||||||
|
end
|
||||||
res = res .. ch
|
res = res .. ch
|
||||||
else
|
else
|
||||||
ignoreNext = false
|
ignoreNext = false
|
||||||
@ -86,6 +88,168 @@ function unicode.undoSafeTextFormat(s)
|
|||||||
return res
|
return res
|
||||||
end
|
end
|
||||||
|
|
||||||
|
-- Yes, this is what I used the freed up SR space for.
|
||||||
|
-- Think of this as my apology for refusing translation support on NEO.
|
||||||
|
keymaps = {
|
||||||
|
-- 'synth' keymap
|
||||||
|
["unknown"] = {
|
||||||
|
},
|
||||||
|
["??-qwerty"] = {
|
||||||
|
{16, "QWERTYUIOP"},
|
||||||
|
{16, "qwertyuiop"},
|
||||||
|
{30, "ASDFGHJKL"},
|
||||||
|
{30, "asdfghjkl"},
|
||||||
|
{44, "ZXCVBNM"},
|
||||||
|
{44, "zxcvbnm"},
|
||||||
|
},
|
||||||
|
["??-qwertz"] = {
|
||||||
|
{16, "QWERTZUIOP"},
|
||||||
|
{16, "qwertzuiop"},
|
||||||
|
{30, "ASDFGHJKL"},
|
||||||
|
{30, "asdfghjkl"},
|
||||||
|
{44, "YXCVBNM"},
|
||||||
|
{44, "yxcvbnm"},
|
||||||
|
},
|
||||||
|
["??-dvorak"] = {
|
||||||
|
{19, "PYFGCRL"},
|
||||||
|
{19, "pyfgcrl"},
|
||||||
|
{30, "AOEUIDHTN"},
|
||||||
|
{30, "aoeuidhtn"},
|
||||||
|
{45, "QJKXBM"},
|
||||||
|
{45, "qjkxbm"},
|
||||||
|
},
|
||||||
|
["??-dvorak-full"] = {
|
||||||
|
{16, "\"<>PYFGCRL"},
|
||||||
|
{16, "',.pyfgcrl"},
|
||||||
|
{30, "AOEUIDHTN"},
|
||||||
|
{30, "aoeuidhtn"},
|
||||||
|
{44, ":QJKXBM"},
|
||||||
|
{44, ";qjkxbm"},
|
||||||
|
},
|
||||||
|
["cz-qwertz"] = {
|
||||||
|
{2, "+ěščřžýáíé="}, -- The last letter is a *compose key*. #WTF
|
||||||
|
{2, "1234567890%"},
|
||||||
|
{15, "\tQWERTZUIOP/("},
|
||||||
|
{15, "\tqwertzuiopú)"},
|
||||||
|
{30, "ASDFGHJKL\"!'"},
|
||||||
|
{30, "asdfghjklů§"},
|
||||||
|
{44, "YXCVBNM?:_"},
|
||||||
|
{44, "yxcvbnm,.-"},
|
||||||
|
},
|
||||||
|
["de-qwertz"] = {
|
||||||
|
{2, "1234567890ß"}, -- another one?
|
||||||
|
{2, "!\"§$%&/()=?"},
|
||||||
|
{15, "\tQWERTZUIOPÜ*"},
|
||||||
|
{15, "\tqwertzuiopü+"},
|
||||||
|
{30, "ASDFGHJKLÖÄ"},
|
||||||
|
{30, "asdfghjklÖÄ"},
|
||||||
|
{44, "YXCVBNM;:_"},
|
||||||
|
{44, "yxcvbnm,.-"},
|
||||||
|
},
|
||||||
|
["uk-qwerty"] = {
|
||||||
|
{41, "`"}, {41, "¬"},
|
||||||
|
{2, "1234567890-="},
|
||||||
|
{2, "!\"£$%^&*()_+"},
|
||||||
|
{15, "\tQWERTYUIOP{}"},
|
||||||
|
{15, "\tqwertyuiop[]"},
|
||||||
|
{30, "ASDFGHJKL:@"},
|
||||||
|
{30, "asdfghjkl;'"},
|
||||||
|
{44, "ZXCVBNM<>?"},
|
||||||
|
{44, "zxcvbnm,./"},
|
||||||
|
},
|
||||||
|
["us-qwerty"] = {
|
||||||
|
{41, "`"}, {41, "~"},
|
||||||
|
{2, "1234567890-="},
|
||||||
|
{2, "!@#$%^&*()_+"},
|
||||||
|
{15, "\tQWERTYUIOP{}\r"},
|
||||||
|
{15, "\tqwertyuiop[]\r"},
|
||||||
|
{30, "ASDFGHJKL\"|"},
|
||||||
|
{30, "asdfghjkl'\\"},
|
||||||
|
{44, "ZXCVBNM<>?"},
|
||||||
|
{44, "zxcvbnm,./"},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
local unknownKeymapContains = {}
|
||||||
|
currentKeymap = "unknown"
|
||||||
|
-- Not really part of this package, but...
|
||||||
|
unicode.getKeymap = function ()
|
||||||
|
return currentKeymap
|
||||||
|
end
|
||||||
|
-- raw info functions, they return nil if they don't know
|
||||||
|
-- Due to a fantastic oversight, unicode.byte or such doesn't exist in OCEmu,
|
||||||
|
-- so things are managed via "Ch" internally.
|
||||||
|
unicode.getKCByCh = function (ch, km)
|
||||||
|
for _, v in ipairs(keymaps[km]) do
|
||||||
|
local spanLen = unicode.len(v[2])
|
||||||
|
for i = 1, spanLen do
|
||||||
|
if unicode.sub(v[2], i, i) == ch then
|
||||||
|
return v[1] + i - 1
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
unicode.getChByKC = function (kc, km)
|
||||||
|
for _, v in ipairs(keymaps[km]) do
|
||||||
|
local spanLen = unicode.len(v[2])
|
||||||
|
if kc >= v[1] and kc < v[1] + spanLen then
|
||||||
|
return unicode.sub(v[2], kc + 1 - v[1], kc + 1 - v[1])
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
local function keymapDetect(ka, kc)
|
||||||
|
if ka == 0 then return end
|
||||||
|
if kc == 0 then return end
|
||||||
|
-- simple algorithm, does the job
|
||||||
|
-- emergencyFunction("KD: " .. unicode.char(signal[3]) .. " " .. signal[4])
|
||||||
|
ka = unicode.char(ka)
|
||||||
|
if unknownKeymapContains[ka] ~= kc then
|
||||||
|
unknownKeymapContains[ka] = kc
|
||||||
|
table.insert(keymaps["unknown"], {kc, ka})
|
||||||
|
else
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
-- 25% of used keys must be known to pass
|
||||||
|
local bestRatio = 0.25
|
||||||
|
local bestName = "unknown"
|
||||||
|
for k, _ in pairs(keymaps) do
|
||||||
|
if k ~= "unknown" then
|
||||||
|
local count = 0
|
||||||
|
local total = 0
|
||||||
|
for kCh, kc in pairs(unknownKeymapContains) do
|
||||||
|
if unicode.getKCByCh(kCh, k) == kc then
|
||||||
|
count = count + 1
|
||||||
|
end
|
||||||
|
total = total + 1
|
||||||
|
end
|
||||||
|
local r = count / math.max(1, total)
|
||||||
|
if r > bestRatio then
|
||||||
|
bestRatio = r
|
||||||
|
bestName = k
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
if currentKeymap ~= bestName then emergencyFunction("Switching to Keymap " .. bestName) end
|
||||||
|
currentKeymap = bestName
|
||||||
|
end
|
||||||
|
-- rtext, codes (codes can end up nil)
|
||||||
|
-- rtext is text's letters switched over
|
||||||
|
-- (for code that will still use the same keycodes,
|
||||||
|
-- but wants to display correct text)
|
||||||
|
-- codes is the keycodes mapped based on the letters
|
||||||
|
unicode.keymap = function (text)
|
||||||
|
local km = unicode.getKeymap()
|
||||||
|
local rtext = ""
|
||||||
|
local codes = {}
|
||||||
|
for i = 1, unicode.len(text) do
|
||||||
|
local ch = unicode.sub(text, i, i)
|
||||||
|
local okc = unicode.getKCByCh(ch, "uk-qwerty") or 0
|
||||||
|
rtext = rtext .. (unicode.getChByKC(okc, currentKeymap) or unicode.getChByKC(okc, "unknown") or ch)
|
||||||
|
codes[i] = unicode.getKCByCh(ch, currentKeymap) or unicode.getKCByCh(ch, "unknown")
|
||||||
|
end
|
||||||
|
return rtext, codes
|
||||||
|
end
|
||||||
|
|
||||||
local function loadfile(s, e)
|
local function loadfile(s, e)
|
||||||
local h = primaryDisk.open(s)
|
local h = primaryDisk.open(s)
|
||||||
if h then
|
if h then
|
||||||
@ -308,6 +472,7 @@ function baseProcEnv()
|
|||||||
totalIdleTime = function () return idleTime end,
|
totalIdleTime = function () return idleTime end,
|
||||||
ensurePath = ensurePath,
|
ensurePath = ensurePath,
|
||||||
ensurePathComponent = ensurePathComponent,
|
ensurePathComponent = ensurePathComponent,
|
||||||
|
ensureType = ensureType
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
@ -631,6 +796,9 @@ while true do
|
|||||||
if dist < 0.05 then dist = 0.05 end
|
if dist < 0.05 then dist = 0.05 end
|
||||||
end
|
end
|
||||||
local signal = {computer.pullSignal(dist)}
|
local signal = {computer.pullSignal(dist)}
|
||||||
|
if signal[1] == "key_down" then
|
||||||
|
keymapDetect(signal[3], signal[4])
|
||||||
|
end
|
||||||
idleTime = idleTime + (computer.uptime() - now)
|
idleTime = idleTime + (computer.uptime() - now)
|
||||||
if signal[1] then
|
if signal[1] then
|
||||||
distEvent(nil, "h." .. signal[1], select(2, table.unpack(signal)))
|
distEvent(nil, "h." .. signal[1], select(2, table.unpack(signal)))
|
||||||
|
@ -216,6 +216,45 @@ return function (event, neo)
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
rotateSelIndex()
|
rotateSelIndex()
|
||||||
|
local function moveIndex(vertical, negative)
|
||||||
|
if not controls[selIndex] then return end
|
||||||
|
local currentMA, currentOA = controls[selIndex].y, controls[selIndex].x
|
||||||
|
local currentMAX = controls[selIndex].y + controls[selIndex].h - 1
|
||||||
|
if vertical then
|
||||||
|
currentMA, currentOA = controls[selIndex].x, controls[selIndex].y
|
||||||
|
currentMAX = controls[selIndex].x + controls[selIndex].w - 1
|
||||||
|
end
|
||||||
|
local bestOA = 9001
|
||||||
|
local bestSI = selIndex
|
||||||
|
if negative then
|
||||||
|
bestOA = -9000
|
||||||
|
end
|
||||||
|
for k, v in ipairs(controls) do
|
||||||
|
if (k ~= selIndex) and v.selectable then
|
||||||
|
local ma, oa = v.y, v.x
|
||||||
|
local max = v.y + v.h - 1
|
||||||
|
if vertical then
|
||||||
|
ma, oa = v.x, v.y
|
||||||
|
max = v.x + v.w - 1
|
||||||
|
end
|
||||||
|
if (ma >= currentMA and ma <= currentMAX) or (max >= currentMA and max <= currentMAX)
|
||||||
|
or (currentMA >= ma and currentMA <= max) or (currentMAX >= ma and currentMAX <= max) then
|
||||||
|
if negative then
|
||||||
|
if (oa < currentOA) and (oa > bestOA) then
|
||||||
|
bestOA = oa
|
||||||
|
bestSI = k
|
||||||
|
end
|
||||||
|
else
|
||||||
|
if (oa > currentOA) and (oa < bestOA) then
|
||||||
|
bestOA = oa
|
||||||
|
bestSI = k
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
selIndex = bestSI
|
||||||
|
end
|
||||||
|
|
||||||
local function doLine(window, a)
|
local function doLine(window, a)
|
||||||
window.span(1, a, (" "):rep(w), bg, fg)
|
window.span(1, a, (" "):rep(w), bg, fg)
|
||||||
@ -237,7 +276,17 @@ return function (event, neo)
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
return function (window, ev, a, b, c)
|
local function moveIndexAU(window, vertical, negative)
|
||||||
|
local c1 = controls[selIndex]
|
||||||
|
moveIndex(vertical, negative)
|
||||||
|
local c2 = controls[selIndex]
|
||||||
|
local cache = {}
|
||||||
|
if c1 then doZone(window, c1, cache) end
|
||||||
|
if c2 then doZone(window, c2, cache) end
|
||||||
|
end
|
||||||
|
|
||||||
|
return function (window, ev, a, b, c, d, e)
|
||||||
|
-- X,Y,Xi,Yi,B
|
||||||
if ev == "touch" then
|
if ev == "touch" then
|
||||||
local found = nil
|
local found = nil
|
||||||
for k, v in ipairs(controls) do
|
for k, v in ipairs(controls) do
|
||||||
@ -263,20 +312,35 @@ return function (event, neo)
|
|||||||
if c2 then
|
if c2 then
|
||||||
doZone(window, c2, cache)
|
doZone(window, c2, cache)
|
||||||
if c2.touch then
|
if c2.touch then
|
||||||
c2.touch(window, function () doZone(window, c2) end, (a - c2.x) + 1, (b - c2.y) + 1)
|
c2.touch(window, function () doZone(window, c2) end, (a - c2.x) + 1, (b - c2.y) + 1, c, d, e)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
-- X,Y,Xi,Yi,B (or D for scroll)
|
||||||
if ev == "drag" then
|
elseif ev == "drag" or ev == "drop" or ev == "scroll" then
|
||||||
if controls[selIndex] then
|
if controls[selIndex] then
|
||||||
if controls[selIndex].drag then
|
if controls[selIndex][ev] then
|
||||||
controls[selIndex].drag(window, function () doZone(window, controls[selIndex]) end, (a - controls[selIndex].x) + 1, (b - controls[selIndex].y) + 1)
|
controls[selIndex][ev](window, function () doZone(window, controls[selIndex]) end, (a - controls[selIndex].x) + 1, (b - controls[selIndex].y) + 1, c, d, e)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
elseif ev == "key" then
|
||||||
if ev == "key" then
|
if b == 203 then
|
||||||
if a == 9 then
|
if c then
|
||||||
|
moveIndexAU(window, false, true)
|
||||||
|
end
|
||||||
|
elseif b == 205 then
|
||||||
|
if c then
|
||||||
|
moveIndexAU(window, false, false)
|
||||||
|
end
|
||||||
|
elseif b == 200 then
|
||||||
|
if c then
|
||||||
|
moveIndexAU(window, true, true)
|
||||||
|
end
|
||||||
|
elseif b == 208 then
|
||||||
|
if c then
|
||||||
|
moveIndexAU(window, true, false)
|
||||||
|
end
|
||||||
|
elseif a == 9 then
|
||||||
if c then
|
if c then
|
||||||
local c1 = controls[selIndex]
|
local c1 = controls[selIndex]
|
||||||
rotateSelIndex()
|
rotateSelIndex()
|
||||||
@ -285,18 +349,14 @@ return function (event, neo)
|
|||||||
if c1 then doZone(window, c1, cache) end
|
if c1 then doZone(window, c1, cache) end
|
||||||
if c2 then doZone(window, c2, cache) end
|
if c2 then doZone(window, c2, cache) end
|
||||||
end
|
end
|
||||||
else
|
elseif controls[selIndex] then
|
||||||
if controls[selIndex] then
|
if controls[selIndex].key then
|
||||||
if controls[selIndex].key then
|
controls[selIndex].key(window, function () doZone(window, controls[selIndex]) end, a, b, c)
|
||||||
controls[selIndex].key(window, function () doZone(window, controls[selIndex]) end, a, b, c)
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
elseif ev == "line" then
|
||||||
if ev == "line" then
|
|
||||||
doLine(window, a)
|
doLine(window, a)
|
||||||
end
|
elseif ev == "close" then
|
||||||
if ev == "close" then
|
|
||||||
closing(window)
|
closing(window)
|
||||||
end
|
end
|
||||||
end, doZone
|
end, doZone
|
||||||
|
@ -2,24 +2,27 @@
|
|||||||
-- No warranty is provided, implied or otherwise. XX
|
-- No warranty is provided, implied or otherwise. XX
|
||||||
local sector = io.write -- XX
|
local sector = io.write -- XX
|
||||||
-- BUNDIVIDE reference implementation for integration XX
|
-- BUNDIVIDE reference implementation for integration XX
|
||||||
local Cs,Cbu,Cb,Cw,Cp,Ci,CP,CB,CD={},128,"",128,""
|
local Cs,Cbu,Cb,Cw,Cp,Ct,Ci,CP,CB,CD={},128,"",128,"",""
|
||||||
CP=function(d,b,i)
|
CP=function(d,b)
|
||||||
i=1
|
Ct=Ct..d
|
||||||
while i<=#d do
|
while#Ct>2 do
|
||||||
b=d:byte(i)
|
b=Ct:byte()
|
||||||
i=i+1
|
Ct=Ct:sub(2)
|
||||||
if b==127 then
|
if b==127then
|
||||||
b=d:byte(i)
|
b=Ct:byte()
|
||||||
i=i+1
|
Ct=Ct:sub(2)
|
||||||
if b==127 then
|
if b==127then
|
||||||
b=d:byte(i)+254
|
b=Ct:byte()+254
|
||||||
i=i+1
|
if b>255then
|
||||||
|
b=b-256
|
||||||
|
end
|
||||||
|
Ct=Ct:sub(2)
|
||||||
else
|
else
|
||||||
b=b+127
|
b=b+127
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
Cp=Cp..string.char(b)
|
Cp=Cp..string.char(b)
|
||||||
if #Cp==512 then
|
if #Cp==512then
|
||||||
sector(Cp)
|
sector(Cp)
|
||||||
Cp=""
|
Cp=""
|
||||||
end
|
end
|
||||||
@ -63,4 +66,4 @@ CD(io.read("*a")) -- XX
|
|||||||
--local Ch=D.open("init-bdivide.lua","rb")--
|
--local Ch=D.open("init-bdivide.lua","rb")--
|
||||||
--dieCB=function()D.close(Ch)D.remove("init-bdivide.lua")end--
|
--dieCB=function()D.close(Ch)D.remove("init-bdivide.lua")end--
|
||||||
--while true do local t=D.read(Ch, 64)if not t then break end CD(t)end--
|
--while true do local t=D.read(Ch, 64)if not t then break end CD(t)end--
|
||||||
CD("\x00\x00")CP(Cs[Cw])
|
CD("\x00\x00")CP(Cs[Cw] .. "\x00\x00")
|
||||||
|
@ -52,7 +52,7 @@ local function tA(s)
|
|||||||
else
|
else
|
||||||
tFN = s:sub(1, 100):gsub("\x00", "")
|
tFN = s:sub(1, 100):gsub("\x00", "")
|
||||||
local sz = convoct(s:sub(125, 135))
|
local sz = convoct(s:sub(125, 135))
|
||||||
if tFN:sub(1, 5) ~= "work/" then
|
if tFN:sub(1, 5) ~= "code/" then
|
||||||
tW = math.ceil(sz / 512)
|
tW = math.ceil(sz / 512)
|
||||||
else
|
else
|
||||||
tFN = tFN:sub(6)
|
tFN = tFN:sub(6)
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
# This is released into the public domain.
|
# This is released into the public domain.
|
||||||
# No warranty is provided, implied or otherwise.
|
# No warranty is provided, implied or otherwise.
|
||||||
|
|
||||||
echo "WARNING: This will rm -rf the 'work' folder."
|
rm code.tar
|
||||||
# safety measure: unless we are likely in the right folder, DO NOT CONTINUE
|
# Hey, look behind you, there's nothing to see here.
|
||||||
git status && stat imitclaw.lua code/apps/sys-init.lua && rm -rf work work.tar
|
# ... ok, are they seriously all named "Mann"?
|
||||||
lua imitclaw.lua && tar -cf work.tar work
|
tar --owner=gray:0 --group=mann:0 -cf code.tar code
|
||||||
|
Loading…
Reference in New Issue
Block a user