input.lua (8748B)
1 local base = string.match(..., "(.-)[^%.]+$") 2 local bf = require(base.."helper.bitfield") 3 local decls = require(base.."ev_api.decls") 4 local errno = require(base.."helper.errno") 5 local eh = require(base.."helper.enum") 6 local ffi = require("ffi") 7 local mth = require(base.."helper.mt") 8 local pio = require(base.."helper.posix_io") 9 local ioh = require(base.."helper.ioctl_helper") 10 11 local bf_new_for_ioctl = bf.new_for_ioctl 12 local ffi_cast, ffi_errno = ffi.cast, ffi.errno 13 local enums, ioctls = decls.enums, decls.ioctls 14 local enum_to_int, enum_to_str = eh.to_int, eh.to_str 15 local e_assert, e_error = errno.assert, errno.error 16 17 -- ev_api modules 18 local absinfo = require(base.."ev_api.absinfo").new 19 local event = require(base.."ev_api.event") 20 local ff_effect = require(base.."ev_api.ff_effect").new 21 local id = require(base.."ev_api.id").new 22 local rs_new = require(base.."ev_api.repeat_settings").new 23 24 local setmetatable = setmetatable 25 26 local mt, index = {}, {} 27 28 -------------------------------------------------------------------------------- 29 -- IOCTL wrappers 30 31 index.get_driver_version = ioh.check_1(ioctls.get_version) 32 index.get_device_id = ioh.check_1_reswrap(ioctls.get_id, id) 33 34 -- repeat settings. need EV.REP in bits 35 local ioctl_get_rep = ioctls.get_rep 36 function index:get_repeat() 37 ffi_errno(0) 38 local res, delay, period = ioctl_get_rep(self.fd) 39 e_assert("ioctl", res == 0, 2) 40 return rs_new(delay, period) 41 end 42 index.get_rep = index.get_repeat -- repeat is a keyword in lua 43 44 local ioctl_set_rep = ioctls.set_rep 45 function index:set_repeat(...) 46 local r = rs_new(...) 47 ffi_errno(0) 48 e_assert("ioctl", ioctl_set_rep(self.fd, r.raw.delay, r.raw.period) == 0, 2) 49 end 50 index.set_rep = index.set_repeat 51 52 -- keycode 53 local KEY = enums.KEY 54 local ioctl_get_keycode = ioctls.get_keycode 55 local function get_keycode(proxy, scancode) 56 ffi_errno(0) 57 local res, kc = ioctl_get_keycode(proxy._instance.fd, scancode, 0) 58 e_assert("ioctl", res == 0, 2) 59 return enum_to_str(KEY, kc) 60 end 61 local ioctl_set_keycode = ioctls.set_keycode 62 local function set_keycode(proxy, scancode, keycode) 63 keycode = enum_to_int(KEY, keycode) 64 ffi_errno(0) 65 local res = ioctl_set_keycode(proxy._instance.fd, scancode, keycode) 66 e_assert("ioctl", res == 0, 2) 67 end 68 local keycode_mt = { __index = get_keycode, __newindex = set_keycode } 69 70 -- TODO: keycode V2 71 72 -- these can result in ENOENT when the specified property is not supported 73 index.get_name = ioh.string_prop(ioctls.get_name) 74 index.get_phys = ioh.string_prop(ioctls.get_phys) 75 index.get_uniq = ioh.string_prop(ioctls.get_uniq) 76 77 local function bitfield_prop(ioctl, enum, len) 78 len = len or enum.MAX + 1 79 return function(self) 80 local bf, buf, bytes = bf_new_for_ioctl(enum, len) 81 ffi_errno(0) 82 local res = ioctl(self.fd, buf, bytes) 83 e_assert("ioctl", res > 0 and res <= bytes, 2) 84 return bf 85 end 86 end 87 index.get_prop = bitfield_prop(ioctls.get_prop, enums.INPUT_PROP) 88 -- consistent naming with other bitfield getters 89 index.get_prop_bits = index.get_prop 90 91 -- mt slots 92 -- whoever came up with this API should be impaled on stick with AIDS. 93 -- You pass in the size of the struct in bytes, then the code will fill in the 94 -- first few values, then return 0. How many values did it fill? Looking at the 95 -- source, you'll neet to get the absinfo for ABS_MT_SLOT, take the maximum and 96 -- add one. Of course, whoever wrote this shit would surely have died suddenly 97 -- if his cockteaser wouldn't be so fucking lazy and would have returned the 98 -- fucking count already used in that dumbass function you nigger cocksucker 99 -- retard. Fuck you. 100 ffi.cdef[[ 101 struct input_mt_request_layout { 102 __u32 code; 103 __s32 values[?]; 104 }; 105 ]] 106 local mt_req_ct = ffi.typeof("struct input_mt_request_layout") 107 local ioctl_get_mtslots = ioctls.get_mtslots 108 local ABS = enums.ABS 109 function index:get_mt_slots(code, num) 110 num = num or self:get_mt_slot_count() 111 local req = mt_req_ct(num) 112 req.code = enum_to_int(ABS, code) 113 ffi_errno(0) 114 local res = ioctl_get_mtslots(self.fd, req) 115 e_assert("ioctl", res == 0, 2) 116 local tbl = {} 117 for i=1,num do tbl[i] = req.values[i-1] end 118 return tbl 119 end 120 121 -- state 122 index.get_key_state = bitfield_prop(ioctls.get_key, KEY, KEY.KEY_MAX+1) 123 index.get_led_state = bitfield_prop(ioctls.get_led, enums.LED) 124 index.get_snd_state = bitfield_prop(ioctls.get_snd, enums.SND) 125 index.get_sw_state = bitfield_prop(ioctls.get_sw, enums.SW) 126 127 local ioctl_get_bit = ioctls.get_bit 128 local inpmask = ffi.typeof("struct input_mask") 129 local ct_u64 = ffi.typeof("__u64") 130 local ioctl_get_mask, ioctl_set_mask = ioctls.get_mask, ioctls.set_mask 131 for _,x in ipairs{"EV", "KEY", "REL", "ABS", "MSC", "LED", "SND", "FF", "SW"} do 132 local xl = x:lower() 133 local enum = assert(enums[x]) 134 -- 0 maps to EV_SYN, but you use that to get EV bits, because fuck logic 135 local id = assert(x == "EV" and 0 or enums.EV[x], x) 136 local len = (enum.MAX or enum.KEY_MAX) + 1 137 index["get_"..xl.."_bits"] = function(self) 138 local bf, buf, bytes = bf_new_for_ioctl(enum, len) 139 ffi_errno(0) 140 local res = ioctl_get_bit(self.fd, id, buf, bytes) 141 e_assert("ioctl", res > 0 and res <= bytes, 2) 142 return bf 143 end 144 145 -- also event mask here because it uses the same set of enums 146 index["get_"..xl.."_mask"] = function(self) 147 local bf, buf, bytes = bf_new_for_ioctl(enum, len) 148 local mask = inpmask(id, bytes, ffi_cast(ct_u64, buf)) 149 ffi_errno(0) 150 e_assert("ioctl", ioctl_get_mask(self.fd, mask) == 0, 2) 151 return bf 152 end 153 154 index["set_"..xl.."_mask"] = function(self, bf) 155 local mask = inpmask(id, bf.bytes, ffi_cast(ct_u64, bf._buf)) 156 ffi_errno(0) 157 e_assert("ioctl", ioctl_set_mask(self.fd, mask) == 0, 2) 158 end 159 end 160 161 -- absinfo 162 local ioctl_get_abs = ioctls.get_abs 163 local function get_absinfo(proxy, abs) 164 ffi_errno(0) 165 local res, info = ioctl_get_abs(proxy._instance.fd, enum_to_int(ABS, abs)) 166 e_assert("ioctl", res == 0, 2) 167 return absinfo(info) 168 end 169 170 local ioctl_set_abs = ioctls.set_abs 171 local function set_absinfo(proxy, abs, ...) 172 local info = absinfo(...) 173 ffi_errno(0) 174 local res = ioctl_set_abs(proxy._instance.fd, enum_to_int(ABS, abs), info.raw) 175 e_assert("ioctl", res == 0, 2) 176 end 177 local absinfo_mt = { __index = get_absinfo, __newindex = set_absinfo } 178 179 local ABS_MT_SLOT = ABS.MT_SLOT 180 function index:get_mt_slot_count() 181 if not self.abs_bits["MT_SLOT"] then return 0 end 182 local res, info = ioctl_get_abs(self.fd, ABS_MT_SLOT) 183 e_assert("ioctl", res == 0, 2) 184 return info.maximum + 1 185 end 186 187 -- FF 188 local ioctl_set_ff = ioctls.set_ff 189 function index:add_ff(...) 190 local ff = ff_effect(...) 191 ffi_errno(0) 192 e_assert("ioctl", ioctl_set_ff(self.fd, ff.raw) == 0, 2) 193 return ff.id 194 end 195 196 index.remove_ff = ioh.check_0(ioctls.rm_ff) 197 index.get_ff_count = ioh.check_1(ioctls.get_effects) 198 199 -- misc 200 local ioctl_grab = ioctls.grab 201 local function set_grab(self, grab) 202 ffi_errno(0) 203 e_assert("ioctl", ioctl_grab(self.fd, grab and 1 or 0) == 0, 2) 204 end 205 index.set_grab = set_grab 206 function index:grab() set_grab(self, true) end 207 function index:ungrab() set_grab(self, false) end 208 209 local ioctl_revoke = ioctls.revoke 210 function index:revoke() 211 ffi_errno(0) 212 -- int parameter must be 0, otherwise kernel throws EINVAL 213 e_assert("ioctl", ioctl_revoke(self.fd, 0) == 0, 2) 214 end 215 216 local CLOCK = eh.make_enum{ {"REALTIME", 0}, {"MONOTONIC", 1}, {"BOOTTIME", 7} } 217 index.CLOCK = CLOCK 218 local ioctl_set_clockid = ioctls.set_clockid 219 function index:set_clockid(id) 220 ffi_errno(0) 221 e_assert("ioctl", ioctl_set_clockid(self.fd, CLOCK[id] or id) == 0, 2) 222 end 223 224 -------------------------------------------------------------------------------- 225 -- MISC 226 227 function index:close() 228 self.io:close() 229 end 230 231 local ev_size = event.raw_struct_size 232 function index:read() 233 return event.new(self.io:read(ev_size)) 234 end 235 236 function index:write(...) 237 local ev = event(...) 238 self.io:write(ev.raw, ev_size) 239 end 240 241 function index:play_ff(id, count) 242 self.io:write(event{type="FF", code=id, value=count or 1}.raw, ev_size) 243 end 244 245 local GAIN = enums.FF.GAIN 246 function index:set_ff_gain(gain) 247 if gain < 0 or gain > 0xffff then error("Invalid gain value "..gain, 2) end 248 self.io:write(event{type="FF", code=GAIN, value=gain}.raw, ev_size) 249 end 250 251 local AUTOCENTER = enums.FF.AUTOCENTER 252 function index:set_ff_autocenter(level) 253 if level < 0 or level > 0xffff then error("Invalid level value "..level, 2) end 254 self.io:write(event{type="FF", code=AUTOCENTER, value=level}.raw, ev_size) 255 end 256 257 258 local function new(fname) 259 local io = pio(fname) 260 local inst = {io=io, fd=io.fd} 261 inst.keycode = setmetatable({_instance=inst}, keycode_mt) 262 inst.absinfo = setmetatable({_instance=inst}, absinfo_mt) 263 return setmetatable(inst, mt) 264 end 265 index.new = new 266 267 mth.add_index_methods(mt, index) 268 return setmetatable(index, { __call = function(_, ...) return new(...) end })