move multishell functionality to kernel
This commit is contained in:
@@ -58,33 +58,37 @@ local function nextUID()
|
||||
return Event.uid - 1
|
||||
end
|
||||
|
||||
function Event.on(event, fn)
|
||||
function Event.on(events, fn)
|
||||
events = type(events) == 'table' and events or { events }
|
||||
|
||||
local handlers = Event.types[event]
|
||||
if not handlers then
|
||||
handlers = { }
|
||||
Event.types[event] = handlers
|
||||
end
|
||||
|
||||
local handler = {
|
||||
local handler = setmetatable({
|
||||
uid = nextUID(),
|
||||
event = event,
|
||||
event = events,
|
||||
fn = fn,
|
||||
}
|
||||
handlers[handler.uid] = handler
|
||||
setmetatable(handler, { __index = Routine })
|
||||
}, { __index = Routine })
|
||||
|
||||
for _,event in pairs(events) do
|
||||
local handlers = Event.types[event]
|
||||
if not handlers then
|
||||
handlers = { }
|
||||
Event.types[event] = handlers
|
||||
end
|
||||
|
||||
handlers[handler.uid] = handler
|
||||
end
|
||||
|
||||
return handler
|
||||
end
|
||||
|
||||
function Event.off(h)
|
||||
if h and h.event then
|
||||
Event.types[h.event][h.uid] = nil
|
||||
for _,event in pairs(h.event) do
|
||||
Event.types[event][h.uid] = nil
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local function addTimer(interval, recurring, fn)
|
||||
|
||||
local timerId = os.startTimer(interval)
|
||||
local handler
|
||||
|
||||
@@ -133,20 +137,18 @@ function Event.waitForEvent(event, timeout)
|
||||
end
|
||||
|
||||
function Event.addRoutine(fn)
|
||||
local r = {
|
||||
local r = setmetatable({
|
||||
co = coroutine.create(fn),
|
||||
uid = nextUID()
|
||||
}
|
||||
setmetatable(r, { __index = Routine })
|
||||
Event.routines[r.uid] = r
|
||||
}, { __index = Routine })
|
||||
|
||||
Event.routines[r.uid] = r
|
||||
r:resume()
|
||||
|
||||
return r
|
||||
end
|
||||
|
||||
function Event.pullEvents(...)
|
||||
|
||||
for _, fn in ipairs({ ... }) do
|
||||
Event.addRoutine(fn)
|
||||
end
|
||||
@@ -162,7 +164,6 @@ function Event.exitPullEvents()
|
||||
end
|
||||
|
||||
local function processHandlers(event)
|
||||
|
||||
local handlers = Event.types[event]
|
||||
if handlers then
|
||||
for _,h in pairs(handlers) do
|
||||
@@ -184,7 +185,6 @@ local function tokeys(t)
|
||||
end
|
||||
|
||||
local function processRoutines(...)
|
||||
|
||||
local keys = tokeys(Event.routines)
|
||||
for _,key in ipairs(keys) do
|
||||
local r = Event.routines[key]
|
||||
@@ -200,7 +200,6 @@ function Event.processEvent(e)
|
||||
end
|
||||
|
||||
function Event.pullEvent(eventType)
|
||||
|
||||
while true do
|
||||
local e = { os.pullEventRaw() }
|
||||
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
local Util = require('util')
|
||||
|
||||
local keys = _G.keys
|
||||
local os = _G.os
|
||||
local keyboard = _G.device.keyboard
|
||||
local keys = _G.keys
|
||||
local os = _G.os
|
||||
|
||||
local modifiers = Util.transpose {
|
||||
keys.leftCtrl, keys.rightCtrl,
|
||||
@@ -10,28 +11,31 @@ local modifiers = Util.transpose {
|
||||
}
|
||||
|
||||
local input = {
|
||||
pressed = { },
|
||||
state = { },
|
||||
}
|
||||
|
||||
function input:modifierPressed()
|
||||
return self.pressed[keys.leftCtrl] or
|
||||
self.pressed[keys.rightCtrl] or
|
||||
self.pressed[keys.leftAlt] or
|
||||
self.pressed[keys.rightAlt]
|
||||
return keyboard.state[keys.leftCtrl] or
|
||||
keyboard.state[keys.rightCtrl] or
|
||||
keyboard.state[keys.leftAlt] or
|
||||
keyboard.state[keys.rightAlt]
|
||||
end
|
||||
|
||||
function input:toCode(ch, code)
|
||||
local result = { }
|
||||
|
||||
if self.pressed[keys.leftCtrl] or self.pressed[keys.rightCtrl] then
|
||||
if keyboard.state[keys.leftCtrl] or keyboard.state[keys.rightCtrl] or
|
||||
code == keys.leftCtrl or code == keys.rightCtrl then
|
||||
table.insert(result, 'control')
|
||||
end
|
||||
|
||||
if self.pressed[keys.leftAlt] or self.pressed[keys.rightAlt] then
|
||||
if keyboard.state[keys.leftAlt] or keyboard.state[keys.rightAlt] or
|
||||
code == keys.leftAlt or code == keys.rightAlt then
|
||||
table.insert(result, 'alt')
|
||||
end
|
||||
|
||||
if self.pressed[keys.leftShift] or self.pressed[keys.rightShift] then
|
||||
if keyboard.state[keys.leftShift] or keyboard.state[keys.rightShift] or
|
||||
code == keys.leftShift or code == keys.rightShift then
|
||||
if code and modifiers[code] then
|
||||
table.insert(result, 'shift')
|
||||
elseif #ch == 1 then
|
||||
@@ -48,7 +52,7 @@ function input:toCode(ch, code)
|
||||
end
|
||||
|
||||
function input:reset()
|
||||
self.pressed = { }
|
||||
self.state = { }
|
||||
self.fired = nil
|
||||
|
||||
self.timer = nil
|
||||
@@ -64,7 +68,7 @@ function input:translate(event, code, p1, p2)
|
||||
return input:toCode(keys.getName(code), code)
|
||||
end
|
||||
else
|
||||
self.pressed[code] = true
|
||||
self.state[code] = true
|
||||
if self:modifierPressed() and not modifiers[code] or code == 57 then
|
||||
self.fired = true
|
||||
return input:toCode(keys.getName(code), code)
|
||||
@@ -81,18 +85,18 @@ function input:translate(event, code, p1, p2)
|
||||
|
||||
elseif event == 'key_up' then
|
||||
if not self.fired then
|
||||
if self.pressed[code] then
|
||||
if self.state[code] then
|
||||
self.fired = true
|
||||
local ch = input:toCode(keys.getName(code), code)
|
||||
self.pressed[code] = nil
|
||||
self.state[code] = nil
|
||||
return ch
|
||||
end
|
||||
end
|
||||
self.pressed[code] = nil
|
||||
self.state[code] = nil
|
||||
|
||||
elseif event == 'paste' then
|
||||
self.pressed[keys.leftCtrl] = nil
|
||||
self.pressed[keys.rightCtrl] = nil
|
||||
--self.state[keys.leftCtrl] = nil
|
||||
--self.state[keys.rightCtrl] = nil
|
||||
self.fired = true
|
||||
return input:toCode('paste', 255)
|
||||
|
||||
@@ -147,4 +151,4 @@ function input:test()
|
||||
end
|
||||
end
|
||||
|
||||
return input
|
||||
return input
|
||||
@@ -68,6 +68,7 @@ local function encodeCommon(val, pretty, tabLevel, tTracking)
|
||||
str = str .. encodeCommon(v, pretty, tabLevel, tTracking)
|
||||
end)
|
||||
else
|
||||
debug(val)
|
||||
arrEncoding(val, "{", "}", pairs, function(k,v)
|
||||
assert(type(k) == "string", "JSON object keys must be strings", 2)
|
||||
str = str .. encodeCommon(k, pretty, tabLevel, tTracking)
|
||||
@@ -94,6 +95,13 @@ function json.encodePretty(val)
|
||||
return encodeCommon(val, true, 0, {})
|
||||
end
|
||||
|
||||
function json.encodeToFile(path, val)
|
||||
local file = io.open(path, "w")
|
||||
assert(file, "Unable to open file")
|
||||
file:write(json.encodePretty(val))
|
||||
file:close()
|
||||
end
|
||||
|
||||
------------------------------------------------------------------ decoding
|
||||
|
||||
local decodeControls = {}
|
||||
|
||||
@@ -2,6 +2,8 @@ local Event = require('event')
|
||||
local Socket = require('socket')
|
||||
local Util = require('util')
|
||||
|
||||
local os = _G.os
|
||||
|
||||
local Peripheral = Util.shallowCopy(_G.peripheral)
|
||||
|
||||
function Peripheral.getList()
|
||||
@@ -176,12 +178,12 @@ local function getProxy(pi)
|
||||
if proxy.type == 'monitor' then
|
||||
Event.addRoutine(function()
|
||||
while true do
|
||||
local event = socket:read()
|
||||
if not event then
|
||||
local data = socket:read()
|
||||
if not data then
|
||||
break
|
||||
end
|
||||
if not Util.empty(event) then
|
||||
os.queueEvent(table.unpack(event))
|
||||
if data.fn and data.fn == 'event' then
|
||||
os.queueEvent(table.unpack(data.data))
|
||||
end
|
||||
end
|
||||
end)
|
||||
|
||||
210
sys/apis/ui.lua
210
sys/apis/ui.lua
@@ -43,111 +43,6 @@ end
|
||||
--[[-- Top Level Manager --]]--
|
||||
local Manager = class()
|
||||
function Manager:init()
|
||||
local running = false
|
||||
|
||||
-- single thread all input events
|
||||
local function singleThread(event, fn)
|
||||
Event.on(event, function(_, ...)
|
||||
if not running then
|
||||
running = true
|
||||
fn(...)
|
||||
running = false
|
||||
else
|
||||
Input:translate(event, ...)
|
||||
end
|
||||
end)
|
||||
end
|
||||
|
||||
Event.on('multishell_focus', function()
|
||||
Input:reset()
|
||||
end)
|
||||
|
||||
singleThread('term_resize', function(side)
|
||||
if self.currentPage then
|
||||
-- the parent doesn't have any children set...
|
||||
-- that's why we have to resize both the parent and the current page
|
||||
-- kinda makes sense
|
||||
if self.currentPage.parent.device.side == side then
|
||||
self.currentPage.parent:resize()
|
||||
|
||||
self.currentPage:resize()
|
||||
self.currentPage:draw()
|
||||
self.currentPage:sync()
|
||||
end
|
||||
end
|
||||
end)
|
||||
|
||||
singleThread('mouse_scroll', function(direction, x, y)
|
||||
if self.currentPage then
|
||||
local event = self.currentPage:pointToChild(x, y)
|
||||
local directions = {
|
||||
[ -1 ] = 'up',
|
||||
[ 1 ] = 'down'
|
||||
}
|
||||
-- revisit - should send out scroll_up and scroll_down events
|
||||
-- let the element convert them to up / down
|
||||
self:inputEvent(event.element,
|
||||
{ type = 'key', key = directions[direction] })
|
||||
self.currentPage:sync()
|
||||
end
|
||||
end)
|
||||
|
||||
-- this should be moved to the device !
|
||||
singleThread('monitor_touch', function(side, x, y)
|
||||
if self.currentPage then
|
||||
if self.currentPage.parent.device.side == side then
|
||||
self:click('mouse_click', 1, x, y)
|
||||
end
|
||||
end
|
||||
end)
|
||||
|
||||
singleThread('mouse_click', function(button, x, y)
|
||||
Input:translate('mouse_click', button, x, y)
|
||||
|
||||
if self.currentPage then
|
||||
if not self.currentPage.parent.device.side then
|
||||
local event = self.currentPage:pointToChild(x, y)
|
||||
if event.element.focus and not event.element.inactive then
|
||||
self.currentPage:setFocus(event.element)
|
||||
self.currentPage:sync()
|
||||
end
|
||||
end
|
||||
end
|
||||
end)
|
||||
|
||||
singleThread('mouse_up', function(button, x, y)
|
||||
local ch = Input:translate('mouse_up', button, x, y)
|
||||
|
||||
if ch == 'control-shift-mouse_click' then -- hack
|
||||
local event = self.currentPage:pointToChild(x, y)
|
||||
_ENV.multishell.openTab({
|
||||
path = 'sys/apps/Lua.lua',
|
||||
args = { event.element },
|
||||
focused = true })
|
||||
|
||||
elseif ch and self.currentPage then
|
||||
if not self.currentPage.parent.device.side then
|
||||
self:click(ch, button, x, y)
|
||||
end
|
||||
end
|
||||
end)
|
||||
|
||||
singleThread('mouse_drag', function(button, x, y)
|
||||
local ch = Input:translate('mouse_drag', button, x, y)
|
||||
if ch and self.currentPage then
|
||||
local event = self.currentPage:pointToChild(x, y)
|
||||
event.type = ch
|
||||
self:inputEvent(event.element, event)
|
||||
self.currentPage:sync()
|
||||
end
|
||||
end)
|
||||
|
||||
singleThread('paste', function(text)
|
||||
Input:translate('paste')
|
||||
self:emitEvent({ type = 'paste', text = text })
|
||||
self.currentPage:sync()
|
||||
end)
|
||||
|
||||
local function keyFunction(event, code, held)
|
||||
local ch = Input:translate(event, code, held)
|
||||
|
||||
@@ -159,9 +54,108 @@ function Manager:init()
|
||||
end
|
||||
end
|
||||
|
||||
singleThread('char', function(code, held) keyFunction('char', code, held) end)
|
||||
singleThread('key_up', function(code, held) keyFunction('key_up', code, held) end)
|
||||
singleThread('key', function(code, held) keyFunction('key', code, held) end)
|
||||
local handlers = {
|
||||
char = keyFunction,
|
||||
key_up = keyFunction,
|
||||
key = keyFunction,
|
||||
|
||||
term_resize = function(_, side)
|
||||
if self.currentPage then
|
||||
-- the parent doesn't have any children set...
|
||||
-- that's why we have to resize both the parent and the current page
|
||||
-- kinda makes sense
|
||||
if self.currentPage.parent.device.side == side then
|
||||
self.currentPage.parent:resize()
|
||||
|
||||
self.currentPage:resize()
|
||||
self.currentPage:draw()
|
||||
self.currentPage:sync()
|
||||
end
|
||||
end
|
||||
end,
|
||||
|
||||
mouse_scroll = function(_, direction, x, y)
|
||||
if self.currentPage then
|
||||
local event = self.currentPage:pointToChild(x, y)
|
||||
local directions = {
|
||||
[ -1 ] = 'up',
|
||||
[ 1 ] = 'down'
|
||||
}
|
||||
-- revisit - should send out scroll_up and scroll_down events
|
||||
-- let the element convert them to up / down
|
||||
self:inputEvent(event.element,
|
||||
{ type = 'key', key = directions[direction] })
|
||||
self.currentPage:sync()
|
||||
end
|
||||
end,
|
||||
|
||||
-- this should be moved to the device !
|
||||
monitor_touch = function(_, side, x, y)
|
||||
Input:translate('mouse_click', 1, x, y)
|
||||
local ch = Input:translate('mouse_up', 1, x, y)
|
||||
if self.currentPage then
|
||||
if self.currentPage.parent.device.side == side then
|
||||
self:click(ch, 1, x, y)
|
||||
end
|
||||
end
|
||||
end,
|
||||
|
||||
mouse_click = function(_, button, x, y)
|
||||
Input:translate('mouse_click', button, x, y)
|
||||
|
||||
if self.currentPage then
|
||||
if not self.currentPage.parent.device.side then
|
||||
local event = self.currentPage:pointToChild(x, y)
|
||||
if event.element.focus and not event.element.inactive then
|
||||
self.currentPage:setFocus(event.element)
|
||||
self.currentPage:sync()
|
||||
end
|
||||
end
|
||||
end
|
||||
end,
|
||||
|
||||
mouse_up = function(_, button, x, y)
|
||||
local ch = Input:translate('mouse_up', button, x, y)
|
||||
|
||||
if ch == 'control-shift-mouse_click' then -- hack
|
||||
local event = self.currentPage:pointToChild(x, y)
|
||||
_ENV.multishell.openTab({
|
||||
path = 'sys/apps/Lua.lua',
|
||||
args = { event.element },
|
||||
focused = true })
|
||||
|
||||
elseif ch and self.currentPage then
|
||||
if not self.currentPage.parent.device.side then
|
||||
self:click(ch, button, x, y)
|
||||
end
|
||||
end
|
||||
end,
|
||||
|
||||
mouse_drag = function(_, button, x, y)
|
||||
local ch = Input:translate('mouse_drag', button, x, y)
|
||||
if ch and self.currentPage then
|
||||
local event = self.currentPage:pointToChild(x, y)
|
||||
event.type = ch
|
||||
self:inputEvent(event.element, event)
|
||||
self.currentPage:sync()
|
||||
end
|
||||
end,
|
||||
|
||||
paste = function(_, text)
|
||||
Input:translate('paste')
|
||||
self:emitEvent({ type = 'paste', text = text })
|
||||
self.currentPage:sync()
|
||||
end,
|
||||
}
|
||||
|
||||
-- use 1 handler to single thread all events
|
||||
Event.on({
|
||||
'char', 'key_up', 'key', 'term_resize',
|
||||
'mouse_scroll', 'monitor_touch', 'mouse_click',
|
||||
'mouse_up', 'mouse_drag', 'paste' },
|
||||
function(event, ...)
|
||||
handlers[event](event, ...)
|
||||
end)
|
||||
end
|
||||
|
||||
function Manager:configure(appName, ...)
|
||||
|
||||
@@ -460,6 +460,8 @@ function Util.toBytes(n)
|
||||
if not tonumber(n) then error('Util.toBytes: n must be a number', 2) end
|
||||
if n >= 1000000 or n <= -1000000 then
|
||||
return string.format('%sM', math.floor(n/1000000 * 10) / 10)
|
||||
elseif n >= 10000 or n <= -10000 then
|
||||
return string.format('%sK', math.floor(n/1000))
|
||||
elseif n >= 1000 or n <= -1000 then
|
||||
return string.format('%sK', math.floor(n/1000 * 10) / 10)
|
||||
end
|
||||
@@ -549,7 +551,6 @@ end
|
||||
-- end word wrapping
|
||||
|
||||
function Util.wordWrap(str, limit)
|
||||
|
||||
local longLines = Util.split(str)
|
||||
local lines = { }
|
||||
|
||||
@@ -560,6 +561,23 @@ function Util.wordWrap(str, limit)
|
||||
return lines
|
||||
end
|
||||
|
||||
function Util.args(arg)
|
||||
local tab = { remainder = { } }
|
||||
|
||||
local k = 1
|
||||
while k <= #arg do
|
||||
local v = arg[k]
|
||||
if string.sub(v, 1, 1) == '-' then
|
||||
local jopt = string.sub(v, 2)
|
||||
tab[ jopt ] = arg[ k + 1 ]
|
||||
k = k + 1
|
||||
else
|
||||
table.insert(tab.remainder, v)
|
||||
end
|
||||
k = k + 1
|
||||
end
|
||||
return tab
|
||||
end
|
||||
-- http://lua-users.org/wiki/AlternativeGetOpt
|
||||
local function getopt( arg, options )
|
||||
local tab = {}
|
||||
|
||||
Reference in New Issue
Block a user