mirror of
https://github.com/20kdc/OC-KittenOS.git
synced 2024-12-25 02:18:07 +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
|
||||
# in how NOT to do compression
|
||||
code.tar
|
||||
work.tar
|
||||
work
|
||||
work/
|
||||
|
@ -2,24 +2,30 @@
|
||||
-- No warranty is provided, implied or otherwise.
|
||||
|
||||
-- '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.
|
||||
|
||||
-- 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 = {
|
||||
"Neolithic: Text Editor",
|
||||
"^A, ^S, ^Q: Load, Save, New",
|
||||
"^C, ^V, ^D: Copy, Paste, Delete Line",
|
||||
"Keymap " .. unicode.getKeymap() .. ", to correct, type",
|
||||
"\"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
|
||||
-- (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,
|
||||
-- so the user can more or less arbitrarily mash together lines
|
||||
"^J: Reset 'append' flag for Cut Lines",
|
||||
"^K: Cut Line(s)",
|
||||
"^" .. mappingFinal[7] .. ": Reset 'append' flag for Cut Lines",
|
||||
"^" .. mappingFinal[8] .. ": Cut Line(s)",
|
||||
"^<arrows>: Resize Win",
|
||||
"'^' is Control.",
|
||||
"Wide text can be pasted in,",
|
||||
" using your 'actual' clipboard.",
|
||||
"Wide text & clipboard supported.",
|
||||
"For example, this.",
|
||||
}
|
||||
|
||||
|
@ -172,12 +172,13 @@ local function updateRegion(monitorId, x, y, w, h, surfaceSpanCache)
|
||||
end
|
||||
|
||||
local function updateStatus()
|
||||
statusLine = "Λ-¶: menu, ◣-Λ-C: Session hardkill"
|
||||
statusLine = "Λ-¶: menu (launch 'pass' to logout)"
|
||||
if surfaces[1] then
|
||||
if #monitors > 1 then
|
||||
statusLine = "Λ-+: move, Λ-Z: switch, Λ-X: swMonitor"
|
||||
-- 123456789X123456789X123456789X123456789X123456789X
|
||||
statusLine = "Λ-+: move, Λ-Z: switch, Λ-X: swMonitor, Λ-C: close"
|
||||
else
|
||||
statusLine = "Λ-+: move, Λ-Z: switch"
|
||||
statusLine = "Λ-+: move, Λ-Z: switch, Λ-C: close"
|
||||
end
|
||||
end
|
||||
statusLine = unicode.safeTextFormat(statusLine)
|
||||
@ -370,12 +371,13 @@ everestProvider(function (pkg, pid, sendSig)
|
||||
end
|
||||
local m = 0
|
||||
if renderingAllowed() then m = 1 end
|
||||
if surfaces[1] then m = surfaces[1][1] end
|
||||
local surf = {m, 1, 1, w, h}
|
||||
local focusState = false
|
||||
local llid = lid
|
||||
lid = lid + 1
|
||||
local specialDragHandler
|
||||
surf[6] = function (ev, a, b, c)
|
||||
surf[6] = function (ev, a, b, c, d, e)
|
||||
-- Must forward surface events
|
||||
if ev == "focus" then
|
||||
focusState = a
|
||||
@ -401,6 +403,13 @@ everestProvider(function (pkg, pid, sendSig)
|
||||
end
|
||||
b = b - 1
|
||||
end
|
||||
if ev == "scroll" then
|
||||
b = b - 1
|
||||
end
|
||||
if ev == "drop" then
|
||||
specialDragHandler = nil
|
||||
b = b - 1
|
||||
end
|
||||
if ev == "line" then
|
||||
if a == 1 then
|
||||
local lw = surf[4]
|
||||
@ -426,7 +435,7 @@ everestProvider(function (pkg, pid, sendSig)
|
||||
handleSpan(surf, surf[4], a, " ", 0, 0)
|
||||
a = a - 1
|
||||
end
|
||||
sendSig(llid, ev, a, b, c)
|
||||
sendSig(llid, ev, a, b, c, d, e)
|
||||
end
|
||||
local osrf = surfaces[1]
|
||||
table.insert(surfaces, 1, surf)
|
||||
@ -580,19 +589,20 @@ while true do
|
||||
for k, v in ipairs(monitors) do
|
||||
if v[2] == s[2] then
|
||||
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)
|
||||
if sid then
|
||||
local os = surfaces[1]
|
||||
local ns = table.remove(surfaces, sid)
|
||||
table.insert(surfaces, 1, ns)
|
||||
changeFocus(os)
|
||||
ns[6]("touch", lx, ly)
|
||||
ns[6]("touch", lx, ly, ix, iy, s[5])
|
||||
end
|
||||
break
|
||||
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
|
||||
local focus = surfaces[1]
|
||||
if focus then
|
||||
@ -600,7 +610,9 @@ while true do
|
||||
if v[2] == s[2] then
|
||||
if k == focus[1] then
|
||||
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
|
||||
break
|
||||
end
|
||||
|
@ -3,9 +3,10 @@
|
||||
|
||||
-- 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-
|
||||
-- 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 glacierDCProvider = neo.requireAccess("r.neo.sys.randr", "creating NEO core APIs")
|
||||
|
||||
local computer = neo.requireAccess("k.computer", "shutting down")
|
||||
local fs = neo.requireAccess("c.filesystem", "settings I/O")
|
||||
@ -21,6 +22,7 @@ end
|
||||
|
||||
-- keys are pids
|
||||
local targs = {} -- settings notify targs
|
||||
local targsDC = {} -- displaycontrol settings notify targs
|
||||
local targsSD = {} -- shutdown notify targs
|
||||
local targsST = {} -- saving throws
|
||||
|
||||
@ -70,9 +72,9 @@ local function saveSettings()
|
||||
st.close()
|
||||
end
|
||||
|
||||
-- Monitor management stuff
|
||||
-- [i] = screenProxy
|
||||
local monitorPool = {}
|
||||
-- {gpu, claimedLoseCallback}
|
||||
-- [screenAddr] = {gpu, claimedLoseCallback}
|
||||
local monitorClaims = {}
|
||||
|
||||
local function announceFreeMonitor(address, except)
|
||||
@ -97,17 +99,38 @@ local function getGPU(monitor)
|
||||
return bestG
|
||||
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 maxW, maxH = gpu.maxResolution()
|
||||
local maxD = gpu.maxDepth()
|
||||
local w = tonumber(settings["scr.w." .. monitor.address]) or 80
|
||||
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)
|
||||
local w, h, d = getMonitorSettings(monitor.address)
|
||||
w, h, d = math.min(w, maxW), math.min(h, maxH), math.min(d, maxD)
|
||||
settings["scr.w." .. monitor.address] = tostring(w)
|
||||
settings["scr.h." .. monitor.address] = tostring(h)
|
||||
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.setDepth(d)
|
||||
pcall(saveSettings)
|
||||
@ -132,18 +155,17 @@ donkonitSPProvider(function (pkg, pid, sendSig)
|
||||
local val = nil
|
||||
if name == "password" then val = "" end
|
||||
settings[name] = val
|
||||
for _, v in pairs(targs) do
|
||||
v("set_setting", name, val)
|
||||
end
|
||||
sRattle(name, val)
|
||||
pcall(saveSettings)
|
||||
end,
|
||||
setSetting = function (name, val)
|
||||
if type(name) ~= "string" then error("Setting name must be string") end
|
||||
if type(val) ~= "string" then error("Setting value must be string") end
|
||||
settings[name] = val
|
||||
for _, v in pairs(targs) do
|
||||
v("set_setting", name, val)
|
||||
end
|
||||
-- NOTE: Either a monitor is under application control,
|
||||
-- or it's not under any control.
|
||||
-- Monitor settings are applied on the transition to control.
|
||||
sRattle(name, val)
|
||||
pcall(saveSettings)
|
||||
--saveSettings()
|
||||
end,
|
||||
@ -249,10 +271,11 @@ loadSettings()
|
||||
local function rescanDevs()
|
||||
monitorPool = {}
|
||||
local hasGPU = gpus.list()()
|
||||
for k, v in pairs(monitorClaims) do
|
||||
v[2](true)
|
||||
end
|
||||
monitorClaims = {}
|
||||
for m in screens.list() do
|
||||
if monitorClaims[m.address] then
|
||||
monitorClaims[m.address][2](true)
|
||||
end
|
||||
table.insert(monitorPool, m)
|
||||
if hasGPU then
|
||||
announceFreeMonitor(m.address)
|
||||
@ -265,6 +288,45 @@ rescanDevs()
|
||||
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
|
||||
local s = {coroutine.yield()}
|
||||
if s[1] == "k.timer" then
|
||||
@ -272,13 +334,19 @@ while true do
|
||||
shutdownFin(shutdownMode)
|
||||
end
|
||||
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
|
||||
if s[1] == "h.component_removed" then
|
||||
rescanDevs()
|
||||
if s[3] == "gpu" or s[3] == "screen" then
|
||||
rescanDevs()
|
||||
end
|
||||
end
|
||||
if s[1] == "k.procdie" then
|
||||
targs[s[3]] = nil
|
||||
targsDC[s[3]] = nil
|
||||
targsSD[s[3]] = nil
|
||||
if targsST[s[3]] then
|
||||
if s[4] then
|
||||
|
@ -276,11 +276,28 @@ end
|
||||
|
||||
local function initializeSystem()
|
||||
-- System has just booted, bristol is in charge
|
||||
-- Firstly, initialize hardware to something sensible since we don't know scrcfg
|
||||
gpu = neo.requestAccess("c.gpu").list()()
|
||||
if gpu then
|
||||
screen = neo.requestAccess("c.screen").list()()
|
||||
if not screen then gpu = nil end
|
||||
-- Firstly, since we don't know scrcfg, let's work out something sensible.
|
||||
-- Note that we should try to keep going with this if there's no reason to do otherwise.
|
||||
local gpuAc = neo.requestAccess("c.gpu")
|
||||
local screenAc = neo.requestAccess("c.screen")
|
||||
-- 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
|
||||
if gpu then
|
||||
screen = screen.address
|
||||
|
182
code/init.lua
182
code/init.lua
@ -2,11 +2,7 @@
|
||||
-- This is released into the public domain.
|
||||
-- No warranty is provided, implied or otherwise.
|
||||
|
||||
-- NOTE: If it's not "local", it's because k.root ought to access it.
|
||||
-- List of things that apply:
|
||||
-- primaryDisk, timers, libraries, processes, accesses, wrapMeta,
|
||||
-- distEvent, baseProcEnv, loadLibraryInner, retrieveAccess,
|
||||
-- start
|
||||
-- NOTE: local is considered unnecessary in kernel since 21 March
|
||||
|
||||
-- Debugging option, turns process errors into actual errors (!)
|
||||
local criticalFailure = false
|
||||
@ -14,9 +10,9 @@ local criticalFailure = false
|
||||
local readBufSize = 2048
|
||||
|
||||
-- A function used for logging, usable by programs.
|
||||
local emergencyFunction = function () end
|
||||
-- Comment this out if you don't want programs to have
|
||||
-- access to ocemu's logger.
|
||||
local emergencyFunction = function () end
|
||||
local ocemu = component.list("ocemu", true)()
|
||||
if ocemu then
|
||||
ocemu = component.proxy(ocemu)
|
||||
@ -77,7 +73,13 @@ function unicode.undoSafeTextFormat(s)
|
||||
for i = 1, unicode.len(s) do
|
||||
if not ignoreNext then
|
||||
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
|
||||
else
|
||||
ignoreNext = false
|
||||
@ -86,6 +88,168 @@ function unicode.undoSafeTextFormat(s)
|
||||
return res
|
||||
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 h = primaryDisk.open(s)
|
||||
if h then
|
||||
@ -308,6 +472,7 @@ function baseProcEnv()
|
||||
totalIdleTime = function () return idleTime end,
|
||||
ensurePath = ensurePath,
|
||||
ensurePathComponent = ensurePathComponent,
|
||||
ensureType = ensureType
|
||||
}
|
||||
}
|
||||
end
|
||||
@ -631,6 +796,9 @@ while true do
|
||||
if dist < 0.05 then dist = 0.05 end
|
||||
end
|
||||
local signal = {computer.pullSignal(dist)}
|
||||
if signal[1] == "key_down" then
|
||||
keymapDetect(signal[3], signal[4])
|
||||
end
|
||||
idleTime = idleTime + (computer.uptime() - now)
|
||||
if signal[1] then
|
||||
distEvent(nil, "h." .. signal[1], select(2, table.unpack(signal)))
|
||||
|
@ -216,6 +216,45 @@ return function (event, neo)
|
||||
end
|
||||
end
|
||||
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)
|
||||
window.span(1, a, (" "):rep(w), bg, fg)
|
||||
@ -237,7 +276,17 @@ return function (event, neo)
|
||||
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
|
||||
local found = nil
|
||||
for k, v in ipairs(controls) do
|
||||
@ -263,20 +312,35 @@ return function (event, neo)
|
||||
if c2 then
|
||||
doZone(window, c2, cache)
|
||||
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
|
||||
if ev == "drag" then
|
||||
-- X,Y,Xi,Yi,B (or D for scroll)
|
||||
elseif ev == "drag" or ev == "drop" or ev == "scroll" then
|
||||
if controls[selIndex] then
|
||||
if controls[selIndex].drag then
|
||||
controls[selIndex].drag(window, function () doZone(window, controls[selIndex]) end, (a - controls[selIndex].x) + 1, (b - controls[selIndex].y) + 1)
|
||||
if controls[selIndex][ev] then
|
||||
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
|
||||
if ev == "key" then
|
||||
if a == 9 then
|
||||
elseif ev == "key" then
|
||||
if b == 203 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
|
||||
local c1 = controls[selIndex]
|
||||
rotateSelIndex()
|
||||
@ -285,18 +349,14 @@ return function (event, neo)
|
||||
if c1 then doZone(window, c1, cache) end
|
||||
if c2 then doZone(window, c2, cache) end
|
||||
end
|
||||
else
|
||||
if controls[selIndex] then
|
||||
if controls[selIndex].key then
|
||||
controls[selIndex].key(window, function () doZone(window, controls[selIndex]) end, a, b, c)
|
||||
end
|
||||
elseif controls[selIndex] then
|
||||
if controls[selIndex].key then
|
||||
controls[selIndex].key(window, function () doZone(window, controls[selIndex]) end, a, b, c)
|
||||
end
|
||||
end
|
||||
end
|
||||
if ev == "line" then
|
||||
elseif ev == "line" then
|
||||
doLine(window, a)
|
||||
end
|
||||
if ev == "close" then
|
||||
elseif ev == "close" then
|
||||
closing(window)
|
||||
end
|
||||
end, doZone
|
||||
|
@ -2,24 +2,27 @@
|
||||
-- No warranty is provided, implied or otherwise. XX
|
||||
local sector = io.write -- XX
|
||||
-- BUNDIVIDE reference implementation for integration XX
|
||||
local Cs,Cbu,Cb,Cw,Cp,Ci,CP,CB,CD={},128,"",128,""
|
||||
CP=function(d,b,i)
|
||||
i=1
|
||||
while i<=#d do
|
||||
b=d:byte(i)
|
||||
i=i+1
|
||||
if b==127 then
|
||||
b=d:byte(i)
|
||||
i=i+1
|
||||
if b==127 then
|
||||
b=d:byte(i)+254
|
||||
i=i+1
|
||||
local Cs,Cbu,Cb,Cw,Cp,Ct,Ci,CP,CB,CD={},128,"",128,"",""
|
||||
CP=function(d,b)
|
||||
Ct=Ct..d
|
||||
while#Ct>2 do
|
||||
b=Ct:byte()
|
||||
Ct=Ct:sub(2)
|
||||
if b==127then
|
||||
b=Ct:byte()
|
||||
Ct=Ct:sub(2)
|
||||
if b==127then
|
||||
b=Ct:byte()+254
|
||||
if b>255then
|
||||
b=b-256
|
||||
end
|
||||
Ct=Ct:sub(2)
|
||||
else
|
||||
b=b+127
|
||||
end
|
||||
end
|
||||
Cp=Cp..string.char(b)
|
||||
if #Cp==512 then
|
||||
if #Cp==512then
|
||||
sector(Cp)
|
||||
Cp=""
|
||||
end
|
||||
@ -63,4 +66,4 @@ CD(io.read("*a")) -- XX
|
||||
--local Ch=D.open("init-bdivide.lua","rb")--
|
||||
--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--
|
||||
CD("\x00\x00")CP(Cs[Cw])
|
||||
CD("\x00\x00")CP(Cs[Cw] .. "\x00\x00")
|
||||
|
@ -52,7 +52,7 @@ local function tA(s)
|
||||
else
|
||||
tFN = s:sub(1, 100):gsub("\x00", "")
|
||||
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)
|
||||
else
|
||||
tFN = tFN:sub(6)
|
||||
|
@ -3,7 +3,7 @@
|
||||
# This is released into the public domain.
|
||||
# No warranty is provided, implied or otherwise.
|
||||
|
||||
echo "WARNING: This will rm -rf the 'work' folder."
|
||||
# safety measure: unless we are likely in the right folder, DO NOT CONTINUE
|
||||
git status && stat imitclaw.lua code/apps/sys-init.lua && rm -rf work work.tar
|
||||
lua imitclaw.lua && tar -cf work.tar work
|
||||
rm code.tar
|
||||
# Hey, look behind you, there's nothing to see here.
|
||||
# ... ok, are they seriously all named "Mann"?
|
||||
tar --owner=gray:0 --group=mann:0 -cf code.tar code
|
||||
|
Loading…
Reference in New Issue
Block a user