我正在使用 Xmonad,并且在我的配置中定义了一个很长的自定义键盘快捷键列表。
我想在配置的底部添加一些类似于 catch all 的内容,如果有人按下未定义的组合键,它会锁定我的屏幕,因此任何未定义为执行其他操作的Ctrl+*
或Alt+应该只锁定*
屏幕。
有没有什么好方法可以做到这一点,而不必列出所有当前未定义的组合?
答案1
有没有什么好方法可以做到这一点,而不必列出所有当前未定义的组合?
你应该明白,这不仅仅是“锁定任何未知的组合”。您可能不想阻止诸如Control-R允许您反向搜索 shell 历史记录,或者Control-P在您最喜欢的办公套件中打开打印对话框之类的事情。
话虽如此,实现目标的最简洁方法是重新定义在 XMonad 中查找键绑定的方式,以便任何“未找到”变成“锁定屏幕”。不幸的是,XMonad 不向用户提供这样的设施;你必须破解 XMonad 本身。
您可以做的下一个最好的事情是生成所有有效组合键的映射,将其删除您已经定义的组合,然后将所有剩余的组合绑定到“锁定屏幕”命令。幸运的是,这一切都可以自动化。
我假设您的屏幕锁定命令定义如下:
lockScreen = spawn "i3lock"
组合键由掩码和按键组成,全部列在Graphics.X11.Types
。
首先,让我们定义可能的掩码列表:
masks = [controlMask, mod1Mask]
在这里,我假设您只想阻止以Control和开头的组合Alt。有 8 个掩模,并且它们可以组合,因此这条线可能会复杂得多。然而,我们在这里定义的掩码越多,我们在生成绑定时就应该越小心——我们不想意外地阻止一些重要的东西!
好的,下一站是钥匙列表。这些也列在 中Graphics.X11.Types
,并以 开头xK_
。他们有类型KeySym
,但他们真正的本质是什么Word64
。然而,我建议不要发疯,避免写类似的东西[0 .. maxBound :: KeySym]
——这会导致一个巨大的地图,会消耗大量的内存。
因此,只需查找您想要覆盖的键的数量并将它们分组为小的定义即可。例如,我在这里介绍最常见的键:
keys :: [KeySym]
keys = [xK_Home .. xK_Num_Lock] ++ -- Cursor control & motion
[xK_KP_Space .. xK_R15] ++ -- Keypad and Function keys
[xK_space .. xK_asciitilde] -- ASCII and such
现在我们准备定义一个键绑定列表:
fallbackKeys = [((mask, key), lockScreen)
| mask <- masks
, key <- keys ]
这将为给定掩码和键的每种可能的组合生成键绑定定义。
现在我们必须将这些定义应用到您的配置中。
XMonad.Util.EZConfig
有一个非常有用的additionalKeys
组合器给定配置和键绑定定义列表,会将后者添加到前者中,如果存在任何冲突,则覆盖现有定义。我们想要的恰恰相反:我们希望fallbackKeys
以这样的方式应用它们:它们仅填充未定义的位置,而保留已定义的按键绑定原样。为了实现这一点,我们将定义另一个函数:
import qualified Data.Map as M
backupKeys :: XConfig a -> [((ButtonMask, KeySym), X ())] -> XConfig a
backupKeys conf keyList =
conf { keys = \cnf -> M.union (keys conf cnf) (M.fromList keyList) }
这是 的直接复制粘贴additionalKeys
,但其中的参数Data.Map.union
被交换,从而产生我们想要的行为。 (看union
的文档以了解其工作原理。)
现在我们终于可以使用这一切了。在你的某个地方xmonad.hs
有这样一行:
main = xmonad $ def {…} `additionalKeys` myKeys
修改如下:
main = xmonad $ def {…} `additionalKeys` myKeys `backupKeys` fallbackKeys
重新编译并重新启动 XMonad,然后享受新设置!