Guest User

dkeylib

a guest
Aug 6th, 2012
54
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Lua 18.01 KB | None | 0 0
  1. dkeylib = {
  2.     -- Feel free to edit the below settings
  3.     layoutName = "US",      -- Keyboard layout
  4.     repeatDelay = 0.5,      -- Delay before starting key repeating (In seconds)
  5.     repeatInterval = 0.02,  -- Delay between each repeated key (In seconds)
  6.    
  7.     -- end of editable settings --
  8.     version = 1,        -- Version Number
  9.     versionMinor = 3,   -- Minor version number
  10.     loaded = false,     -- true if dkeylib has been loaded. false otherwise
  11.    
  12.     layouts = {},       -- Layouts for various keyboards
  13.     layout = {},        -- Current layout
  14.     processors = {},    -- Various extra processing functions you may choose to use
  15.     pressedvkeys = {},  -- Current virtual keys that have been pressed
  16.    
  17.     bind = {},          -- Namespace for bind related functions
  18.     allbinds = {},      -- Current keyboard binds
  19.     key = {},           -- Last pressed key
  20. }
  21.  
  22. --[[
  23. -- Notes for lua script writers developer --
  24.   It's recommended you do not modify anything marked as readonly,
  25.   as the behaviour of doing so is not defined.
  26.  
  27. Bind interface
  28.   dkeylib:newbind(name [, priority])
  29.     name        string      The name of the bind (This must be unique)
  30.     priority    int         The priority of the bind (higher goes first)    default = 0
  31.     returns:    bind object see bindobj
  32.    
  33.     Create a new bind object with the name and priority specified
  34.  
  35.   dkeylib:getbind(name)
  36.     name        string      The name of the bind to get
  37.     returns:    bind object or nil if the bind does not exist
  38.    
  39.     Get the bind object with the name name
  40.    
  41.   dkeylib:isvkeydown(vkeys)
  42.     vkeys       multiple    A single vkey, or a table of vkeys to test
  43.     returns:    true if all the specified vkeys are currently down, false otherwise
  44.  
  45.     Test if a vkey is being pressed (search for [MAPPINGS])
  46.    
  47.   --------------------------------------------------------------------------------
  48.   bindobj = {
  49.     enabled     if true, the bind is enabled and bound functions are called
  50.     name        readonly. The name passed into newbind when this bind was created
  51.     priority    readonly. The priority of the bind object (higher goes first)
  52.   }
  53.  
  54.   bindobj:bind(f [, key, modifiers, userdata])
  55.     f           function    The handler for this bind
  56.     key         multiple    The key to bind the handler to          default = nil
  57.     modifiers   multiple    The key modifiers (shift etc.)          default = -1
  58.     userdata    multiple    Extra user specified data to pass to f  default = nil
  59.     returns:    nil
  60.    
  61.     Bind the function f.
  62.      If key is nil then f becomes the global key handler
  63.         modifiers has no effect
  64.      
  65.      Otherwise f is bound to key specified
  66.         modifiers can be a number or a table of modifiers (see vkeys)
  67.        
  68.         -1 will bind f to any combination of modifiers
  69.        
  70.      The function you should pass into bind should look like the following
  71.         function bind( key, userdata )
  72.             [or]
  73.         function bind( key )
  74.      
  75.      Search for [KEY] to get an idea of what key is.
  76.    
  77.    
  78. Binds are called in the following order
  79.   start at highest bind
  80.   call specific modifier bind (eg. shift+r)
  81.   call key handler
  82.   call global key handler
  83.   move to lower priority bind and repeat
  84.  
  85.   If any bind at any point returns true then no more binds will be processed
  86.   and the event will be eaten and not passed to powder toy.
  87. ]]--
  88.  
  89. ------------------------------------------------
  90. -- LAYOUTS -------------------------------------
  91. ------------------------------------------------
  92. dkeylib.layouts.US = function(self, layout)
  93.     self:addprocessor(layout, "shiftdef")
  94.     self:addprocessor(layout, "shiftmap")
  95.     self:addprocessor(layout, "special")
  96.  
  97.     -- Shifted Numbers Map
  98.     layout.numbers = {")", "!", "@", "#", "$", "%", "^", "&", "*", "("}
  99.    
  100.     -- Shifted Symbols Map
  101.     layout.shift["-"] = "_"
  102.     layout.shift["="] = "+"
  103.     layout.shift["["] = "{"
  104.     layout.shift["]"] = "}"
  105.     layout.shift[";"] = ":"
  106.     layout.shift["'"] = "\""
  107.     layout.shift[","] = "<"
  108.     layout.shift["."] = ">"
  109.     layout.shift["/"] = "?"
  110.     layout.shift["\\"] = "|"
  111.    
  112.     -- Modifier key map
  113.     layout.modifiers = {
  114.         {  1, self.vkey.shift, self.vkey.shift_left},
  115.         {  2, self.vkey.shift, self.vkey.shift_right},
  116.         { 64, self.vkey.ctrl , self.vkey.ctrl_left},
  117.         {128, self.vkey.ctrl , self.vkey.ctrl_right},
  118.         {256, self.vkey.alt  , self.vkey.alt_left},
  119.         {512, self.vkey.alt  , self.vkey.alt_left},
  120.         {8192, self.vkey.capslock}
  121.     }
  122.    
  123.     layout.vkey[96] = self.vkey.console
  124.    
  125.     return layout
  126. end
  127. dkeylib.layouts.default = dkeylib.layouts.US
  128.  
  129. dkeylib.layouts.ISO = function(self, layout)
  130.     self:addprocessor(layout, "shiftdef")
  131.     self:addprocessor(layout, "shiftmap")
  132.     self:addprocessor(layout, "special")
  133.  
  134.     -- Shifted Numbers Map
  135.     layout.numbers = {")", "!", "@", "#", "$", "%", "^", "&", "*", "("}
  136.    
  137.     -- Shifted Symbols Map
  138.     layout.shift["-"] = "_"
  139.     layout.shift["="] = "+"
  140.     layout.shift["["] = "{"
  141.     layout.shift["]"] = "}"
  142.     layout.shift[";"] = ":"
  143.     layout.shift["'"] = "\""
  144.     layout.shift[","] = "<"
  145.     layout.shift["."] = ">"
  146.     layout.shift["/"] = "?"
  147.     layout.shift["\\"] = "|"
  148.    
  149.     -- Modifier key map
  150.     layout.modifiers = {
  151.         {  1, self.vkey.shift, self.vkey.shift_left},
  152.         {  2, self.vkey.shift, self.vkey.shift_right},
  153.         { 64, self.vkey.ctrl , self.vkey.ctrl_left},
  154.         {128, self.vkey.ctrl , self.vkey.ctrl_right},
  155.         {256, self.vkey.alt  , self.vkey.alt_left},
  156.         {512, self.vkey.alt  , self.vkey.alt_left},
  157.         {8192, self.vkey.caps_lock}
  158.     }
  159.    
  160.     layout.vkey[96] = self.vkey.console
  161.    
  162.     return layout
  163. end
  164.  
  165. ------------------------------------------------
  166. -- PROCESSORS ----------------------------------
  167. ------------------------------------------------
  168. dkeylib.processors.shiftdef = function(self, layout, key)
  169.     local m = key.modifier
  170.     local v = key.value
  171.    
  172.     local s = self:isvkeydown(self.vkey.shift)
  173.     local c = self:isvkeydown(self.vkey.capslock)
  174.    
  175.     -- Mappings for shifted keys
  176.     if s then
  177.         if v >= 48 and v <= 57 then
  178.             key.pstr = layout.numbers[v - 47]
  179.         end
  180.     end
  181.    
  182.     if s or c then
  183.         if s ~= c then
  184.             if v >= 97 and v <= 122 then
  185.                 key.pstr = string.char(v - 32)
  186.             end
  187.         end
  188.     end
  189. end
  190.  
  191. dkeylib.processors.special = function(self, layout, key)
  192.     if key.value >= 256 or key.value < 32 then
  193.         key.pstr = "[S]"
  194.     end
  195. end
  196.  
  197. dkeylib.processors.shiftmap = function(self, layout, key)
  198.     -- Shift map
  199.     local s = self:isvkeydown(self.vkey.shift)
  200.    
  201.     if s then
  202.         local temp = layout.shift[key.str]
  203.        
  204.         if temp ~= nil then
  205.             key.pstr = temp
  206.         end
  207.     end
  208. end
  209.  
  210. ------------------------------------------------
  211. -- [MAPPINGS] ----------------------------------
  212. ------------------------------------------------
  213. dkeylib.vkey = {
  214.     shift       = 1,
  215.     shift_left  = 2,
  216.     shift_right = 3,
  217.    
  218.     ctrl        = 4,
  219.     ctrl_left   = 5,
  220.     ctrl_right  = 6,
  221.    
  222.     alt         = 7,
  223.     alt_left    = 8,
  224.     alt_right   = 9,
  225.    
  226.     capslock    = 10,
  227.     shiftlock   = 11,
  228.     numlock     = 12,
  229. }
  230.  
  231. ------------------------------------------------
  232. -- [KEY] ---------------------------------------
  233. ------------------------------------------------
  234. dkeylib.key = {
  235.     value = 0,      -- Value of last key pressed
  236.     modifier = 0,   -- Modifier value of last key pressed
  237.     str = 0,        -- Key string
  238.     pstr = 0,       -- Processed key string ([S] for special key)
  239.     event = 0,      -- 1 = Pressed, 2 = Released, 3 = Held
  240.    
  241.     -- Used internally for repeating (don't use these if possible)
  242.     downstart = 0,  -- Time when key was pressed
  243.     down = 0,       -- 0 = Up, 1 = Down, 2 = Pressed
  244. }
  245.  
  246. ------------------------------------------------
  247. -- CORE FUNCTIONS ------------------------------
  248. ------------------------------------------------
  249. table.compare = function(a, b)
  250.     if #a ~= #b then
  251.         return false
  252.     end
  253.    
  254.     local ai, as, ab = pairs(a)
  255.     local bi, bs, bc = pairs(b)
  256.    
  257.     for i=1,#a do
  258.         ak, av = ai(as, ac)
  259.         bk, bv = bi(bs, bc)
  260.        
  261.         if ak ~= bk or av ~= bv then
  262.             return false
  263.         end
  264.     end
  265.    
  266.     return true
  267. end
  268.  
  269. dkeylib.isvkeydown = function(self, search)
  270.     if type(search) == "table" then
  271.         matched = 0
  272.         for i=1,#search do
  273.             if self.pressedvkeys[search[i]] == true then
  274.                 matched = matched + 1
  275.             end
  276.         end
  277.         return matched == #search
  278.     end
  279.    
  280.     return self.pressedvkeys[search] == true
  281. end
  282.  
  283. dkeylib.addprocessor = function(self, layout, processor)
  284.     -- Lookup processor
  285.     local p = self.processors[processor]
  286.    
  287.     if p == nil then
  288.         error("A processor by the name '" .. processor .. "' does not exist")
  289.         return
  290.     end
  291.    
  292.     table.insert(layout.process, p)
  293. end
  294.  
  295. dkeylib.newlayout = function(self)
  296.     local layout = {
  297.         process = {},   -- Functions to process input
  298.         shift = {},     -- Shifted symbols map (run before process)
  299.         modifiers = {}, -- Map of modifiers to their vkey counterparts
  300.         vkey = {},      -- Map of other keys to their vkey counterparts
  301.     }
  302.    
  303.     return layout
  304. end
  305.  
  306. -- set the layout to the specified layout
  307. dkeylib.setlayout = function(self, layout)
  308.     local l = dkeylib.layouts[layout]
  309.    
  310.     if l == nil then
  311.         -- Set the default layout and throw an error
  312.         dkeylib.layout = dkeylib.layouts.default(dkeylib, dkeylib:newlayout())
  313.         error("A keyboard layout with the name " .. tostring(layout) .. " does not exist")
  314.     end
  315.    
  316.     dkeylib.layout = l(dkeylib, dkeylib:newlayout())
  317. end
  318.  
  319. ------------------------------------------------
  320. -- BINDS ---------------------------------------
  321. ------------------------------------------------
  322. dkeylib.newbind = function(self, name, priority)
  323.     if priority == nil or type(priority) ~= "number" then
  324.         priority = 0
  325.     end
  326.    
  327.     if self:getbind(name) ~= nil then
  328.         error("A bind already exists with that name")
  329.     end
  330.  
  331.     local temp = {
  332.         enabled  = true,
  333.        
  334.         name     = name,
  335.         priority = priority,
  336.        
  337.         binds    = {},
  338.         handler  = nil,
  339.        
  340.         --
  341.         bind    = dkeylib.bind.bind,
  342.     }
  343.    
  344.     table.insert(self.allbinds, temp)
  345.     table.sort(self.allbinds, dkeylib.bind.sort)
  346.    
  347.     return temp
  348. end
  349.  
  350. dkeylib.getbind = function(self, name)
  351.     for i,v in pairs(self.allbinds) do
  352.         if v.name == name then
  353.             return v
  354.         end
  355.     end
  356.    
  357.     return nil
  358. end
  359.  
  360. dkeylib.bind.sort = function(a, b)
  361.     return a.priority > b.priority
  362. end
  363.  
  364. dkeylib.bind.bind = function(self, f, key, modifiers, userdata)
  365.     if type(f) ~= "function" then
  366.         error("f must be a function")
  367.     end
  368.  
  369.     if key == nil then
  370.         if self.handler ~= nil then
  371.             error("A handler has already been defined for the bind group " .. self.name)
  372.             return
  373.         end
  374.        
  375.         self.handler = { f = f, userdata = userdata }
  376.         return
  377.     end
  378.    
  379.     if type(key) == "string" then
  380.         if #key ~= 1 then
  381.             error("Bind target is longer than a single character '" .. key .. "'")
  382.         end
  383.        
  384.         key = string.byte(key)
  385.     end
  386.    
  387.     if type(key) == "number" then
  388.         if self.binds[key] == nil then
  389.             self.binds[key] = {}
  390.         end
  391.    
  392.         if modifiers == nil or modifiers == -1 then
  393.             if self.binds[key][-1] ~= nil then
  394.                 error("A handler for the bind '" .. tostring(key) .. "' has already been defined.")
  395.             end
  396.            
  397.             self.binds[key][-1] = { f = f, userdata = userdata }
  398.             return
  399.         end
  400.        
  401.         if type(modifiers) == "number" then
  402.             modifiers = {modifiers}
  403.         end
  404.        
  405.         for i,v in pairs(self.binds[key]) do
  406.             if table.compare(i, modifiers) then
  407.                 error("A handler for the bind '" .. tostring(key) .. "' has already been defined.")
  408.             end
  409.         end
  410.        
  411.         self.binds[key][modifiers] = { f = f, userdata = userdata }
  412.         return
  413.     end
  414.    
  415.     error("Unable to bind function, unknown key '" .. tostring(key) .. "' to bind group " .. self.name)
  416. end
  417.  
  418. function pobj(obj)
  419.     o = ""
  420.     for i,v in pairs(obj) do
  421.         o = o .. tostring(i) .. ": " .. tostring(v) .. "\n"
  422.     end
  423.     return o
  424. end
  425.  
  426. dkeylib.callbind = function(self, bind, key)
  427.     if bind.enabled ~= true then
  428.         return
  429.     end
  430.    
  431.     if bind.binds[key.value] == nil then
  432.         if bind.handler ~= nil then
  433.             return ecall(bind.handler.f, key, bind.handler.userdata)
  434.         end
  435.         return
  436.     end
  437.    
  438.     for i,v in pairs(bind.binds[key.value]) do
  439.         if self:isvkeydown(i) then
  440.             if ecall(v.f, key, v.userdata) == true then
  441.                 return true
  442.             end
  443.            
  444.             break
  445.         end
  446.     end
  447.    
  448.     local v = bind.binds[key.value][-1]
  449.    
  450.     if v ~= nil then
  451.         if ecall(v.f, key, v.userdata) == true then
  452.             return true
  453.         end
  454.     end
  455.  
  456.     if bind.handler ~= nil then
  457.         return ecall(bind.handler.f, key, bind.handler.userdata)
  458.     end
  459.    
  460.     return false
  461. end
  462.  
  463. ------------------------------------------------
  464. -- HOOKS & INITIALIZATION ----------------------
  465. ------------------------------------------------
  466.  
  467. -- Handle held keys
  468. dkeylib.hookStep = function()
  469.     local key = dkeylib.key
  470.    
  471.     if key.down == 1 then
  472.         if os.clock() - key.downstart > dkeylib.repeatDelay then
  473.             key.down = 2
  474.         end
  475.     end
  476.    
  477.     if key.down == 2 and (os.clock() - key.downstart) > dkeylib.repeatInterval then        
  478.         dkeylib.hookKey(key.str, key.value, key.modifier, 3)
  479.     end
  480. end
  481.  
  482. -- Main key processing function
  483. dkeylib.hookKey = function(keyString, value, modifier, event)
  484.     local key = dkeylib.key
  485.     local layout = dkeylib.layout
  486.    
  487.     key.downstart = os.clock()
  488.     key.event = event
  489.    
  490.     if event ~= 3 then
  491.         key.down = 2 - event
  492.     end
  493.    
  494.     -- Update modifier keys
  495.     if key.modifier ~= modifier then
  496.         dkeylib.pressedvkeys = {}
  497.        
  498.         if modifier ~= 0 then
  499.             for i=1,#layout.modifiers do
  500.                 m = layout.modifiers[i]
  501.                 f = m[1]
  502.                
  503.                 if modifier % (2*f) >= f then
  504.                     for ii=2,#m do
  505.                         if dkeylib.pressedvkeys[m[ii]] ~= true then
  506.                             dkeylib.pressedvkeys[m[ii]] = true
  507.                         end
  508.                     end
  509.                 end
  510.             end
  511.         end
  512.        
  513.         -- Force dkeylib to reprocess this key
  514.         key.value = 0
  515.         key.modifier = modifier
  516.     end
  517.    
  518.     -- Update current pressed key & Reaquire current binds
  519.     if key.value ~= value then
  520.         key.value = value
  521.         key.str = keyString
  522.         key.pstr = keyString
  523.        
  524.         -- Run current layout processors
  525.         for i=1,#layout.process do
  526.             local temp = layout.process[i]
  527.             if temp(dkeylib, layout, key) == true then
  528.                 break
  529.             end
  530.         end
  531.     end
  532.    
  533.     -- Run all binds
  534.     for k,bind in pairs(dkeylib.allbinds) do
  535.         if dkeylib:callbind(bind, key) == true then
  536.             return false
  537.         end
  538.     end
  539.    
  540.     return true
  541. end
  542.  
  543. dkeylib.load = function()
  544.     tpt.register_keypress(dkeylib.hookKey)
  545.     tpt.register_step(dkeylib.hookStep)
  546.     dkeylib:setlayout(dkeylib.layoutName)
  547.     tpt.log(string.format("Loaded dkeylib V%d.%d", dkeylib.version, dkeylib.versionMinor))
  548.     dkeylib.loaded = true
  549. end
  550.  
  551. dkeylib.unload = function()
  552.     tpt.unregister_step(dkeylib.hookStep)
  553.     tpt.unregister_keypress(dkeylib.hookKey)
  554.     dkeylib.loaded = false
  555. end
  556.  
  557. ------------------------ DKEYLIB TEST CODE ------------------------
  558. dkeylib.load()
  559.  
  560. -- Call cmd & automatically call error (w/ error message) upon error
  561. function ecall(cmd, ...)
  562.     _, result = pcall(cmd, unpack(arg))
  563.  
  564.     if _ == false then
  565.         error(result)
  566.     end
  567.  
  568.     return result, _
  569. end
  570.  
  571. local _e = "No key has been pressed - Extra: None"
  572. local function draw()
  573.     tpt.drawtext(0, 10, "DKEYLIB TESTMODE Version " .. dkeylib.version .. "." .. dkeylib.versionMinor)
  574.     tpt.drawtext(0, 20, "Please test the following keys. a, f, shift+r, shift+ctrl+r")
  575.     tpt.drawtext(0, 30, "Extra should be 12345 for a, override for f, shift+r for shift+r and shift+ctrl+r for shift+ctrl+r")
  576.     tpt.drawtext(0, 40, "Try pressing and holding a key, E should change to 3")
  577.    
  578.     tpt.drawtext(0, 60, "Key Pressed: " .. _e)
  579.     tpt.hud(0)
  580. end
  581. tpt.register_step(draw)
  582.  
  583. local function test(key, userdata)
  584.     _e = string.format("S: %s E: %d V: %d - Extra: %s", key.pstr, key.event, key.value, tostring(userdata))
  585.     return true
  586. end
  587.  
  588. -- You do not need to worry about userdata
  589. local function testany(key)
  590.     _e = string.format("S: %s E: %d V: %d - Extra: None", key.pstr, key.event, key.value)
  591.     return true
  592. end
  593.  
  594. ----- Overriding
  595. -- override bind has a higher priority than test so its binds will get called first
  596. local b2 = dkeylib:newbind("override bind", 1000)
  597. b2:bind(test, 'f', -1, "override")
  598.  
  599. local b = dkeylib:newbind("test bind") -- Create a new bind with default priority, called test
  600.  
  601. -- Bind to any key press of 'a', userdata can be anything
  602. b:bind(test, 'a', -1, 12345)
  603.  
  604. -- Bind to shift+ctrl+r
  605. b:bind(test, 'r', {dkeylib.vkey.shift, dkeylib.vkey.ctrl}, "shift+ctrl+r" )
  606.  
  607. -- Bind to only shift+r
  608. b:bind(test, 'r', dkeylib.vkey.shift, "shift+r" )
  609.  
  610. -- Bind to every other key press
  611. b:bind(testany)
  612.  
  613. -- If you wanted to pass userdata to testany
  614. -- b:bind(testany, nil, nil, "User data")
Advertisement
Add Comment
Please, Sign In to add comment