uinput.lua (5435B)
1 local base = string.match(..., "(.-)[^%.]+$") 2 local eh = require(base.."helper.enum") 3 local errno = require(base.."helper.errno") 4 local ffi = require("ffi") 5 local decls = require(base.."ev_api.decls") 6 local ioh = require(base.."helper.ioctl_helper") 7 local mth = require(base.."helper.mt") 8 local pio = require(base.."helper.posix_io") 9 10 local ffi_errno = ffi.errno 11 local enum_to_int = eh.to_int 12 local enums, ioctls = decls.enums, decls.ioctls 13 local e_assert = errno.assert 14 15 -- ev_api modules 16 local absinfo = require(base.."ev_api.absinfo").new 17 local event = require(base.."ev_api.event") 18 local ff_erase = require(base.."ev_api.ff_erase").new 19 local ff_upload = require(base.."ev_api.ff_upload").new 20 local setup = require(base.."ev_api.setup").new 21 22 local select, type = select, type 23 local getmetatable, setmetatable = getmetatable, setmetatable 24 25 local mt, index = {}, {} 26 27 -------------------------------------------------------------------------------- 28 -- IOCTL wrappers 29 30 index.create = ioh.check_0(ioctls.ui_dev_create) 31 index.destroy = ioh.check_0(ioctls.ui_dev_destroy) 32 33 -- general setup 34 index.setup = ioh.check_0_argwrap(ioctls.ui_dev_setup, setup) 35 36 local ioctl_abs_setup = ioctls.ui_abs_setup 37 local ct = ffi.typeof("struct uinput_abs_setup") 38 local ABS = enums.ABS 39 function index:abs_setup(abs, ...) 40 self:set_evbit("ABS") 41 42 local info = absinfo(...) 43 local arg = ct(enum_to_int(ABS, abs), info.raw) 44 ffi_errno(0) 45 e_assert("ioctl", ioctl_abs_setup(self.fd, arg) == 0, 2) 46 end 47 48 -- bits setup 49 for _,x in ipairs{"EV", "KEY", "REL", "ABS", "MSC", "LED", "SND", "FF", "SW", "PROP"} do 50 local ioctl = ioctls["ui_set_"..x:lower().."bit"] 51 local enum = assert(x == "PROP" and enums.INPUT_PROP or enums[x], x) 52 index["set_"..x:lower().."bit"] = function(self, bit) 53 bit = enum_to_int(enum, bit) 54 ffi_errno(0) 55 e_assert("ioctl", ioctl(self.fd, bit) == 0, 2) 56 end 57 end 58 59 -- phys 60 index.set_phys = ioh.check_0(ioctls.ui_set_phys) 61 62 -- FF 63 local function begin_func(ioctl, wrap) 64 return function(self, ...) 65 local arg 66 if select('#', ...) == 1 then 67 local x = ... 68 local t = type(x) 69 if t == "number" then 70 arg = wrap{request_id=x} 71 -- TODO something better 72 elseif t == "table" and x.struct_name == "input_event" then 73 arg = wrap{request_id=x.value} 74 end 75 end 76 if not arg then arg = wrap(...) end 77 78 ffi_errno(0) 79 e_assert("ioctl", ioctl(self.fd, arg.raw) == 0, 2) 80 return arg 81 end 82 end 83 84 index.begin_ff_upload = begin_func(ioctls.ui_begin_ff_upload, ff_upload) 85 index.end_ff_upload = ioh.check_0_argwrap(ioctls.ui_end_ff_upload, ff_upload) 86 87 index.begin_ff_erase = begin_func(ioctls.ui_begin_ff_erase, ff_erase) 88 index.end_ff_erase = ioh.check_0_argwrap(ioctls.ui_end_ff_erase, ff_erase) 89 90 -- misc 91 index.get_sysname = ioh.string_prop(ioctls.ui_get_sysname) 92 index.get_version = ioh.check_1(ioctls.ui_get_version) 93 94 -------------------------------------------------------------------------------- 95 -- helpers 96 97 function index:copy_caps(inp) 98 local absinfo = inp.absinfo 99 for i in inp.abs_bits:i_members() do 100 self:abs_setup(i, absinfo[i]) 101 end 102 103 -- skip abs, abs_setup did it automatically 104 for _,x in ipairs{"ev", "key", "rel", "msc", "led", "snd", "ff", "sw", "prop"} do 105 local setter = self["set_"..x.."bit"] 106 for i in inp[x.."_bits"]:i_members() do 107 setter(self, i) 108 end 109 end 110 end 111 112 -- ???: rep, scancode map 113 function index:add_keyboard_caps(skip_leds) 114 self:set_evbit("KEY") 115 for k,v in pairs(enums.KEY) do 116 if type(k) == "number" and v:sub(1, 4) == "KEY_" then 117 self:set_keybit(k) 118 end 119 end 120 121 if not skip_leds then 122 self:set_evbit("LED") 123 self:set_ledbit("NUML") 124 self:set_ledbit("CAPSL") 125 self:set_ledbit("SCROLLL") 126 end 127 end 128 129 function index:gen_ff_forwarder(inp) 130 local last_map = {} 131 local function write_if(ev) 132 local t = ev.type 133 local m = last_map[t] 134 if not m then m = {} last_map[t] = m end 135 136 local code = ev.code 137 local val = ev.value 138 if m[code] == val then return end 139 140 inp:write(ev) 141 m[code] = val 142 end 143 144 local ff_map = {} 145 return function() 146 local ev = self:read() 147 if ev.type == "UINPUT" then 148 local code = ev.code 149 if code == "FF_UPLOAD" then 150 local x = self:begin_ff_upload(ev) 151 -- TODO error handling 152 local old_id = x.effect.id 153 x.effect.id = ff_map[old_id] or -1 154 inp:add_ff(x.effect) 155 ff_map[old_id] = x.effect.id 156 x.retval = 0 157 self:end_ff_upload(x) 158 elseif code == "FF_ERASE" then 159 local x = self:begin_ff_erase(ev) 160 inp:remove_ff(ff_map[x.effect_id]) 161 ff_map[x.effect_id] = nil 162 x.retval = 0 163 self:end_ff_erase(x) 164 end 165 elseif ev.type == "FF" then 166 local m = ff_map[ev.code] 167 if m then ev.code = m end 168 write_if(ev) 169 else 170 write_if(ev) 171 end 172 end 173 end 174 175 -------------------------------------------------------------------------------- 176 -- misc 177 178 function index:close() 179 self.io:close() 180 end 181 182 local ev_size = event.raw_struct_size 183 function index:read() 184 return event.new(self.io:read(ev_size)) 185 end 186 187 function index:write(...) 188 local ev = event(...) 189 self.io:write(ev.raw, ev_size) 190 end 191 192 local function new(fname) 193 local io = pio(fname or "/dev/uinput") 194 return setmetatable({io=io, fd=io.fd}, mt) 195 end 196 index.new = new 197 198 mth.add_index_methods(mt, index) 199 return setmetatable(index, { __call = function(_, ...) return new(...) end })