Skip to content

Commit 8bcb5b7

Browse files
committed
refactor(uinput): flatten lazy metadata fields
1 parent 9e1a625 commit 8bcb5b7

5 files changed

Lines changed: 83 additions & 86 deletions

File tree

src/evdev/uinput.lua

Lines changed: 35 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,29 +1,48 @@
1-
---@diagnostic disable: inject-field
2-
31
local evdev = require "evdev"
42

53
local ecodes = evdev.ecodes
64
local util = evdev._util
75

86
local create_uinput = evdev._core.create_uinput
7+
local find_device = evdev.devices.find
98
local tbl_copy = util.tbl_copy
109
local tbl_keys = util.tbl_keys
10+
local tbl_update = util.tbl_update
1111
local validate = util.validate
1212
local fmt = string.format
1313

1414
---@type evdev.UInput
15+
---@diagnostic disable-next-line: missing-fields
1516
local UInput = {}
16-
UInput.__index = UInput
1717

1818
---@type fun(dev:evdev.UInput, fname:string, ...):...
1919
local function call_uinput(ui, fname, ...)
20-
local core = ui._core
20+
local core = rawget(ui, "_core")
2121
if not core then
2222
return nil, "uinput device is closed"
2323
end
2424
return core[fname](core, ...)
2525
end
2626

27+
function UInput:__index(k)
28+
local v = rawget(UInput, k)
29+
if v then
30+
return v
31+
end
32+
33+
if not rawget(self, "_metadata") then
34+
local md, err = call_uinput(self, "info")
35+
if not md then
36+
error(err, 3)
37+
end
38+
39+
tbl_update(self, find_device(md.path))
40+
self._metadata = md
41+
end
42+
43+
return rawget(self, k)
44+
end
45+
2746
local function is_metacode(name)
2847
return name:match("_MAX$")
2948
or name:match("_CNT$")
@@ -139,8 +158,9 @@ local function normalize(spec)
139158
end
140159

141160
function UInput:close()
142-
if self._core then
143-
local ok, err = self._core:close()
161+
local core = rawget(self, "_core")
162+
if core then
163+
local ok, err = core:close()
144164
if not ok then
145165
return nil, err
146166
end
@@ -156,11 +176,14 @@ function UInput:emit(type, code, value)
156176
return call_uinput(self, "emit", type, code, value)
157177
end
158178

159-
-- stylua: ignore start
160-
function UInput:is_open() return self._core ~= nil and self._core:is_open() end
161-
function UInput:sync() return call_uinput(self, "sync") end
162-
function UInput:info() return call_uinput(self, "info") end
163-
-- stylua: ignore end
179+
function UInput:is_open()
180+
local core = rawget(self, "_core")
181+
return core ~= nil and core:is_open()
182+
end
183+
184+
function UInput:sync()
185+
return call_uinput(self, "sync")
186+
end
164187

165188
---@type evdev.uinput
166189
local M = {}
@@ -175,6 +198,7 @@ end
175198

176199
---@diagnostic disable-next-line: undefined-global
177200
if _TEST then
201+
---@diagnostic disable-next-line: inject-field
178202
M._normalize = normalize
179203
end
180204

tests/device.test.lua

Lines changed: 32 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -11,20 +11,15 @@ local sleep = system.sleep
1111
local fmt = string.format
1212

