--[[ Author: TheOriginalBIT Version: 1.0 Created: 25 Mar 2013 Last Update: 25 Mar 2013 License: COPYRIGHT NOTICE Copyright © 2013 Joshua Asbury a.k.a TheOriginalBIT [theoriginalbit@gmail.com] Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: -The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. -Visible credit is given to the original author. -The software is distributed in a non-profit way. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ]]-- local views = {} local cycleInfo = {} local activeView = nil local monitorSide = nil local monitorObj = nil local offset_x, offset_y = 0, 0 local shiftPressed = false local routineKeyboard = nil _G.assert = function(condition, errMsg, level) if not condition then error(errMsg, (tonumber(level) or 1) + 1) end return condition end function setActiveScreen(key) assert(views[key], 'A screen with the key \''..key..'\' does not exist', 2) activeView = key end function cycleActiveScreen() activeView = cycleInfo[activeView]._next end function registerScreen(key, prev_screen, next_screen) assert(not views[key], 'A screen with the key \''..key..'\' already exists', 2) assert(type(prev_screen) == 'string', 'Invalid parameter: expected prev_screen to be a string, got '..type(prev_screen), 2) assert(type(next_screen) == 'string', 'Invalid parameter: expected next_screen to be a string, got '..type(next_screen), 2) views[key] = {} cycleInfo[key] = { _prev = prev_screen, _next = next_screen} end function registerKey(screen, key, text, xPos, yPos, width, height, func, backColor, textColor) assert(views[screen], 'A screen with the key \''..screen..'\' does not exist', 2) assert(not views[screen][key], 'A key with the key \''..screen..'\' already exists', 2) assert(type(text) == 'string', 'Invalid parameter: expected text to be a string, got '..type(text), 2) assert(type(xPos) == 'number', 'Invalid parameter: expected xPos to be a number, got '..type(xPos), 2) assert(type(yPos) == 'number', 'Invalid parameter: expected yPos to be a number, got '..type(yPos), 2) assert(type(width) == 'number' or type(width) == 'nil', 'Invalid parameter: expected width to be a number or nil, got '..type(width), 2) assert(type(height) == 'number' or type(height) == 'nil', 'Invalid parameter: expected height to be a number or nil, got '..type(height), 2) assert(type(func) == 'function', 'Invalid parameter: expected func to be a function, got '..type(func), 2) assert(type(backColor) == 'number' and backColor >= 2^0 and backColor <= 2^15, 'Invalid parameter: expected backColor to be a number color, got '..type(backColor), 2) assert(type(textColor) == 'number' and textColor >= 2^0 and textColor <= 2^15, 'Invalid parameter: expected textColor to be a number color, got '..type(textColor), 2) views[screen][key] = {} views[screen][key]._t = text views[screen][key]._x = xPos views[screen][key]._y = yPos views[screen][key]._w = width or #text views[screen][key]._h = height or 1 views[screen][key]._bc = backColor views[screen][key]._tc = textColor views[screen][key].onClick = key == 'SF' and func or function( ... ) func(...) shiftPressed = false -- turn off shift, we have done our capital letter end views[screen][key].wasClicked = function(self, mouse_x, mouse_y) return mouse_x >= self._x + offset_x and mouse_x <= self._x + offset_x + self._w - 1 and mouse_y >= self._y + offset_y and mouse_y <= self._y + offset_y + self._h - 1 end views[screen][key].onDraw = function(self) if self._t == '^ ' and shiftPressed then term.setBackgroundColor(colors.lightBlue) else term.setBackgroundColor(self._bc) end term.setTextColor(self._tc) for y = 0, self._h - 1 do term.setCursorPos(offset_x + self._x, offset_y + self._y + y) write( string.rep(' ', self._w) ) end term.setCursorPos(offset_x + self._x + math.floor(self._w / 2 - #self._t / 2), offset_y + self._y + math.floor(self._h / 2)) if shiftPressed and not (self._t == ' space ' or self._t == 'enter') then write(string.upper(self._t) or '?') else write(self._t or '?') end end end function render() term.redirect(monitorObj) term.setBackgroundColor(colors.lightGray) for i = 1, 4 do term.setCursorPos(offset_x + 1, offset_y + i) write( string.rep(' ', 19) ) end for _,v in pairs(views[activeView]) do v:onDraw() end term.restore() end local function run() while true do local event = { coroutine.yield() } if event[1] == 'terminate' then return elseif (event[1] == 'monitor_touch' and event[2] == monitorSide) then for _, v in pairs(views[activeView]) do if v:wasClicked( event[3], event[4]) then v:onClick() break -- a button was clicked, we don't have stacked buttons end end end end end function pullEvent(useRaw) local pullEvent = useRaw and os.pullEventRaw or os.pullEvent local event = { pullEvent() } coroutine.resume(routineKeyboard, unpack(event) ) return unpack(event) end function isAlive() return routineKeyboard and coroutine.status(routineKeyboard) ~= 'dead' end function startCoroutine() if not routineKeyboard or not isAlive() then routineKeyboard = coroutine.create(run) end coroutine.resume(routineKeyboard) end function setup( side, topLeftX, topLeftY ) if topLeftX then offset_x = topLeftX end if topLeftY then offset_y = topLeftY end assert(type(side) == 'string', 'Invalid parameter: expected side to be a string, got '..type(side), 2) if peripheral.getType(side) ~= 'monitor' then printError('No monitor on the computers '..side..' side') error() end monitorSide = side monitorObj = peripheral.wrap(side) if not monitorObj.isColor() then printError('Monitor must be an advanced monitor') error() end monitorObj.setTextScale(1) local mw, mh = monitorObj.getSize() local scale = mw / 19 if scale > 5 then scale = 5 end if scale < 0.5 then scale = 0.5 end monitorObj.setTextScale(scale) term.redirect(monitorObj) local w, h = term.getSize() term.restore() if w < 19 then printError('Monitor is not wide enough to display keyboard') error() end if h < 4 then printError('Monitor is not tall enough to display keyboard') error() end registerScreen('ABC', '#+=', '123') registerScreen('123', 'ABC', '#+=') registerScreen('#+=', '123', 'ABC') setActiveScreen('ABC') -- FIRST VIEW: ABC do -- First row, ASCII keyboard registerKey('ABC', 'q', 'q', 1, 1, nil, nil, function() os.queueEvent('key', keys.q) os.queueEvent('char', shiftPressed and 'Q' or 'q') end, colors.lightGray, colors.black) registerKey('ABC', 'w', 'w', 3, 1, nil, nil, function() os.queueEvent('key', keys.w) os.queueEvent('char', shiftPressed and 'W' or 'w') end, colors.lightGray, colors.black) registerKey('ABC', 'e', 'e', 5, 1, nil, nil, function() os.queueEvent('key', keys.e) os.queueEvent('char', shiftPressed and 'E' or 'e') end, colors.lightGray, colors.black) registerKey('ABC', 'r', 'r', 7, 1, nil, nil, function() os.queueEvent('key', keys.r) os.queueEvent('char', shiftPressed and 'R' or 'r') end, colors.lightGray, colors.black) registerKey('ABC', 't', 't', 9, 1, nil, nil, function() os.queueEvent('key', keys.t) os.queueEvent('char', shiftPressed and 'T' or 't') end, colors.lightGray, colors.black) registerKey('ABC', 'y', 'y', 11, 1, nil, nil, function() os.queueEvent('key', keys.y) os.queueEvent('char', shiftPressed and 'Y' or 'y') end, colors.lightGray, colors.black) registerKey('ABC', 'u', 'u', 13, 1, nil, nil, function() os.queueEvent('key', keys.u) os.queueEvent('char', shiftPressed and 'U' or 'u') end, colors.lightGray, colors.black) registerKey('ABC', 'i', 'i', 15, 1, nil, nil, function() os.queueEvent('key', keys.i) os.queueEvent('char', shiftPressed and 'I' or 'i') end, colors.lightGray, colors.black) registerKey('ABC', 'o', 'o', 17, 1, nil, nil, function() os.queueEvent('key', keys.o) os.queueEvent('char', shiftPressed and 'O' or 'o') end, colors.lightGray, colors.black) registerKey('ABC', 'p', 'p', 19, 1, nil, nil, function() os.queueEvent('key', keys.p) os.queueEvent('char', shiftPressed and 'P' or 'p') end, colors.lightGray, colors.black) -- Second row, ASCII keyboard registerKey('ABC', 'a', 'a', 2, 2, nil, nil, function() os.queueEvent('key', keys.a) os.queueEvent('char', shiftPressed and 'A' or 'a') end, colors.lightGray, colors.black) registerKey('ABC', 's', 's', 4, 2, nil, nil, function() os.queueEvent('key', keys.s) os.queueEvent('char', shiftPressed and 'S' or 's') end, colors.lightGray, colors.black) registerKey('ABC', 'd', 'd', 6, 2, nil, nil, function() os.queueEvent('key', keys.d) os.queueEvent('char', shiftPressed and 'D' or 'd') end, colors.lightGray, colors.black) registerKey('ABC', 'f', 'f', 8, 2, nil, nil, function() os.queueEvent('key', keys.f) os.queueEvent('char', shiftPressed and 'F' or 'f') end, colors.lightGray, colors.black) registerKey('ABC', 'g', 'g', 10, 2, nil, nil, function() os.queueEvent('key', keys.g) os.queueEvent('char', shiftPressed and 'G' or 'g') end, colors.lightGray, colors.black) registerKey('ABC', 'h', 'h', 12, 2, nil, nil, function() os.queueEvent('key', keys.h) os.queueEvent('char', shiftPressed and 'H' or 'h') end, colors.lightGray, colors.black) registerKey('ABC', 'j', 'j', 14, 2, nil, nil, function() os.queueEvent('key', keys.j) os.queueEvent('char', shiftPressed and 'J' or 'j') end, colors.lightGray, colors.black) registerKey('ABC', 'k', 'k', 16, 2, nil, nil, function() os.queueEvent('key', keys.k) os.queueEvent('char', shiftPressed and 'K' or 'k') end, colors.lightGray, colors.black) registerKey('ABC', 'l', 'l', 18, 2, nil, nil, function() os.queueEvent('key', keys.l) os.queueEvent('char', shiftPressed and 'L' or 'l') end, colors.lightGray, colors.black) -- Third row, ASCII keyboard registerKey('ABC', 'SF', '^ ', 1, 3, nil, nil, function() os.queueEvent('key', keys.leftShift) shiftPressed = not shiftPressed end, colors.lightGray, colors.black) registerKey('ABC', 'z', 'z', 4, 3, nil, nil, function() os.queueEvent('key', keys.z) os.queueEvent('char', shiftPressed and 'Z' or 'z') end, colors.lightGray, colors.black) registerKey('ABC', 'x', 'x', 6, 3, nil, nil, function() os.queueEvent('key', keys.x) os.queueEvent('char', shiftPressed and 'X' or 'x') end, colors.lightGray, colors.black) registerKey('ABC', 'c', 'c', 8, 3, nil, nil, function() os.queueEvent('key', keys.c) os.queueEvent('char', shiftPressed and 'C' or 'c') end, colors.lightGray, colors.black) registerKey('ABC', 'v', 'v', 10, 3, nil, nil, function() os.queueEvent('key', keys.v) os.queueEvent('char', shiftPressed and 'V' or 'v') end, colors.lightGray, colors.black) registerKey('ABC', 'b', 'b', 12, 3, nil, nil, function() os.queueEvent('key', keys.b) os.queueEvent('char', shiftPressed and 'B' or 'b') end, colors.lightGray, colors.black) registerKey('ABC', 'n', 'n', 14, 3, nil, nil, function() os.queueEvent('key', keys.n) os.queueEvent('char', shiftPressed and 'N' or 'n') end, colors.lightGray, colors.black) registerKey('ABC', 'm', 'm', 16, 3, nil, nil, function() os.queueEvent('key', keys.m) os.queueEvent('char', shiftPressed and 'M' or 'm') end, colors.lightGray, colors.black) registerKey('ABC', 'BK', '<-', 18, 3, nil, nil, function() os.queueEvent('key', keys.backspace) end, colors.lightGray, colors.black) -- Fourth row, ASCII keyboard registerKey('ABC', 'SP_123', '123', 1, 4, nil, nil, function() setActiveScreen('123') end, colors.lightGray, colors.black) registerKey('ABC', 'SB', ' space ', 5, 4, nil, nil, function() os.queueEvent('key', keys.space) os.queueEvent('char', ' ') end, colors.lightGray, colors.black) registerKey('ABC', 'EN', 'enter', 15, 4, nil, nil, function() os.queueEvent('key', keys.enter) end, colors.lightGray, colors.black) end -- SECOND VIEW: 123 do -- First row, Numbers registerKey('123', '1', '1', 1, 1, nil, nil, function() os.queueEvent('key', keys.one) os.queueEvent('char', '1') end, colors.lightGray, colors.black) registerKey('123', '2', '2', 3, 1, nil, nil, function() os.queueEvent('key', keys.two) os.queueEvent('char', '2') end, colors.lightGray, colors.black) registerKey('123', '3', '3', 5, 1, nil, nil, function() os.queueEvent('key', keys.three) os.queueEvent('char', '3') end, colors.lightGray, colors.black) registerKey('123', '4', '4', 7, 1, nil, nil, function() os.queueEvent('key', keys.four) os.queueEvent('char', '4') end, colors.lightGray, colors.black) registerKey('123', '5', '5', 9, 1, nil, nil, function() os.queueEvent('key', keys.five) os.queueEvent('char', '5') end, colors.lightGray, colors.black) registerKey('123', '6', '6', 11, 1, nil, nil, function() os.queueEvent('key', keys.six) os.queueEvent('char', '6') end, colors.lightGray, colors.black) registerKey('123', '7', '7', 13, 1, nil, nil, function() os.queueEvent('key', keys.seven) os.queueEvent('char', '7') end, colors.lightGray, colors.black) registerKey('123', '8', '8', 15, 1, nil, nil, function() os.queueEvent('key', keys.eight) os.queueEvent('char', '8') end, colors.lightGray, colors.black) registerKey('123', '9', '9', 17, 1, nil, nil, function() os.queueEvent('key', keys.nine) os.queueEvent('char', '9') end, colors.lightGray, colors.black) registerKey('123', '0', '0', 19, 1, nil, nil, function() os.queueEvent('key', keys.zero) os.queueEvent('char', '0') end, colors.lightGray, colors.black) -- Second row, Symbols registerKey('123', 'minus', '-', 2, 2, nil, nil, function() os.queueEvent('key', keys.minus) os.queueEvent('char', '-') end, colors.lightGray, colors.black) registerKey('123', 'slash', '/', 4, 2, nil, nil, function() os.queueEvent('key', keys.slash) os.queueEvent('char', '/') end, colors.lightGray, colors.black) registerKey('123', 'colon', ':', 6, 2, nil, nil, function() os.queueEvent('key', keys.colon) os.queueEvent('char', ':') end, colors.lightGray, colors.black) registerKey('123', 'semicolon', ';', 8, 2, nil, nil, function() os.queueEvent('key', keys.colon) os.queueEvent('char', ';') end, colors.lightGray, colors.black) registerKey('123', 'lbracket', '(', 10, 2, nil, nil, function() os.queueEvent('key', keys.nine) os.queueEvent('char', '(') end, colors.lightGray, colors.black) registerKey('123', 'rbrakcet', ')', 12, 2, nil, nil, function() os.queueEvent('key', keys.zero) os.queueEvent('char', ')') end, colors.lightGray, colors.black) registerKey('123', 'dollars', '$', 14, 2, nil, nil, function() os.queueEvent('key', keys.four) os.queueEvent('char', '$') end, colors.lightGray, colors.black) registerKey('123', 'amp', '&', 16, 2, nil, nil, function() os.queueEvent('key', keys.seven) os.queueEvent('char', '&') end, colors.lightGray, colors.black) registerKey('123', 'at', '@', 18, 2, nil, nil, function() os.queueEvent('key', keys.two) os.queueEvent('char', '@') end, colors.lightGray, colors.black) -- third row, Symbols registerKey('123', 'CYC_#+=', '#=', 1, 3, nil, nil, function() setActiveScreen('#+=') end, colors.lightGray, colors.black) registerKey('123', 'period', '.', 5, 3, nil, nil, function() os.queueEvent('key', keys.period) os.queueEvent('char', '.') end, colors.lightGray, colors.black) registerKey('123', 'comma', ',', 7, 3, nil, nil, function() os.queueEvent('key', keys.comma) os.queueEvent('char', ',') end, colors.lightGray, colors.black) registerKey('123', 'question', '?', 9, 3, nil, nil, function() os.queueEvent('key', keys.slash) os.queueEvent('char', '?') end, colors.lightGray, colors.black) registerKey('123', 'exclamation', '!', 11, 3, nil, nil, function() os.queueEvent('key', keys.one) os.queueEvent('char', '!') end, colors.lightGray, colors.black) registerKey('123', 'singleQuote', '\'', 13, 3, nil, nil, function() os.queueEvent('key', 0) os.queueEvent('char', '\'') end, colors.lightGray, colors.black) registerKey('123', 'quote', '\"', 15, 3, nil, nil, function() os.queueEvent('key', 0) os.queueEvent('char', '\"') end, colors.lightGray, colors.black) registerKey('123', 'BK', '<-', 18, 3, nil, nil, function() os.queueEvent('key', keys.backspace) end, colors.lightGray, colors.black) -- Fourth row, Standard registerKey('123', 'SP_ABC', 'ABC', 1, 4, nil, nil, function() setActiveScreen('ABC') end, colors.lightGray, colors.black) registerKey('123', 'SB', ' space ', 5, 4, nil, nil, function() os.queueEvent('key', keys.space) os.queueEvent('char', ' ') end, colors.lightGray, colors.black) registerKey('123', 'EN', 'enter', 15, 4, nil, nil, function() os.queueEvent('key', keys.enter) end, colors.lightGray, colors.black) end -- THIRD VIEW: #+= do -- First row, Symbols registerKey('#+=', 'lsbrace', '[', 1, 1, nil, nil, function() os.queueEvent('key', keys.leftBracket) os.queueEvent('char', '[') end, colors.lightGray, colors.black) registerKey('#+=', 'rsbrace', ']', 3, 1, nil, nil, function() os.queueEvent('key', keys.rightBracket) os.queueEvent('char', ']') end, colors.lightGray, colors.black) registerKey('#+=', 'lcbrace', '{', 5, 1, nil, nil, function() os.queueEvent('key', keys.leftBracket) os.queueEvent('char', '{') end, colors.lightGray, colors.black) registerKey('#+=', 'rcbrace', '}', 7, 1, nil, nil, function() os.queueEvent('key', keys.rightBracket) os.queueEvent('char', '}') end, colors.lightGray, colors.black) registerKey('#+=', 'hash', '#', 9, 1, nil, nil, function() os.queueEvent('key', keys.three) os.queueEvent('char', '#') end, colors.lightGray, colors.black) registerKey('#+=', 'percent', '%', 11, 1, nil, nil, function() os.queueEvent('key', keys.five) os.queueEvent('char', '%') end, colors.lightGray, colors.black) registerKey('#+=', 'carrot', '^', 13, 1, nil, nil, function() os.queueEvent('key', keys.six) os.queueEvent('char', '^') end, colors.lightGray, colors.black) registerKey('#+=', 'asterisk', '*', 15, 1, nil, nil, function() os.queueEvent('key', keys.eight) os.queueEvent('char', '*') end, colors.lightGray, colors.black) registerKey('#+=', 'plus', '+', 17, 1, nil, nil, function() os.queueEvent('key', keys.equals) os.queueEvent('char', '+') end, colors.lightGray, colors.black) registerKey('#+=', 'equals', '=', 19, 1, nil, nil, function() os.queueEvent('key', keys.equals) os.queueEvent('char', '=') end, colors.lightGray, colors.black) -- Second row, Symbols registerKey('#+=', 'score', '_', 2, 2, nil, nil, function() os.queueEvent('key', keys.minus) os.queueEvent('char', '_') end, colors.lightGray, colors.black) registerKey('#+=', 'backslash', '\\', 4, 2, nil, nil, function() os.queueEvent('key', keys.backslash) os.queueEvent('char', '\\') end, colors.lightGray, colors.black) registerKey('#+=', 'bar', '|', 6, 2, nil, nil, function() os.queueEvent('key', keys.backslash) os.queueEvent('char', '|') end, colors.lightGray, colors.black) registerKey('#+=', 'tild', '~', 8, 2, nil, nil, function() os.queueEvent('key', 0) os.queueEvent('char', '~') end, colors.lightGray, colors.black) registerKey('#+=', 'lt', '<', 10, 2, nil, nil, function() os.queueEvent('key', keys.comma) os.queueEvent('char', '<') end, colors.lightGray, colors.black) registerKey('#+=', 'gt', '>', 12, 2, nil, nil, function() os.queueEvent('key', keys.period) os.queueEvent('char', '>') end, colors.lightGray, colors.black) registerKey('#+=', 'dollars', '$', 14, 2, nil, nil, function() os.queueEvent('key', keys.four) os.queueEvent('char', '$') end, colors.lightGray, colors.black) registerKey('#+=', 'amp', '&', 16, 2, nil, nil, function() os.queueEvent('key', keys.seven) os.queueEvent('char', '&') end, colors.lightGray, colors.black) registerKey('#+=', 'at', '@', 18, 2, nil, nil, function() os.queueEvent('key', keys.two) os.queueEvent('char', '@') end, colors.lightGray, colors.black) -- third row, Symbols registerKey('#+=', 'CYC_123', '12', 1, 3, nil, nil, function() setActiveScreen('123') end, colors.lightGray, colors.black) registerKey('#+=', 'period', '.', 5, 3, nil, nil, function() os.queueEvent('key', keys.period) os.queueEvent('char', '.') end, colors.lightGray, colors.black) registerKey('#+=', 'comma', ',', 7, 3, nil, nil, function() os.queueEvent('key', keys.comma) os.queueEvent('char', ',') end, colors.lightGray, colors.black) registerKey('#+=', 'question', '?', 9, 3, nil, nil, function() os.queueEvent('key', keys.slash) os.queueEvent('char', '?') end, colors.lightGray, colors.black) registerKey('#+=', 'exclamation', '!', 11, 3, nil, nil, function() os.queueEvent('key', keys.one) os.queueEvent('char', '!') end, colors.lightGray, colors.black) registerKey('#+=', 'singleQuote', '\'', 13, 3, nil, nil, function() os.queueEvent('key', 0) os.queueEvent('char', '\'') end, colors.lightGray, colors.black) registerKey('#+=', 'quote', '\"', 15, 3, nil, nil, function() os.queueEvent('key', 0) os.queueEvent('char', '\"') end, colors.lightGray, colors.black) registerKey('#+=', 'BK', '<-', 18, 3, nil, nil, function() os.queueEvent('key', keys.backspace) end, colors.lightGray, colors.black) -- Fourth row, Standard registerKey('#+=', 'SP_ABC', 'ABC', 1, 4, nil, nil, function() setActiveScreen('ABC') end, colors.lightGray, colors.black) registerKey('#+=', 'SB', ' space ', 5, 4, nil, nil, function() os.queueEvent('key', keys.space) os.queueEvent('char', ' ') end, colors.lightGray, colors.black) registerKey('#+=', 'EN', 'enter', 15, 4, nil, nil, function() os.queueEvent('key', keys.enter) end, colors.lightGray, colors.black) end startCoroutine() end --[[ q w e r t y u i o p a s d f g h j k l ^ z x c v b n m <- 123 space enter 1 2 3 4 5 6 7 8 9 0 - / : ; ( ) $ & @ " #+= . , ? ! ' <- ABC space enter [ ] { } # % ^ * + = _ \ | ~ < > $ & @ " 123 . , ? ! ' <- ABC space enter ]]