[英]Use IO when creating Xmonad configuration (keymap depends on number of connected monitors)
我正在尝试根据连接的监视器数量设置不同的 Xmonad 键映射。 原因是我在多个系统(台式机、具有不同显示器配置的笔记本电脑,包括 3 个显示器)上使用相同的 Xmonad 配置文件。 显示器在不同系统上以不同的顺序列出,这就是为什么我需要在使用 3 显示器设置时对显示索引进行硬编码。
我目前最好的尝试是这样的(所有不相关的都已删除):
import qualified Graphics.X11.Xlib as X11
import qualified Graphics.X11.Xinerama as X11
screenKeysFor2Monitors conf@(XConfig {XMonad.modMask = modMask}) = M.fromList $
[((m .|. mod4Mask, key), screenWorkspace sc >>= flip whenJust (windows . f)) -- Replace 'mod1Mask' with your mod key of choice.
| (key, sc) <- zip [xK_w, xK_e] [0, 1] -- Usual screen order
, (f, m) <- [(W.view, 0), (W.shift, shiftMask), (W.greedyView, mod1Mask)]]
screenKeysFor3Monitors conf@(XConfig {XMonad.modMask = modMask}) = M.fromList $
[((m .|. mod4Mask, key), screenWorkspace sc >>= flip whenJust (windows . f)) -- Replace 'mod1Mask' with your mod key of choice.
| (key, sc) <- zip [xK_w, xK_e, xK_q] [0, 2, 1] -- hardcoded according to laptop driver
, (f, m) <- [(W.view, 0), (W.shift, shiftMask), (W.greedyView, mod1Mask)]]
screenKeys x = do
numberOfScreens <- getScreens
keyConfig <- case numberOfScreens of
3 -> screenKeysFor3Monitors x
_ -> screenKeysFor2Monitors x
return keyConfig
-- | Get number of screens
getScreens = do
screens <- do
dpy <- X11.openDisplay ""
rects <- X11.getScreenInfo dpy
X11.closeDisplay dpy
return rects
pure $ length screens
xmonadConfig = ewmh xfceConfig{
modMask = mod4Mask
keys = MyKeys.screenKeys
}
我收到这个错误
Error detected while loading xmonad configuration file: /home/me/.xmonad/xmonad.hs
lib/MyXMonad/Keys.hs:51:64: error:
* Couldn't match expected type `M.Map (KeyMask, KeySym) (X ())`
with actual type `IO (X ())`
* In the expression: (screenKeys x)
In the second argument of `($)`, namely
`[(myKeysToAdd x), (workspaceKeys x), (screenKeys x)]`
In the expression:
M.unions $ [(myKeysToAdd x), (workspaceKeys x), (screenKeys x)]
|
51 | keysToAdd x = M.unions $ [(myKeysToAdd x), (workspaceKeys x), (screenKeys x)]
| ^^^^^^^^^^^^
lib/MyXMonad/Keys.hs:242:30: error:
* Couldn't match type `M.Map (KeyMask, KeySym)` with `IO`
Expected type: IO (X ())
Actual type: M.Map (KeyMask, KeySym) (X ())
* In the expression: screenKeysFor3Monitors x
In a case alternative: 3 -> screenKeysFor3Monitors x
In a stmt of a 'do' block:
keyConfig <- case numberOfScreens of
3 -> screenKeysFor3Monitors x
_ -> screenKeysFor2Monitors x
|
242 | 3 -> screenKeysFor3Monitors x
| ^^^^^^^^^^^^^^^^^^^^^^^^
lib/MyXMonad/Keys.hs:243:30: error:
* Couldn't match type `M.Map (KeyMask, KeySym)` with `IO`
Expected type: IO (X ())
Actual type: M.Map (KeyMask, KeySym) (X ())
* In the expression: screenKeysFor2Monitors x
In a case alternative: _ -> screenKeysFor2Monitors x
In a stmt of a 'do' block:
keyConfig <- case numberOfScreens of
3 -> screenKeysFor3Monitors x
_ -> screenKeysFor2Monitors x
|
243 | _ -> screenKeysFor2Monitors x
| ^^^^^^^^^^^^^^^^^^^^^^^^
Please check the file for errors.
如果我理解正确,这里的问题是我的代码取决于副作用(使用监视器配置使用 IO monad)并且变得不纯。 我可以使用liftIO
将IO
monad 转换为X
monad。 但是X
monad 只能在键绑定处理程序中访问。 为 Xmonad 配置创建键绑定的代码必须是纯的,这里不需要X
monad。
换句话说,如果我的情况正确,就不可能使用非纯函数定义键绑定(例如,通过查看连接的监视器)。 也许有一些解决方法? 我对 Haskell 缺乏一个体面的理解,也许对于普通的 Haskell 程序员来说,我遗漏了一些明显的东西。
对 Xmonad 不太熟悉,但我猜您可以轻松地执行以下操作。 创建一个纯 function mkConfig
,它接受屏幕数量并返回所需的键映射。 然后,在你的main
传递给xmonad
function。 我没有尝试编译任何这些但可能你可以轻松修改它
mkConfig numberOfScreens = -- Notice that this is a pure function
case numberOfScreens of
3 -> screenKeysFor3Monitors x
_ -> screenKeysFor2Monitors x
main :: IO ()
main = do
numberOfScreens <- getScreens -- Retrive the number of screens from the system
let keyConfig = mkConfig numberOfScreens -- Makes a key mapping out of this
xmonadConfig = ewmh xfceConfig{ modMask = mod4Mask, keys = keyConfig } -- Creates a Xmonad configuration
xmonad xmonadConfig -- Launch Xmonad.
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.