1313
describe("evdev.device", function()
14-
local mouse, mouse_path
15-
local kb, kb_path
14+
local mouse, kb
1615

1716
setup(function()
1817
kb = assert(UInput({ keys = { ecodes.KEY_ENTER, ecodes.KEY_F24, ecodes.KEY_F23 } }))
1918
mouse = assert(UInput({
2019
keys = { ecodes.BTN_LEFT, ecodes.BTN_RIGHT, ecodes.BTN_MIDDLE },
2120
rels = { ecodes.REL_X, ecodes.REL_Y, ecodes.REL_WHEEL },
2221
}))
23-
2422
sleep(0.1)
25-
26-
mouse_path = assert(mouse:info()).path
27-
kb_path = assert(kb:info()).path
2823
end)
2924

3025
teardown(function()
@@ -38,13 +33,13 @@ describe("evdev.device", function()
3833

3934
describe("open()", function()
4035
it("opens a device by path", function()
41-
local dev = assert(Device(kb_path))
36+
local dev = assert(Device(kb.path))
4237
assert.True(dev:is_open())
4338
assert.True(dev:close())
4439
end)
4540

4641
it("returns true for device instances", function()
47-
local dev = assert(Device(kb_path))
42+
local dev = assert(Device(kb.path))
4843
assert.True(evdev.device.is_device(dev))
4944
assert.False(evdev.device.is_device({}))
5045
assert.False(evdev.device.is_device(false))
@@ -66,13 +61,13 @@ describe("evdev.device", function()
6661

6762
describe("close()", function()
6863
it("closes the device cleanly", function()
69-
local dev = Device(kb_path)
64+
local dev = Device(kb.path)
7065
assert.True(dev:close())
7166
assert.False(dev:is_open())
7267
end)
7368

7469
it("returns true when called multiple times", function()
75-
local dev = Device(kb_path)
70+
local dev = Device(kb.path)
7671

7772
assert.True(dev:is_open())
7873
assert.True(dev:close())
@@ -87,14 +82,14 @@ describe("evdev.device", function()
8782

8883
describe("metadata fields", function()
8984
it("loads metadata fields", function()
90-
local dev = Device(kb_path)
91-
assert.Equal(kb_path, dev.path)
85+
local dev = Device(kb.path)
86+
assert.Equal(kb.path, dev.path)
9287
assert.String(dev.name)
9388
assert.True(dev:close())
9489
end)
9590

9691
it("stays cached after close", function()
97-
local dev = Device(kb_path)
92+
local dev = Device(kb.path)
9893
local path = dev.path
9994
local name = dev.name
10095
dev:close()
@@ -106,23 +101,23 @@ describe("evdev.device", function()
106101

107102
describe("fd()", function()
108103
it("returns the file descriptor", function()
109-
local dev = Device(mouse_path)
104+
local dev = Device(mouse.path)
110105
local fd = dev:fd()
111106
assert.Number(fd)
112107
assert.True(fd >= 0)
113108
assert.True(dev:close())
114109
end)
115110

116111
it("returns nil after close", function()
117-
local dev = Device(mouse_path)
112+
local dev = Device(mouse.path)
118113
assert.True(dev:close())
119114
assert.Nil(dev:fd())
120115
end)
121116
end)
122117

123118
describe("get_repeat()", function()
124119
it("returns repeat settings for repeat-capable devices", function()
125-
local dev = Device(kb_path)
120+
local dev = Device(kb.path)
126121
local delay, period, err = dev:get_repeat()
127122
assert.Number(delay)
128123
assert.Number(period)
@@ -131,18 +126,18 @@ describe("evdev.device", function()
131126
end)
132127

133128
it("returns an unsupported error for non-repeat devices", function()
134-
local dev = Device(mouse_path)
129+
local dev = Device(mouse.path)
135130
local delay, period, err = dev:get_repeat()
136131
assert.Nil(delay)
137132
assert.Nil(period)
138-
assert.Equal(fmt("get repeat %s: device does not support repeat settings", mouse_path), err)
133+
assert.Equal(fmt("get repeat %s: device does not support repeat settings", mouse.path), err)
139134
assert.True(dev:close())
140135
end)
141136
end)
142137

143138
describe("set_repeat()", function()
144139
it("updates repeat settings for repeat-capable devices", function()
145-
local dev = Device(kb_path)
140+
local dev = Device(kb.path)
146141
local delay, period, err = dev:get_repeat()
147142

148143
assert.Number(delay)
@@ -157,61 +152,61 @@ describe("evdev.device", function()
157152
end)
158153

159154
it("returns an unsupported error for non-repeat devices", function()
160-
local dev = Device(mouse_path)
155+
local dev = Device(mouse.path)
161156
local ok, err = dev:set_repeat(300, 40)
162157
assert.Nil(ok)
163-
assert.Equal(fmt("set repeat %s: device does not support repeat settings", mouse_path), err)
158+
assert.Equal(fmt("set repeat %s: device does not support repeat settings", mouse.path), err)
164159
assert.True(dev:close())
165160
end)
166161
end)
167162

168163
describe("grab()", function()
169164
it("grabs the device", function()
170-
local dev = Device(kb_path)
165+
local dev = Device(kb.path)
171166
assert.True(dev:grab())
172167
assert.True(dev:close())
173168
end)
174169

175170
it("errors when the device is already grabbed", function()
176-
local dev = Device(kb_path)
171+
local dev = Device(kb.path)
177172
assert.True(dev:grab())
178173
dev:grab()
179174

180175
local ok, err = dev:grab()
181176
assert.Nil(ok)
182-
assert.Equal(fmt("grab %s: device is already grabbed", kb_path), err)
177+
assert.Equal(fmt("grab %s: device is already grabbed", kb.path), err)
183178
assert.True(dev:close())
184179
end)
185180
end)
186181

187182
describe("ungrab() ", function()
188183
it("releases the device grab", function()
189-
local dev = Device(kb_path)
184+
local dev = Device(kb.path)
190185
assert.True(dev:grab())
191186
assert.True(dev:ungrab())
192187
assert.True(dev:close())
193188
end)
194189

195190
it("errors when the device is not grabbed", function()
196-
local dev = Device(kb_path)
191+
local dev = Device(kb.path)
197192
local ok, err = dev:ungrab()
198193
assert.Nil(ok)
199-
assert.Equal(fmt("ungrab %s: device is not grabbed", kb_path), err)
194+
assert.Equal(fmt("ungrab %s: device is not grabbed", kb.path), err)
200195
assert.True(dev:close())
201196
end)
202197
end)
203198

204199
describe("poll()", function()
205200
it("returns true when input is ready", function()
206-
local dev = Device(kb_path)
201+
local dev = Device(kb.path)
207202
assert.True(kb:emit(ecodes.EV_KEY, ecodes.KEY_F24, 1))
208203
assert.True(kb:sync())
209204
assert.True(dev:poll())
210205
assert.True(dev:close())
211206
end)
212207

213208
it("returns a closed-device error after close", function()
214-
local dev = Device(kb_path)
209+
local dev = Device(kb.path)
215210
assert.True(dev:close())
216211

217212
local ready, err = dev:poll()
@@ -222,7 +217,7 @@ describe("evdev.device", function()
222217

223218
describe("flush()", function()
224219
it("drains queued events", function()
225-
local dev = Device(kb_path)
220+
local dev = Device(kb.path)
226221

227222
assert.True(kb:emit(ecodes.EV_KEY, ecodes.KEY_F24, 1))
228223
assert.True(kb:sync())
@@ -242,7 +237,7 @@ describe("evdev.device", function()
242237
end)
243238

244239
it("returns a closed-device error after close", function()
245-
local dev = Device(kb_path)
240+
local dev = Device(kb.path)
246241
assert.True(dev:close())
247242

248243
local count, err = dev:flush()
@@ -256,7 +251,7 @@ describe("evdev.device", function()
256251
local ui = assert(UInput({ keys = { ecodes.KEY_F24 } }))
257252
sleep(0.1)
258253

259-
local path = assert(ui:info()).path
254+
local path = ui.path
260255
local dev = assert(Device(path))
261256

262257
assert.True(ui:emit(ecodes.EV_KEY, ecodes.KEY_F24, 1))
@@ -276,15 +271,15 @@ describe("evdev.device", function()
276271
end)
277272

278273
it("returns nil when no event is queued", function()
279-
local dev = Device(kb_path)
274+
local dev = Device(kb.path)
280275
local event, err = dev:read()
281276
assert.Nil(event)
282277
assert.Nil(err)
283278
assert.True(dev:close())
284279
end)
285280

286281
it("returns a closed-device error after close", function()
287-
local dev = Device(kb_path)
282+
local dev = Device(kb.path)
288283
assert.True(dev:close())
289284

290285
local event, err = dev:read()
@@ -309,7 +304,7 @@ describe("evdev.device", function()
309304
local ui = assert(UInput({ keys = { ecodes.KEY_F24 } }))
310305
sleep(0.1)
311306

312-
local path = assert(ui:info()).path
307+
local path = ui.path
313308
local dev = assert(Device(path))
314309

315310
assert.True(ui:emit(ecodes.EV_KEY, ecodes.KEY_F24, 1))
@@ -330,7 +325,7 @@ describe("evdev.device", function()
330325
local ui = assert(UInput({ keys = { ecodes.KEY_F24, ecodes.KEY_F23 } }))
331326
sleep(0.1)
332327

333-
local dev = assert(Device(assert(ui:info()).path))
328+
local dev = assert(Device(ui.path))
334329

335330
assert.True(ui:emit(ecodes.EV_KEY, ecodes.KEY_F24, 1))
336331
assert.True(ui:sync())
@@ -353,7 +348,7 @@ describe("evdev.device", function()
353348
end)
354349

355350
it("raises a closed-device error after close", function()
356-
local dev = Device(kb_path)
351+
local dev = Device(kb.path)
357352
assert.True(dev:close())
358353
assert.Error(function()
359354
dev:events()()

0 commit comments

Comments
 (0)