From 7d91a1bf855ead8a77bdf039f59d0d0eb6420169 Mon Sep 17 00:00:00 2001 From: slotThe Date: Sat, 5 Feb 2022 10:34:22 +0100 Subject: [PATCH] X.Prelude: Improve keyToString output MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The keysymToString function prints the key names in pure ASCII; e.g., `keysymToString 250` returns "uacute" instead of "รบ". This is undesirable when printing these keysyms in places like visualSubmap. Thus, move all of the key infrastructure (heh) from X.U.EZConfig to X.Prelude and look up the name of the key if possible. For better composability, slightly change the signature for `regularKeys` and the associated parser. --- XMonad/Prelude.hs | 287 +++++++++++++++++++++++++++++++++++++++- XMonad/Util/EZConfig.hs | 258 +----------------------------------- 2 files changed, 287 insertions(+), 258 deletions(-) diff --git a/XMonad/Prelude.hs b/XMonad/Prelude.hs index ba10f772..18805fa2 100644 --- a/XMonad/Prelude.hs +++ b/XMonad/Prelude.hs @@ -22,9 +22,16 @@ module XMonad.Prelude ( NonEmpty((:|)), notEmpty, safeGetWindowAttributes, + + -- * Keys keyToString, keymaskToString, cleanKeyMask, + regularKeys, + allSpecialKeys, + specialKeys, + multimediaKeys, + functionKeys, ) where import Foreign (alloca, peek) @@ -42,9 +49,13 @@ import Data.Maybe as Exports import Data.Monoid as Exports import Data.Traversable as Exports +import qualified Data.Map.Strict as Map + +import Control.Arrow ((&&&), first) import Data.Bifunctor (bimap) import Data.Bits import Data.List.NonEmpty (NonEmpty ((:|))) +import Data.Tuple (swap) import GHC.Stack -- | Short for 'fromIntegral'. @@ -86,6 +97,9 @@ safeGetWindowAttributes w = withDisplay $ \dpy -> io . alloca $ \p -> 0 -> pure Nothing _ -> Just <$> peek p +----------------------------------------------------------------------- +-- Keys + -- | Convert a modifier mask into a useful string. keymaskToString :: KeyMask -- ^ Num lock mask -> KeyMask -- ^ Modifier mask @@ -115,8 +129,18 @@ keymaskToString numLockMask msk = -- | Convert a full key combination; i.e., a 'KeyMask' and 'KeySym' -- pair, into a string. -keyToString :: (KeyMask, KeySym) -> [Char] -keyToString = uncurry (++) . bimap (keymaskToString 0) keysymToString +keyToString :: (KeyMask, KeySym) -> String +keyToString = uncurry (++) . bimap (keymaskToString 0) ppKeysym + where + ppKeysym :: KeySym -> String + ppKeysym x = case specialMap Map.!? x of + Just s -> "<" <> s <> ">" + Nothing -> case regularMap Map.!? x of + Nothing -> keysymToString x + Just s -> s + + regularMap = Map.fromList (map swap regularKeys) + specialMap = Map.fromList (map swap allSpecialKeys) -- | Strip numlock, capslock, mouse buttons and XKB group from a 'KeyMask', -- leaving only modifier keys like Shift, Control, Super, Hyper in the mask @@ -132,3 +156,262 @@ cleanKeyMask = cleanKeyMask' <$> gets numberlockMask cleanKeyMask' :: KeyMask -> KeyMask -> KeyMask cleanKeyMask' numLockMask mask = mask .&. complement (numLockMask .|. lockMask) .&. (button1Mask - 1) + +-- | A list of "regular" (extended ASCII) keys. +regularKeys :: [(String, KeySym)] +regularKeys = map (first (:[])) + $ zip ['!' .. '~' ] -- ASCII + [xK_exclam .. xK_asciitilde] + <> zip ['\xa0' .. '\xff' ] -- Latin1 + [xK_nobreakspace .. xK_ydiaeresis] + +-- | A list of all special key names and their associated KeySyms. +allSpecialKeys :: [(String, KeySym)] +allSpecialKeys = functionKeys <> specialKeys <> multimediaKeys + +-- | A list pairing function key descriptor strings (e.g. @\"\"@) +-- with the associated KeySyms. +functionKeys :: [(String, KeySym)] +functionKeys = [ ('F' : show n, k) + | (n,k) <- zip ([1..24] :: [Int]) [xK_F1..] + ] + +-- | A list of special key names and their corresponding KeySyms. +specialKeys :: [(String, KeySym)] +specialKeys = + [ ("Backspace" , xK_BackSpace) + , ("Tab" , xK_Tab) + , ("Return" , xK_Return) + , ("Pause" , xK_Pause) + , ("Num_Lock" , xK_Num_Lock) + , ("Caps_Lock" , xK_Caps_Lock) + , ("Scroll_lock", xK_Scroll_Lock) + , ("Sys_Req" , xK_Sys_Req) + , ("Print" , xK_Print) + , ("Escape" , xK_Escape) + , ("Esc" , xK_Escape) + , ("Delete" , xK_Delete) + , ("Home" , xK_Home) + , ("Left" , xK_Left) + , ("Up" , xK_Up) + , ("Right" , xK_Right) + , ("Down" , xK_Down) + , ("L" , xK_Left) + , ("U" , xK_Up) + , ("R" , xK_Right) + , ("D" , xK_Down) + , ("Page_Up" , xK_Page_Up) + , ("Page_Down" , xK_Page_Down) + , ("End" , xK_End) + , ("Insert" , xK_Insert) + , ("Break" , xK_Break) + , ("Space" , xK_space) + , ("Control_L" , xK_Control_L) + , ("Control_R" , xK_Control_R) + , ("Shift_L" , xK_Shift_L) + , ("Shift_R" , xK_Shift_R) + , ("Alt_L" , xK_Alt_L) + , ("Alt_R" , xK_Alt_R) + , ("Meta_L" , xK_Meta_L) + , ("Meta_R" , xK_Meta_R) + , ("Super_L" , xK_Super_L) + , ("Super_R" , xK_Super_R) + , ("Hyper_L" , xK_Hyper_L) + , ("Hyper_R" , xK_Hyper_R) + , ("KP_Space" , xK_KP_Space) + , ("KP_Tab" , xK_KP_Tab) + , ("KP_Enter" , xK_KP_Enter) + , ("KP_F1" , xK_KP_F1) + , ("KP_F2" , xK_KP_F2) + , ("KP_F3" , xK_KP_F3) + , ("KP_F4" , xK_KP_F4) + , ("KP_Home" , xK_KP_Home) + , ("KP_Left" , xK_KP_Left) + , ("KP_Up" , xK_KP_Up) + , ("KP_Right" , xK_KP_Right) + , ("KP_Down" , xK_KP_Down) + , ("KP_Prior" , xK_KP_Prior) + , ("KP_Page_Up" , xK_KP_Page_Up) + , ("KP_Next" , xK_KP_Next) + , ("KP_Page_Down", xK_KP_Page_Down) + , ("KP_End" , xK_KP_End) + , ("KP_Begin" , xK_KP_Begin) + , ("KP_Insert" , xK_KP_Insert) + , ("KP_Delete" , xK_KP_Delete) + , ("KP_Equal" , xK_KP_Equal) + , ("KP_Multiply", xK_KP_Multiply) + , ("KP_Add" , xK_KP_Add) + , ("KP_Separator", xK_KP_Separator) + , ("KP_Subtract", xK_KP_Subtract) + , ("KP_Decimal" , xK_KP_Decimal) + , ("KP_Divide" , xK_KP_Divide) + , ("KP_0" , xK_KP_0) + , ("KP_1" , xK_KP_1) + , ("KP_2" , xK_KP_2) + , ("KP_3" , xK_KP_3) + , ("KP_4" , xK_KP_4) + , ("KP_5" , xK_KP_5) + , ("KP_6" , xK_KP_6) + , ("KP_7" , xK_KP_7) + , ("KP_8" , xK_KP_8) + , ("KP_9" , xK_KP_9) + ] + +-- | List of multimedia keys. If Xlib does not know about some keysym +-- it's omitted from the list ('stringToKeysym' returns 'noSymbol' in +-- this case). +multimediaKeys :: [(String, KeySym)] +multimediaKeys = filter ((/= noSymbol) . snd) . map (id &&& stringToKeysym) $ + [ "XF86ModeLock" + , "XF86MonBrightnessUp" + , "XF86MonBrightnessDown" + , "XF86KbdLightOnOff" + , "XF86KbdBrightnessUp" + , "XF86KbdBrightnessDown" + , "XF86Standby" + , "XF86AudioLowerVolume" + , "XF86AudioMute" + , "XF86AudioRaiseVolume" + , "XF86AudioPlay" + , "XF86AudioStop" + , "XF86AudioPrev" + , "XF86AudioNext" + , "XF86HomePage" + , "XF86Mail" + , "XF86Start" + , "XF86Search" + , "XF86AudioRecord" + , "XF86Calculator" + , "XF86Memo" + , "XF86ToDoList" + , "XF86Calendar" + , "XF86PowerDown" + , "XF86ContrastAdjust" + , "XF86RockerUp" + , "XF86RockerDown" + , "XF86RockerEnter" + , "XF86Back" + , "XF86Forward" + , "XF86Stop" + , "XF86Refresh" + , "XF86PowerOff" + , "XF86WakeUp" + , "XF86Eject" + , "XF86ScreenSaver" + , "XF86WWW" + , "XF86Sleep" + , "XF86Favorites" + , "XF86AudioPause" + , "XF86AudioMedia" + , "XF86MyComputer" + , "XF86VendorHome" + , "XF86LightBulb" + , "XF86Shop" + , "XF86History" + , "XF86OpenURL" + , "XF86AddFavorite" + , "XF86HotLinks" + , "XF86BrightnessAdjust" + , "XF86Finance" + , "XF86Community" + , "XF86AudioRewind" + , "XF86BackForward" + , "XF86Launch0" + , "XF86Launch1" + , "XF86Launch2" + , "XF86Launch3" + , "XF86Launch4" + , "XF86Launch5" + , "XF86Launch6" + , "XF86Launch7" + , "XF86Launch8" + , "XF86Launch9" + , "XF86LaunchA" + , "XF86LaunchB" + , "XF86LaunchC" + , "XF86LaunchD" + , "XF86LaunchE" + , "XF86LaunchF" + , "XF86ApplicationLeft" + , "XF86ApplicationRight" + , "XF86Book" + , "XF86CD" + , "XF86Calculater" + , "XF86Clear" + , "XF86Close" + , "XF86Copy" + , "XF86Cut" + , "XF86Display" + , "XF86DOS" + , "XF86Documents" + , "XF86Excel" + , "XF86Explorer" + , "XF86Game" + , "XF86Go" + , "XF86iTouch" + , "XF86LogOff" + , "XF86Market" + , "XF86Meeting" + , "XF86MenuKB" + , "XF86MenuPB" + , "XF86MySites" + , "XF86New" + , "XF86News" + , "XF86OfficeHome" + , "XF86Open" + , "XF86Option" + , "XF86Paste" + , "XF86Phone" + , "XF86Q" + , "XF86Reply" + , "XF86Reload" + , "XF86RotateWindows" + , "XF86RotationPB" + , "XF86RotationKB" + , "XF86Save" + , "XF86ScrollUp" + , "XF86ScrollDown" + , "XF86ScrollClick" + , "XF86Send" + , "XF86Spell" + , "XF86SplitScreen" + , "XF86Support" + , "XF86TaskPane" + , "XF86Terminal" + , "XF86Tools" + , "XF86Travel" + , "XF86UserPB" + , "XF86User1KB" + , "XF86User2KB" + , "XF86Video" + , "XF86WheelButton" + , "XF86Word" + , "XF86Xfer" + , "XF86ZoomIn" + , "XF86ZoomOut" + , "XF86Away" + , "XF86Messenger" + , "XF86WebCam" + , "XF86MailForward" + , "XF86Pictures" + , "XF86Music" + , "XF86TouchpadToggle" + , "XF86AudioMicMute" + , "XF86_Switch_VT_1" + , "XF86_Switch_VT_2" + , "XF86_Switch_VT_3" + , "XF86_Switch_VT_4" + , "XF86_Switch_VT_5" + , "XF86_Switch_VT_6" + , "XF86_Switch_VT_7" + , "XF86_Switch_VT_8" + , "XF86_Switch_VT_9" + , "XF86_Switch_VT_10" + , "XF86_Switch_VT_11" + , "XF86_Switch_VT_12" + , "XF86_Ungrab" + , "XF86_ClearGrab" + , "XF86_Next_VMode" + , "XF86_Prev_VMode" + , "XF86Bluetooth" + ] diff --git a/XMonad/Util/EZConfig.hs b/XMonad/Util/EZConfig.hs index 71e54f09..3fd76be7 100644 --- a/XMonad/Util/EZConfig.hs +++ b/XMonad/Util/EZConfig.hs @@ -37,7 +37,6 @@ module XMonad.Util.EZConfig ( parseKeyCombo, parseKeySequence, readKeySequence, #ifdef TESTING - functionKeys, specialKeys, multimediaKeys, parseModifier, #endif ) where @@ -444,268 +443,15 @@ parseKey = parseSpecial <> parseRegular -- | Parse a regular key name (represented by itself). parseRegular :: Parser KeySym -parseRegular = choice [ char s $> k - | (s,k) <- zip ['!' .. '~' ] -- ASCII - [xK_exclam .. xK_asciitilde] - - ++ zip ['\xa0' .. '\xff' ] -- Latin1 - [xK_nobreakspace .. xK_ydiaeresis] - ] +parseRegular = choice [ string s $> k | (s, k) <- regularKeys ] -- | Parse a special key name (one enclosed in angle brackets). parseSpecial :: Parser KeySym parseSpecial = do _ <- char '<' choice [ k <$ string name <* char '>' - | (name, k) <- keyNames + | (name, k) <- allSpecialKeys ] --- | A list of all special key names and their associated KeySyms. -keyNames :: [(String, KeySym)] -keyNames = functionKeys ++ specialKeys ++ multimediaKeys - --- | A list pairing function key descriptor strings (e.g. @\"\"@) with --- the associated KeySyms. -functionKeys :: [(String, KeySym)] -functionKeys = [ ('F' : show n, k) - | (n,k) <- zip ([1..24] :: [Int]) [xK_F1..] ] - --- | A list of special key names and their corresponding KeySyms. -specialKeys :: [(String, KeySym)] -specialKeys = [ ("Backspace" , xK_BackSpace) - , ("Tab" , xK_Tab) - , ("Return" , xK_Return) - , ("Pause" , xK_Pause) - , ("Num_Lock" , xK_Num_Lock) - , ("Caps_Lock" , xK_Caps_Lock) - , ("Scroll_lock", xK_Scroll_Lock) - , ("Sys_Req" , xK_Sys_Req) - , ("Print" , xK_Print) - , ("Escape" , xK_Escape) - , ("Esc" , xK_Escape) - , ("Delete" , xK_Delete) - , ("Home" , xK_Home) - , ("Left" , xK_Left) - , ("Up" , xK_Up) - , ("Right" , xK_Right) - , ("Down" , xK_Down) - , ("L" , xK_Left) - , ("U" , xK_Up) - , ("R" , xK_Right) - , ("D" , xK_Down) - , ("Page_Up" , xK_Page_Up) - , ("Page_Down" , xK_Page_Down) - , ("End" , xK_End) - , ("Insert" , xK_Insert) - , ("Break" , xK_Break) - , ("Space" , xK_space) - , ("Control_L" , xK_Control_L) - , ("Control_R" , xK_Control_R) - , ("Shift_L" , xK_Shift_L) - , ("Shift_R" , xK_Shift_R) - , ("Alt_L" , xK_Alt_L) - , ("Alt_R" , xK_Alt_R) - , ("Meta_L" , xK_Meta_L) - , ("Meta_R" , xK_Meta_R) - , ("Super_L" , xK_Super_L) - , ("Super_R" , xK_Super_R) - , ("Hyper_L" , xK_Hyper_L) - , ("Hyper_R" , xK_Hyper_R) - , ("KP_Space" , xK_KP_Space) - , ("KP_Tab" , xK_KP_Tab) - , ("KP_Enter" , xK_KP_Enter) - , ("KP_F1" , xK_KP_F1) - , ("KP_F2" , xK_KP_F2) - , ("KP_F3" , xK_KP_F3) - , ("KP_F4" , xK_KP_F4) - , ("KP_Home" , xK_KP_Home) - , ("KP_Left" , xK_KP_Left) - , ("KP_Up" , xK_KP_Up) - , ("KP_Right" , xK_KP_Right) - , ("KP_Down" , xK_KP_Down) - , ("KP_Prior" , xK_KP_Prior) - , ("KP_Page_Up" , xK_KP_Page_Up) - , ("KP_Next" , xK_KP_Next) - , ("KP_Page_Down", xK_KP_Page_Down) - , ("KP_End" , xK_KP_End) - , ("KP_Begin" , xK_KP_Begin) - , ("KP_Insert" , xK_KP_Insert) - , ("KP_Delete" , xK_KP_Delete) - , ("KP_Equal" , xK_KP_Equal) - , ("KP_Multiply", xK_KP_Multiply) - , ("KP_Add" , xK_KP_Add) - , ("KP_Separator", xK_KP_Separator) - , ("KP_Subtract", xK_KP_Subtract) - , ("KP_Decimal" , xK_KP_Decimal) - , ("KP_Divide" , xK_KP_Divide) - , ("KP_0" , xK_KP_0) - , ("KP_1" , xK_KP_1) - , ("KP_2" , xK_KP_2) - , ("KP_3" , xK_KP_3) - , ("KP_4" , xK_KP_4) - , ("KP_5" , xK_KP_5) - , ("KP_6" , xK_KP_6) - , ("KP_7" , xK_KP_7) - , ("KP_8" , xK_KP_8) - , ("KP_9" , xK_KP_9) - ] - --- | List of multimedia keys. If X server does not know about some --- | keysym it's omitted from list. (stringToKeysym returns noSymbol in this case) -multimediaKeys :: [(String, KeySym)] -multimediaKeys = filter ((/= noSymbol) . snd) . map (id &&& stringToKeysym) $ - [ "XF86ModeLock" - , "XF86MonBrightnessUp" - , "XF86MonBrightnessDown" - , "XF86KbdLightOnOff" - , "XF86KbdBrightnessUp" - , "XF86KbdBrightnessDown" - , "XF86Standby" - , "XF86AudioLowerVolume" - , "XF86AudioMute" - , "XF86AudioRaiseVolume" - , "XF86AudioPlay" - , "XF86AudioStop" - , "XF86AudioPrev" - , "XF86AudioNext" - , "XF86HomePage" - , "XF86Mail" - , "XF86Start" - , "XF86Search" - , "XF86AudioRecord" - , "XF86Calculator" - , "XF86Memo" - , "XF86ToDoList" - , "XF86Calendar" - , "XF86PowerDown" - , "XF86ContrastAdjust" - , "XF86RockerUp" - , "XF86RockerDown" - , "XF86RockerEnter" - , "XF86Back" - , "XF86Forward" - , "XF86Stop" - , "XF86Refresh" - , "XF86PowerOff" - , "XF86WakeUp" - , "XF86Eject" - , "XF86ScreenSaver" - , "XF86WWW" - , "XF86Sleep" - , "XF86Favorites" - , "XF86AudioPause" - , "XF86AudioMedia" - , "XF86MyComputer" - , "XF86VendorHome" - , "XF86LightBulb" - , "XF86Shop" - , "XF86History" - , "XF86OpenURL" - , "XF86AddFavorite" - , "XF86HotLinks" - , "XF86BrightnessAdjust" - , "XF86Finance" - , "XF86Community" - , "XF86AudioRewind" - , "XF86BackForward" - , "XF86Launch0" - , "XF86Launch1" - , "XF86Launch2" - , "XF86Launch3" - , "XF86Launch4" - , "XF86Launch5" - , "XF86Launch6" - , "XF86Launch7" - , "XF86Launch8" - , "XF86Launch9" - , "XF86LaunchA" - , "XF86LaunchB" - , "XF86LaunchC" - , "XF86LaunchD" - , "XF86LaunchE" - , "XF86LaunchF" - , "XF86ApplicationLeft" - , "XF86ApplicationRight" - , "XF86Book" - , "XF86CD" - , "XF86Calculater" - , "XF86Clear" - , "XF86Close" - , "XF86Copy" - , "XF86Cut" - , "XF86Display" - , "XF86DOS" - , "XF86Documents" - , "XF86Excel" - , "XF86Explorer" - , "XF86Game" - , "XF86Go" - , "XF86iTouch" - , "XF86LogOff" - , "XF86Market" - , "XF86Meeting" - , "XF86MenuKB" - , "XF86MenuPB" - , "XF86MySites" - , "XF86New" - , "XF86News" - , "XF86OfficeHome" - , "XF86Open" - , "XF86Option" - , "XF86Paste" - , "XF86Phone" - , "XF86Q" - , "XF86Reply" - , "XF86Reload" - , "XF86RotateWindows" - , "XF86RotationPB" - , "XF86RotationKB" - , "XF86Save" - , "XF86ScrollUp" - , "XF86ScrollDown" - , "XF86ScrollClick" - , "XF86Send" - , "XF86Spell" - , "XF86SplitScreen" - , "XF86Support" - , "XF86TaskPane" - , "XF86Terminal" - , "XF86Tools" - , "XF86Travel" - , "XF86UserPB" - , "XF86User1KB" - , "XF86User2KB" - , "XF86Video" - , "XF86WheelButton" - , "XF86Word" - , "XF86Xfer" - , "XF86ZoomIn" - , "XF86ZoomOut" - , "XF86Away" - , "XF86Messenger" - , "XF86WebCam" - , "XF86MailForward" - , "XF86Pictures" - , "XF86Music" - , "XF86TouchpadToggle" - , "XF86AudioMicMute" - , "XF86_Switch_VT_1" - , "XF86_Switch_VT_2" - , "XF86_Switch_VT_3" - , "XF86_Switch_VT_4" - , "XF86_Switch_VT_5" - , "XF86_Switch_VT_6" - , "XF86_Switch_VT_7" - , "XF86_Switch_VT_8" - , "XF86_Switch_VT_9" - , "XF86_Switch_VT_10" - , "XF86_Switch_VT_11" - , "XF86_Switch_VT_12" - , "XF86_Ungrab" - , "XF86_ClearGrab" - , "XF86_Next_VMode" - , "XF86_Prev_VMode" - , "XF86Bluetooth" ] - -- | Given a configuration record and a list of (key sequence -- description, action) pairs, check the key sequence descriptions -- for validity, and warn the user (via a popup xmessage window) of