-
Notifications
You must be signed in to change notification settings - Fork 0
tuxmark5/FCommandD
Folders and files
Name | Name | Last commit message | Last commit date | |
---|---|---|---|---|
Repository files navigation
FCommandD is an input server. It grabs all incoming events from linux evdev input devices (/dev/input/event*) and forwards them to virtual uinput sinks. This allows to filter incoming events and to react to various key combinations (send DBus-messages, launch new applications and so on). FCommandD can be used to: * launch applications (much like xbindkeys) * send d-bus messages (e.g. to control a media player) * simulate key presses (e.g. to translate keyboard shortcuts. This can be very useful when combined with a mouse, which has some extra buttons) * perform actions based on current context ("modes" can be switched dynamically based on currently focused window.) * to make mouse wheel scroll faster * and so on. A typical FCommandD event chain looks like this: EVDev Keyboard ---\ /--> Virtual UInput Sink #1 ==> Macro Filter --> Hub === EVDev Mouse ---/ \--> Virtual UInput Sink #2 FCommandD periodically monitors processes. This way the daemon can detect new sessions based on process name and identify the session by it's environment variables. When daemon detects a new session, it connects to it's D-Bus and Xorg services. This way FCommandD can monitor actively focused window of each session and to send d-bus to that session's applications. ################################################################################ # INSTALLATION ################################################################################ In order to use FCommandD, you need to: 1. Install cabal, git and ghc: sudo apt-get install cabal git ghc 2. Download the source of FCommandD: git clone git@github.com:tuxmark5/FCommandD.git 3. Copy files/allow-root-access.conf to /etc/dbus-1/session.d This allows for root to access regular d-bus sessions (for some reason this is disabled by default) 4. Tweak src/Main.hs to your liking. 5. Update cabal's database: cabal update 6. Compile & install FCommandD: cd <FCommandD source dir> cabal install 7. Start the daemon: sudo <path to fcommandd>/fcommandd 8. Optionally you can add fcommandd to system's startup (example upstart script - files/fcommandd.conf) ################################################################################ # CONFIGURATION ################################################################################ All user specific configuration is stored within src/Main.hs source file A few important sections of the config file: 1. Input device filter: mdev :: Word16 -> Word16 -> IO SourceId mdev 0x1532 0x010d = return 0 -- BlackWidow mdev 0x1532 0x001f = return 1 -- Naga mdev _ _ = return (-1) This code fragment identifies input devices based on USB vendor and product ids and assigns to each device an identifier (SourceId). Vendor and product ids can be obtained using lsusb. Identifier -1 tells FCommandD to ignore the device. 2. Session filter: sesFilt :: ByteString -> Bool sesFilt "dwm" = True sesFilt "fmonad" = True sesFilt "xfce4-session" = True sesFilt _ = False Session filter is used to identify new sessions. These processes are called session processes. The environments of such processes are used to launch new applications (this way variables like DISPLAY, XAUTHORITY and so on are ensured to be correct). 3. Session identifier: sesId :: Session -> IO ByteString sesId Session { sesDisplay = ":5" } = return "Dl" sesId _ = return "Main" Session identifier assigns a name to each session. This name can be used to switch between sessions. This is only useful when there are more than one Xorg servers running at the same time (and usually on different monitors). With one session such session identifier is sufficient: sesId :: Session -> IO ByteString sesId _ = return "Main" 4. The main function: main :: IO () main = daemon $ do lift $ putStrLn "[*] Starting ..." evdev <- mkEVDevSourceDyn mdev -- creates input sources based on dev filter uinput0 <- mkUInputSink "Primary" -- creates virtual sink #1 macro <- newMacroFilter -- creates the macro filter (cmd, hub) <- newCommander sesId $ do -- creates a commander* addSink "Main" uinput0 -- assigns sink uinput0 to session "Main" setModeSwitcher macro switcher -- assigns mode switcher** setSessionFilter sesFilt -- assigns a session filter runMode macro cmd $ do -- registers modes mode "global" $ do modeApps modeGuayadeque modeVolume modeXMonad mode "local" $ do modeDefault modeFirefox modeGEdit modeKrusader modeLibreOfficeWriter modeMPlayer modeOpera modeSublime modeVMware modeXTerm evdev >>> macro >>> hub -- connects the evdev source with the macro filter and the hub*** lift $ putStrLn "[*] Initialized ..." lift $ forever $ threadDelay 500000000 * commander is responsible for handling session creation/destruction ** mode switcher can be used to disable/enable modes based on currently focused window's properties *** hubs can be used to redirect event stream between multiple sinks. Only useful when running multiple X servers at once. ################################################################################ # MODES ################################################################################ Commands can be grouped into modes. Modes can be arranged into trees. If a parent mode is disabled, so are it's children. An example mode: modeApps :: ModeM Commander () modeApps = mode "apps" $ do command "*LeftAlt+F2" $ run "`dmenu_path | dmenu -b`" command "*Super+B" $ run "VirtualBox" command "*Super+C" $ run "urxvt -e python" command "*Super+F*Super+F" $ run "firefox" command "*Super+F*Super+M" $ run "Thunar" Each command within a mode is triggered by a shortcut. Shortcuts follow this grammar: shortcut ::= (prefix key device?)+ prefix ::= '*' | '+' key ::= identifier device ::= ':' identifier identifier ::= [a-zA-Z0-9] Each key within a shorcut combo must be prefixed with a '*' or a '+'. '*' indicates a MODIFIER key. Modifier keys are never filtered and when pressed are always passed to the X server. Any key prefixed with a '*' becomes a modifier key. '+' indicates a REGULAR key. Regular keys when matched are filtered. Each key can be suffixed with a device identifier. If there is no device identifier present then FCommandD assumes by default that the key's device number (SourceId) is 0. Examples: *LeftCtrl+Z - LeftCtrl key is NOT filtered, but Z is *LeftCtrl+X*LeftCtrl+*LeftShift+Y means exactly same as emacs combo C-x C+Y ################################################################################ # SOME RANDOM NOTES ################################################################################ * FCommandD can only be run as root * FCommandD does not require X11 to function. All keyboard actions created with FCommandD are global and should work within virtual terminals as well. It can be safely (probably :D ) started on init 3 * FCommandD was only tested on a x86_64 system, so there are no guarantees that it will work on any other arch. * If FCommandD hangs (this should only happen with some crazy configs), then re-plug your keyboard and/or mouse. * Currently FCommandD can only launch processes as UID=1000 (this is hardcoded). Hopefully will be fixed in the future. * FCommandD can be used to control window managers as well. An example config for XMonad can be found here: git@github.com:tuxmark5/FMonad.git ################################################################################ # TODO ################################################################################ * TCP Source/Sink. This will replicate functionality of synergy (http://synergy-foss.org/) project * EVDEV device hotplug. * Need to parse UIDs from the session environment, so applications can be run with UIDs other than 1000 ################################################################################
About
Input/command server
Resources
Stars
Watchers
Forks
Releases
No releases published
Packages 0
No packages published