evdev 2.1.0 → 2.2.0
raw patch · 8 files changed
+86/−15 lines, 8 filesPVP ok
version bump matches the API change (PVP)
API changes (from Hackage documentation)
+ Evdev: AbsInfo :: Int32 -> Int32 -> Int32 -> Int32 -> Int32 -> Int32 -> AbsInfo
+ Evdev: LedOff :: LEDValue
+ Evdev: LedOn :: LEDValue
+ Evdev: [absFlat] :: AbsInfo -> Int32
+ Evdev: [absFuzz] :: AbsInfo -> Int32
+ Evdev: [absMaximum] :: AbsInfo -> Int32
+ Evdev: [absMinimum] :: AbsInfo -> Int32
+ Evdev: [absResolution] :: AbsInfo -> Int32
+ Evdev: [absValue] :: AbsInfo -> Int32
+ Evdev: data AbsInfo
+ Evdev: data LEDValue
+ Evdev: deviceAbsAxis :: Device -> AbsoluteAxis -> IO (Maybe AbsInfo)
+ Evdev: setDeviceLED :: Device -> LEDEvent -> LEDValue -> IO ()
+ Evdev.Codes: RelHWheelHiRes :: RelativeAxis
+ Evdev.Codes: RelReserved :: RelativeAxis
+ Evdev.Codes: RelWheelHiRes :: RelativeAxis
+ Evdev.Uinput: AbsoluteEvent :: AbsoluteAxis -> EventValue -> EventData
+ Evdev.Uinput: Event :: EventData -> DiffTime -> Event
+ Evdev.Uinput: EventCode :: Word16 -> EventCode
+ Evdev.Uinput: EventValue :: Int32 -> EventValue
+ Evdev.Uinput: ForceFeedbackEvent :: EventCode -> EventValue -> EventData
+ Evdev.Uinput: ForceFeedbackStatusEvent :: EventCode -> EventValue -> EventData
+ Evdev.Uinput: KeyEvent :: Key -> KeyEvent -> EventData
+ Evdev.Uinput: LEDEvent :: LEDEvent -> EventValue -> EventData
+ Evdev.Uinput: MiscEvent :: MiscEvent -> EventValue -> EventData
+ Evdev.Uinput: PowerEvent :: EventCode -> EventValue -> EventData
+ Evdev.Uinput: Pressed :: KeyEvent
+ Evdev.Uinput: RelativeEvent :: RelativeAxis -> EventValue -> EventData
+ Evdev.Uinput: Released :: KeyEvent
+ Evdev.Uinput: RepeatEvent :: RepeatEvent -> EventValue -> EventData
+ Evdev.Uinput: Repeated :: KeyEvent
+ Evdev.Uinput: SoundEvent :: SoundEvent -> EventValue -> EventData
+ Evdev.Uinput: SwitchEvent :: SwitchEvent -> EventValue -> EventData
+ Evdev.Uinput: SyncEvent :: SyncEvent -> EventData
+ Evdev.Uinput: UnknownEvent :: Word16 -> EventCode -> EventValue -> EventData
+ Evdev.Uinput: [eventData] :: Event -> EventData
+ Evdev.Uinput: [eventTime] :: Event -> DiffTime
+ Evdev.Uinput: data Event
+ Evdev.Uinput: data EventData
+ Evdev.Uinput: data KeyEvent
+ Evdev.Uinput: newtype EventCode
+ Evdev.Uinput: newtype EventValue
- Evdev: devicePhys :: Device -> IO ByteString
+ Evdev: devicePhys :: Device -> IO (Maybe ByteString)
- Evdev: deviceUniq :: Device -> IO ByteString
+ Evdev: deviceUniq :: Device -> IO (Maybe ByteString)
Files
- CHANGELOG.md +9/−0
- README.md +1/−1
- evdev.cabal +3/−3
- src/Evdev.hs +19/−6
- src/Evdev/Codes.chs +20/−1
- src/Evdev/LowLevel.chs +24/−3
- src/Evdev/Uinput.hs +8/−1
- test/Test.hs +2/−0
CHANGELOG.md view
@@ -1,5 +1,14 @@ # Revision history for evdev +## 2.2.0 -- 05-11-2022+* More bindings:+ * `deviceAbsAxis`+ * `REL_WHEEL_HI_RES` and `REL_HWHEEL_HI_RES`+ * `setDeviceLED`+* Open devices with write permissions by default. This is primarily in order to make `setDeviceLED` easier to use.+* Export event types from `Uinput` module. This means that that module can actually reasonably be used without also importing `Evdev` and selectively hiding things.+* Wrap results of `deviceUniq` and `devicePhys` in `Maybe`, to avoid possibly dereferencing null pointers.+ ## 2.1.0 -- 2021-02-12 * Add `Evdev.Uinput` module, for creating virtual devices. * More functions for querying device properties.
README.md view
@@ -13,7 +13,7 @@ # Permissions -Your user will need to be a member of the `input` group in order to read from devices. Try `usermod -a -G input [username]`.+Your user will need to be a member of the `input` group in order to read from devices. Try `usermod -a -G input $USER`. To create virtual devices (i.e. to use the `Evdev.UInput` module) you will need permission to write to `/dev/uinput`. This can usually be achieved by creating a group specially for uinput permissions: ```
evdev.cabal view
@@ -1,6 +1,6 @@ cabal-version: 3.0 name: evdev-version: 2.1.0+version: 2.2.0 author: George Thomas maintainer: George Thomas description: Provides access to the Linux event device interface.@@ -25,8 +25,8 @@ extra ^>= {1.6.18, 1.7}, filepath-bytestring ^>= 1.4.2, monad-loops ^>= 0.4.3,- rawfilepath ^>= 0.2.4,- time ^>= {1.9.3, 1.10, 1.11},+ rawfilepath ^>= 1.0.0,+ time ^>= {1.9.3, 1.10, 1.11, 1.12, 1.13}, unix ^>= 2.7.2, default-language: Haskell2010 default-extensions:
src/Evdev.hs view
@@ -20,6 +20,8 @@ deviceVendor, deviceBustype, deviceVersion,+ deviceAbsAxis,+ LL.AbsInfo (..), -- ** Grabbing grabDevice, ungrabDevice,@@ -34,6 +36,8 @@ -- * Lower-level newDeviceFromFd, nextEventMay,+ LL.LEDValue(..),+ setDeviceLED, -- ** C-style types -- | These correspond more directly to C's /input_event/ and /timeval/. -- They are used internally, but may be useful for advanced users.@@ -66,7 +70,7 @@ import System.Posix.Process (getProcessID) import System.Posix.Files (readSymbolicLink) import System.Posix.ByteString (Fd, RawFilePath)-import System.Posix.IO.ByteString (OpenMode (ReadOnly), defaultFileFlags, openFd)+import System.Posix.IO.ByteString (OpenMode (..), defaultFileFlags, openFd) import qualified Evdev.LowLevel as LL import Evdev.Codes@@ -197,11 +201,14 @@ toCTimeVal t = LL.CTimeVal n (round $ f * 1_000_000) where (n,f) = properFraction t --- | Create a device from a valid path - usually /\/dev\/input\/eventX/ for some /X/.+{- | Create a device from a valid path - usually /\/dev\/input\/eventX/ for some numeric /X/.+Use 'newDeviceFromFd' if you need more control over how the device is created.+-} newDevice :: RawFilePath -> IO Device-newDevice path = newDeviceFromFd =<< openFd path ReadOnly Nothing defaultFileFlags+newDevice path = newDeviceFromFd =<< openFd path ReadWrite Nothing defaultFileFlags -{- | Generalisation of 'newDevice'.+{- | Generalisation of 'newDevice', in case one needs control over the file descriptor,+e.g. in order to set a particular 'System.Posix.FileMode', 'System.Posix.OpenMode', or 'System.Posix.OpenFileFlags'. Note that: > newDevice path = newDeviceFromFd =<< openFd path ReadOnly Nothing defaultFileFlags@@ -224,9 +231,9 @@ deviceFd :: Device -> IO Fd deviceFd = LL.deviceFd . cDevice-devicePhys :: Device -> IO ByteString+devicePhys :: Device -> IO (Maybe ByteString) devicePhys = join . LL.devicePhys . cDevice-deviceUniq :: Device -> IO ByteString+deviceUniq :: Device -> IO (Maybe ByteString) deviceUniq = join . LL.deviceUniq . cDevice deviceProduct :: Device -> IO Int deviceProduct = LL.deviceProduct . cDevice@@ -248,6 +255,12 @@ deviceHasEvent dev e = LL.hasEventCode (cDevice dev) typ code where (typ,code,_val) = toCEventData e +deviceAbsAxis :: Device -> AbsoluteAxis -> IO (Maybe LL.AbsInfo)+deviceAbsAxis dev = LL.getAbsInfo (cDevice dev) . fromEnum'++-- | Set the state of a LED on a device.+setDeviceLED :: Device -> LEDEvent -> LL.LEDValue -> IO ()+setDeviceLED dev led val = cErrCall "setDeviceLED" dev (LL.libevdev_kernel_set_led_value (cDevice dev) led val) {- Util -}
src/Evdev/Codes.chs view
@@ -582,6 +582,7 @@ deriving (Bounded, Eq, Ord, Read, Show) #} -- | Relative changes+#if defined(REL_WHEEL_HI_RES) {#enum define RelativeAxis { REL_X as RelX, REL_Y as RelY,@@ -592,8 +593,26 @@ REL_HWHEEL as RelHwheel, REL_DIAL as RelDial, REL_WHEEL as RelWheel,- REL_MISC as RelMisc}+ REL_MISC as RelMisc,+ REL_RESERVED as RelReserved,+ REL_WHEEL_HI_RES as RelWheelHiRes,+ REL_HWHEEL_HI_RES as RelHWheelHiRes} deriving (Bounded, Eq, Ord, Read, Show) #}+# else+{#enum define RelativeAxis {+ REL_X as RelX,+ REL_Y as RelY,+ REL_Z as RelZ,+ REL_RX as RelRx,+ REL_RY as RelRy,+ REL_RZ as RelRz,+ REL_HWHEEL as RelHwheel,+ REL_DIAL as RelDial,+ REL_WHEEL as RelWheel,+ REL_MISC as RelMisc,+ REL_RESERVED as RelReserved}+ deriving (Bounded, Eq, Ord, Read, Show) #}+#endif -- | Absolute changes {#enum define AbsoluteAxis {
src/Evdev/LowLevel.chs view
@@ -4,7 +4,7 @@ import Data.ByteString (ByteString,packCString,useAsCString) import Data.Coerce (coerce) import Data.Int (Int32,Int64)-import Data.Word (Word16)+import Data.Word (Word16, Word32) import Foreign (Ptr,allocaBytes,mallocBytes,mallocForeignPtrBytes,newForeignPtr_,nullPtr,peek,withForeignPtr) import Foreign.C (CInt(..),CLong(..),CUInt(..),CUShort(..),CString) import Foreign.C.Error (Errno(Errno), eOK, eAGAIN)@@ -128,6 +128,7 @@ , absFlat :: Int32 , absResolution :: Int32 }+ deriving (Show) withAbsInfo :: AbsInfo -> (Ptr () -> IO a) -> IO a withAbsInfo AbsInfo{..} f = do p <- mallocBytes {#sizeof input_absinfo#}@@ -140,7 +141,21 @@ pf <- newForeignPtr_ p withForeignPtr pf f +--TODO can c2hs make this simpler at all?+foreign import ccall safe "Evdev/LowLevel.chs.h libevdev_get_abs_info"+ libevdev_get_abs_info :: Ptr Device -> CUInt -> IO (Ptr ())+getAbsInfo :: Device -> Word32 -> IO (Maybe AbsInfo)+getAbsInfo dev x = withDevice dev \devPtr ->+ libevdev_get_abs_info devPtr (CUInt x) >>= handleNull (pure Nothing) \absinfoPtr -> do+ CInt absValue <- {#get input_absinfo.value#} absinfoPtr+ CInt absMinimum <- {#get input_absinfo.minimum#} absinfoPtr+ CInt absMaximum <- {#get input_absinfo.maximum#} absinfoPtr+ CInt absFuzz <- {#get input_absinfo.fuzz#} absinfoPtr+ CInt absFlat <- {#get input_absinfo.flat#} absinfoPtr+ CInt absResolution <- {#get input_absinfo.resolution#} absinfoPtr+ pure $ Just AbsInfo{..} + {- Simpler functions -} {#fun libevdev_has_property as hasProperty { `Device', convertEnum `DeviceProperty' } -> `Bool' #}@@ -148,8 +163,8 @@ {#fun libevdev_has_event_code as hasEventCode { `Device', `Word16', `Word16' } -> `Bool' #} {#fun libevdev_get_fd as deviceFd { `Device' } -> `Fd' Fd #} {#fun libevdev_get_name as deviceName { `Device' } -> `IO ByteString' packCString #}-{#fun libevdev_get_phys as devicePhys { `Device' } -> `IO ByteString' packCString #}-{#fun libevdev_get_uniq as deviceUniq { `Device' } -> `IO ByteString' packCString #}+{#fun libevdev_get_phys as devicePhys { `Device' } -> `IO (Maybe ByteString)' packCString' #}+{#fun libevdev_get_uniq as deviceUniq { `Device' } -> `IO (Maybe ByteString)' packCString' #} {#fun libevdev_get_id_product as deviceProduct { `Device' } -> `Int' #} {#fun libevdev_get_id_vendor as deviceVendor { `Device' } -> `Int' #} {#fun libevdev_get_id_bustype as deviceBustype { `Device' } -> `Int' #}@@ -162,6 +177,12 @@ {#fun libevdev_enable_event_code as enableCode { `Device', `Word16', `Word16', `Ptr ()' } -> `Errno' Errno #} {#fun libevdev_uinput_write_event as writeEvent { `UDevice', `Word16', `Word16', `Int32' } -> `Errno' Errno #} +-- | LEDs values+{#enum define LEDValue {+ LIBEVDEV_LED_ON as LedOn,+ LIBEVDEV_LED_OFF as LedOff}+ deriving (Bounded, Eq, Ord, Read, Show) #}+{#fun libevdev_kernel_set_led_value { `Device', convertEnum `LEDEvent', `LEDValue' } -> `Errno' Errno #} {- Util -}
src/Evdev/Uinput.hs view
@@ -6,9 +6,16 @@ writeBatch, defaultDeviceOpts, DeviceOpts (..),- LL.AbsInfo (..), deviceSyspath, deviceDevnode,++ -- * Re-exports from 'Evdev'+ AbsInfo (..),+ Event(..),+ EventData(..),+ KeyEvent(..),+ EventCode(..),+ EventValue(..), ) where import Control.Monad
test/Test.hs view
@@ -42,6 +42,8 @@ Nothing -> assertFailure "Couldn't find device with correct name" Just d -> do putMVar start ()+ (@?= Nothing) =<< devicePhys d+ (@?= Nothing) =<< deviceUniq d (@?= [EvSyn, EvKey]) =<< deviceEventTypes d evs' <- whileJust ((\x -> guard (x /= last evs) $> x) . eventData <$> nextEvent d) pure filter (/= SyncEvent SynReport) evs' @?= init evs