Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions cl-evdev.asd
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
:depends-on (#:binary-types
#:alexandria
#:local-time
#:trivial-features
#:cl-event-handler)
:components ((:file "package")
(:file "evdev")))
28 changes: 23 additions & 5 deletions evdev.lisp
Original file line number Diff line number Diff line change
Expand Up @@ -175,11 +175,8 @@ linux/include/uapi/linux/input.h.")
:test #'equal
:documentation "Relative motion types.")

(cond ((member (machine-type) '("X86" "armv7l") :test #'equal)
(define-unsigned unsigned-long-int 4))
((member (machine-type) '("X86-64" "x86_64") :test #'equal)
(define-unsigned unsigned-long-int 8))
(t 4))
#+32-bit(define-unsigned unsigned-long-int 4)
#+64-bit(define-unsigned unsigned-long-int 8)
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This has always stuck in my craw, and while using these flags seem to work okay, I worry it's the wrong approach.

The more I think about it, the more I think the host CL compiler is the wrong place to put this: it's possible this library could be running in a 32-bit compiler with a 64-bit host kernel, which means these values are entirely wrong for the evdev interface.

We really need a way to identify what the host kernel's word size is, rather than the host compiler's architecture.


(define-unsigned unsigned-short 2)
(define-unsigned unsigned-int 4)
Expand Down Expand Up @@ -346,3 +343,24 @@ condition is signaled."
for ,event-var = (read-event ,stream)
while ,event-var
do (progn ,@body)))))

(defmacro with-evdev-devices ((event-var &rest device-paths)
&body body)
"Opens DEVICE-PATHS for reading, combine individual stream events into
EVENT-VAR and calls BODY for each event passed in. DEVICE-PATHS must
exist, otherwise an error condition is signaled."
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's also worth noting here that the event orders may be out of order, kernel depending, since you're only using a read syscall here instead of poll or otherwise. It's possible that the other devices may be ready, but you're blocked on one earlier in the list.

read-raw-event should probably at the very least be made to work in nonblocking mode for this to work correctly, or these file descriptors should be passed out in a threaded manner, or otherwise poll/select should be setup to do this, otherwise, this function isn't really what you want. I know I'm speaking C here, but that's the underlying interface we have to think about in this case.

When I designed this library, the concept was to keep it focused on doing one thing well (parse out evdev data into something useful for CL), ideally in a reentrant way. That's why I never put in anything relating to nonblocking, threading or anything else.

This meant that I was actually letting threading and nonblocking behavior exist outside of this library in the outer silica project's inputmanager handler, which felt more appropriate. In there, I was using chanl as a means to dispatch events from multiple threads into a producer/consumer setup to solve the blocking problem in a more managed way. See also handler.lisp in cl-event-handler. Effectively, while the code is currently written to only handle one evdev device, the manager could be altered to manage events from multiple handler instances, each running their own with-evdev-device loop.

(let ((concatenated (gensym))
(inputs (gensym)))
`(let* ((,inputs (loop for device-path in ',device-paths
collecting (open device-path
:element-type '(unsigned-byte 8)
:direction :input
:if-does-not-exist :error)))
(,concatenated (apply #'make-concatenated-stream ,inputs)))
(unwind-protect
(loop
for ,event-var = (read-event ,concatenated)
while ,event-var
do (progn ,@body))
(dolist (s (concatenated-stream-streams ,concatenated))
(close s))))))
1 change: 1 addition & 0 deletions package.lisp
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
(:use #:cl #:binary-types #:alexandria #:local-time #:cl-event-handler)
(:documentation "Linux keyboard event input driver.")
(:export #:with-evdev-device
#:with-evdev-devices

#:input-event
#:keyboard-event
Expand Down