keypress
Description
Keypress API
Installation
Copy one of these commands into your ComputerCraft terminal:
wget:
wget https://raw.githubusercontent.com/LDDestroier/CC/master/keypress.lua keypressArchive:
wget https://cc.shobie.xyz/cc/get/gh-LDDestroier-CC-keypress keypress
Quick Install:
wget https://cc.shobie.xyz/cc/get/gh-LDDestroier-CC-keypress keypress
Usage
Run: keypress
Tags
Source
View Original SourceCode Preview
-- Keypress API
-- by LDDestroier
--
-- keypress event:
-- kp = {
-- key : numerical keycode of key pressed
-- char : printable character of keypress
-- use this in place of "char" events, like for text input
-- char_pressed : character of keypress, not necessarily printed
-- for instance, pressing "A" will return a char event, but
-- pressing "CTRL+A" will not
-- notation : vim-style notation of key event, like <C-PageUp>
-- Modifier keys do not have notation on their own.
-- name : vim-style notaton of EVERY key event, including modifier keys.
-- if you want to match against every possible keystroke, use this.
-- time : os.epoch() time of keypress
-- ctrl : true/false if CTRL was held
-- alt : true/false if ALT was held
-- shift : true/false if SHIFT was held
-- paste : if not nil, contains text that had been pasted
-- }
local keypress = {}
local _DEMO = false
if select(1, ...) == "demo" then
_DEMO = true
end
local r_keys = {}
for k,v in pairs(keys) do
r_keys[v] = k
end
local keys_down = {}
local last_epoch, last_key = 0, 0
local last_evt
local delta
keypress.keys_down = keys_down
local nonprintable_keys = {
[keys.backspace] = true,
[keys.leftCtrl] = true,
[keys.rightCtrl] = true,
[keys.leftAlt] = true,
[keys.rightAlt] = true,
[keys.leftShift] = true,
[keys.rightShift] = true,
[keys.capsLock] = true,
[keys.enter] = true,
[keys.insert] = true,
[keys.delete] = true,
[keys.home] = true,
[keys["end"]] = true,
[keys.pageDown] = true,
[keys.pageUp] = true,
[keys.numLock] = true,
[keys.scrollLock] = true,
[keys.numPadEnter] = true,
[keys.up] = true,
[keys.down] = true,
[keys.left] = true,
[keys.right] = true,
}
for i = 1, 15 do
nonprintable_keys[keys["f" .. i]] = true
end
-- TODO: make these local variables as to not polute the keys table
keys.ctrl = 1001
keys.shift = 1002
keys.alt = 1003
for k,v in pairs(keys) do
keys_down[k] = false
end
local function modifier_keydowns()
keys_down[keys.ctrl] = keys_down[keys.leftCtrl] or keys_down[keys.rightCtrl]
keys_down[keys.shift] = keys_down[keys.leftShift] or keys_down[keys.rightShift]
keys_down[keys.alt] = keys_down[keys.leftAlt] or keys_down[keys.rightAlt]
end
local modifier_lookup = {
[ keys.leftCtrl ] = "Ctrl",
[ keys.rightCtrl ] = "Ctrl",
[ keys.ctrl ] = "Ctrl",
[ keys.leftShift ] = "Shift",
[ keys.rightShift ] = "Shift",
[ keys.shift ] = "Shift",
[ keys.leftAlt ] = "Alt",
[ keys.rightAlt ] = "Alt",
[ keys.alt ] = "Alt",
ctrl = {
[ keys.leftCtrl ] = true,
[ keys.rightCtrl ] = true,
[ keys.ctrl ] = true,
},
shift = {
[ keys.leftShift ] = true,
[ keys.rightShift ] = true,
[ keys.shift ] = true,
},
alt = {
[ keys.leftAlt ] = true,
[ keys.rightAlt ] = true,
[ keys.alt ] = true,
}
}
-- requires kp.notation to be populated to work right
local function get_keypress_name( kp )
if kp.notation then
return kp.notation
elseif modifier_lookup[ kp.key ] then
return "<" .. modifier_lookup[ kp.key ] .. ">"
else
return "<UnknownKey>"
end
end
function keypress.resume(...)
local evt = {...}
local output = {}
local paste_contents
if evt[1] == "keypress" then
if _DEMO then
-- exit demo with CTRL-C
if evt[2].key == keys.c and evt[2].ctrl then
return "keypress_terminatedemo"
else
print("key = keys." .. (r_keys[evt[2] .key] or "???"))
if evt[2].char then
write("char = '" .. evt[2].char .. "'")
else
write("char = nil")
end
if evt[2].char_pressed then
print(" ('" .. evt[2].char_pressed .. "')")
else
print("")
end
print("name = " .. (evt[2].name or "nil"))
print("notation = " .. (evt[2].notation or "(NONE)"))
write("mods = ")
write(evt[2].ctrl and "ctrl " or "")
write(evt[2].alt and "alt " or "")
print(evt[2].shift and "shift" or "")
if evt[2].paste then
print("paste = " .. evt[2].paste)
end
print("")
end
end
-- keypress events should die when fed back into keypress.resume()
return
elseif evt[1] == "paste" then
-- assume a paste event means you pressed 'v'
evt[1] = "key"
paste_contents = evt[2]
evt[2] = keys.v
evt[3] = false
end
if evt[1] == "key" then
keys_down[evt[2]] = true
modifier_keydowns()
if nonprintable_keys[evt[2]] or (keys_down[keys.ctrl] or keys_down[keys.alt]) then
output[1] = "keypress"
output[2] = {
key = evt[2],
char = nil, -- represents a printable character -- use this if you're using keypress API for text input
char_pressed = nil, -- represents the character pressed regardless of if it should print
time = os.epoch(),
ctrl = keys_down[keys.ctrl],
shift = keys_down[keys.shift],
alt = keys_down[keys.alt],
paste = paste_contents
}
output[2].notation = keypress.to_vim_notation(output[2])
output[2].name = get_keypress_name(output[2])
else
last_epoch = os.epoch()
last_key = evt[2]
end
elseif evt[1] == "key_up" then
keys_down[evt[2]] = false
modifier_keydowns()
elseif evt[1] == "char" and last_evt == "key" then
delta = os.epoch() - last_epoch
if delta <= 90 then
output[1] = "keypress"
output[2] = {
key = last_key,
char = evt[2],
char_pressed = evt[2],
time = os.epoch(),
ctrl = keys_down[keys.ctrl],
shift = keys_down[keys.shift],
alt = keys_down[keys.alt],
paste = paste_contents
}
output[2].notation = keypress.to_vim_notation(output[2])
output[2].name = get_keypress_name(output[2])
end
else
last_key = nil
end
if #output == 0 then
output = evt
end
last_evt = evt[1]
return table.unpack(output)
end
-- convert some key codes to characters
local keys_printable_lookup = {
[ keys.one ] = "1",
[ keys.two ] = "2",
[ keys.three ] = "3",
[ keys.four ] = "4",
[ keys.five ] = "5",
[ keys.six ] = "6",
[ keys.seven ] = "7",
[ keys.eight ] = "8",
[ keys.nine ] = "9",
[ keys.zero ] = "0",
[ keys.grave ] = "`",
[ keys.equals ] = "=",
[ keys.minus ] = "-",
[ keys.underscore ] = "_",
[ keys.leftBracket ] = "[",
[ keys.rightBracket ] = "]",
[ keys.apostrophe ] = "'",
[ keys.colon ] = ":",
[ keys.semiColon ] = ";",
[ keys.period ] = ".",
[ keys.comma ] = ",",
[ keys.slash ] = "/",
[ keys.backslash ] = "\\",
}
local alphabet = "abcdefghijklmnopqrstuvwxyz"
for i = 1, #alphabet do
keys_printable_lookup[ keys[alphabet:sub(i, i)] ] = alphabet:sub(i, i)
end
-- lookup table to turn keypress events into vim notation
local vim_notation_lookup = {
[ keys.home ] = "Home",
[ keys["end"] ] = "End",
[ keys.pageUp ] = "PageUp",
[ keys.pageDown ] = "PageDown",
[ keys.insert ] = "Insert",
[ keys.delete ] = "Del",
[ keys.space ] = "Space",
[ keys.tab ] = "Tab",
[ keys.enter ] = "Enter",
[ keys.backspace ] = "BS",
[ "<" ] = "lt",
[ "|" ] = "Bar",
[ "\\" ] = "Bslash",
[ "\000" ] = "Nul",
[ keys.left ] = "Left",
[ keys.right ] = "Right",
[ keys.up ] = "Up",
[ keys.down ] = "Down",
-- numpad keys that do not change if numlock is on or off
[ keys.numPadAdd ] = "kPlus",
[ keys.numPadSubtract ] = "kMinus",
[ keys.numPadDivide ] = "kDivide",
[ keys.multiply ] = "kMultiply",
[ keys.numPadComma ] = "kComma",
[ keys.numPadEnter ] = "kEnter",
[ keys.numPadEquals ] = "kEqual",
-- NOTE: unsure of actual Vim notation (if any), since I don't own a keyboard with these keys
[ keys.kanji ] = "Kanji",
[ keys.kana ] = "Kana",
[ keys.ax ] = "Ax",
[ keys.yen ] = "Yen",
[ keys.stop ] = "Stop",
[ keys.convert ] = "Convert",
[ keys.noconvert ] = "NoConvert",
-- NOTE: I am quite sure these keys are not recognized in Vim, but they *are* in CraftOS and are not modifiers
[ keys.capsLock ] = "CapsLock",
[ keys.scollLock ] = "ScrollLock", -- 'scollLock' misspelled in CraftOS
[ keys.numLock ] = "NumLock",
[ keys.pause ] = "Pause",
}
-- function keys
for i = 1, 15 do
vim_notation_lookup[ keys["f" .. i] ] = "F" .. i
end
-- treated as though numlock is OFF
local vim_notation_nonumlock = {
[ keys.numPadDecimal ] = "kDel",
[ keys.numPad0 ] = "Insert",
[ keys.numPad1 ] = "kEnd",
[ keys.numPad2 ] = "kDown",
[ keys.numPad3 ] = "kPageDown",
[ keys.numPad4 ] = "kLeft",
[ keys.numPad5 ] = "kOrigin",
[ keys.numPad6 ] = "kRight",
[ keys.numPad7 ] = "kHome",
[ keys.numPad8 ] = "kUp",
[ keys.numPad9 ] = "kPageUp",
}
-- what to register if numlock is ON
local vim_notation_numlock = {
[ keys.numPadDecimal ] = "kPoint",
[ keys.numPad0 ] = "k0",
[ keys.numPad1 ] = "k1",
[ keys.numPad2 ] = "k2",
[ keys.numPad3 ] = "k3",
[ keys.numPad4 ] = "k4",
[ keys.numPad5 ] = "k5",
[ keys.numPad6 ] = "k6",
[ keys.numPad7 ] = "k7",
[ keys.numPad8 ] = "k8",
[ keys.numPad9 ] = "k9",
}
-- aliases for vim notation into other vim notation
local vim_notation_alias = {
[ "kDel" ] = "Del",
[ "kEnd" ] = "End",
[ "kDown" ] = "Down",
[ "kPageDown" ] = "PageDown",
[ "kLeft" ] = "Left",
[ "kRight" ] = "Right",
[ "kHome" ] = "Home",
[ "kUp" ] = "Up",
[ "kPageUp" ] = "PageUp",
}
-- lookup table for shift-modified characters
-- might not be representative of keyboards other than my own
local shifted_keys = {
['1'] = '!',
['2'] = '@',
['3'] = '#',
['4'] = '{{code}}#039;,
['5'] = '%',
['6'] = '^',
['7'] = '&',
['8'] = '*',
['9'] = '(',
['0'] = ')',
['-'] = '_',
['='] = '+',
['`'] = '~',
['['] = '{',
[']'] = '}',
['\\'] = '|',
[';'] = ':',
['\''] = '\"',
[','] = "<",
['.'] = ">",
['/'] = "?",
}
local function uppersize(char)
return shifted_keys[char] or char:upper()
end
function keypress.to_vim_notation( kp )
if (not kp) or type(kp) ~= "table" then return "", false end
if not kp.key then return "", false end
local output = {"<", "", "", "", "", ">"}
-- output[2] is "M" (alt)
-- output[3] is "C" (ctrl)
-- output[4] is "S" (shift)
-- output[5] is the key code
-- if the keypress has a printable character, omit the "S" notation
local do_omit_s = false
-- check if key is numlock-modifiable
if vim_notation_numlock[ kp.key ] then
-- if a character event was queued, that means numlock must have been on!
if kp.char then
output[5] = vim_notation_numlock[ kp.key ]
else
output[5] = vim_notation_nonumlock[ kp.key ]
end
else
if vim_notation_lookup[ kp.char ] then
output[5] = vim_notation_lookup[ kp.char ]
elseif (kp.ctrl or kp.alt) and keys_printable_lookup[ kp.key ] then
output[5] = keys_printable_lookup[ kp.key ]
if kp.shift then
output[5] = uppersize(output[5])
end
kp.char_pressed = output[5]
do_omit_s = true
output[5] = vim_notation_lookup[ output[5] ] or output[5]
elseif vim_notation_lookup[ kp.key ] then
output[5] = vim_notation_lookup[ kp.key ]
end
end
if kp.char then
do_omit_s = true
end
kp.char_pressed = kp.char_pressed or kp.char
-- tack on modifier codes
if kp.alt and not modifier_lookup.alt[ kp.key ] then
output[2] = "M-"
end
if kp.ctrl and not modifier_lookup.ctrl[ kp.key ] then
output[3] = "C-"
end
if kp.shift and (not do_omit_s) and not modifier_lookup.shift[ kp.key ] then
output[4] = "S-"
end
-- enforce notation aliases
if vim_notation_alias[ output[5] ] then
output[5] = vim_notation_alias[ output[5] ]
end
-- for keys without notation, remove the chevrons and use the printed character
if output[5] == "" then
if not (kp.ctrl or kp.alt) then
output[1] = ""
output[6] = ""
end
output[5] = kp.char
end
if output[5] then
return table.concat(output)
else
return nil
end
end
function keypress.process()
if _DEMO then
print("Keypress API Demo")
print("Press CTRL-C to exit.")
end
while true do
local evt, kp = keypress.resume( os.pullEvent() )
if evt == "keypress" then
os.queueEvent(evt, kp)
elseif _DEMO and evt == "keypress_terminatedemo" then
print("Demo ended.")
return
end
end
end
if _DEMO then
keypress.process()
end
return keypress