Brian McKenna avatar Brian McKenna committed b4e9722

Execute key bindings

Comments (0)

Files changed (6)

 import Control.Exception (bracket)
 import Control.Monad
 import Data.Char
+import Data.Maybe (fromMaybe)
 import Data.List
 import System.Exit
 import System.IO
 
+import qualified Data.Map as Map
+
 import Foreign
 import Foreign.C
 
 import qualified XMonad.Layout as L
 import qualified XMonad.StackSet as S
 
+import OSXMonad.Keys
 import OSXMonad.Window
 
 updateWindow :: Window -> IO ()
                   height = fromIntegral $ rect_height r
                 }
 
-tile' l r@(Rectangle _ _ screenWidth screenHeight) context = do
+eventModBits :: Event -> XM.ButtonMask
+eventModBits event =
+    foldl ((. bits) . (+)) 0 [
+     (altKey, XM.mod1Mask),
+     (commandKey, XM.mod4Mask),
+     (controlKey, XM.controlMask),
+     (shiftKey, XM.shiftMask)
+    ]
+        where bits (k, d) = if toBool (k event) then fromIntegral d else 0
+
+getEvent :: IO Event
+getEvent = do
+  collectEvent
+  peek globalEvent
+
+getNamedWindows :: Ptr Windows -> IO [Window]
+getNamedWindows context = do
   count <- getWindows context
   filledContext <- peek context
 
   windowsPtrs <- peekArray count . elements $ filledContext
   windows <- mapM (\winPtr -> peek winPtr) windowsPtrs
 
-  namedWindows <- filterM (\win -> (peekCString . name $ win) >>= return . not . all isSpace) windows
+  filterM (\win -> (peekCString . name $ win) >>= return . not . all isSpace) windows
+
+tile' :: Rectangle -> Ptr Windows -> XM.X ()
+tile' r context = do
+  event <- XM.io getEvent
+
+  xmc <- XM.asks XM.config
+  ks <- XM.asks XM.keyActions
+
+  let modBits = eventModBits event
+      osxKey = osxKeyToX11 . fromIntegral . keyCode $ event
+      maybeAction = Map.lookup (modBits, osxKey) ks
+  fromMaybe (return ()) maybeAction
+
+  namedWindows <- XM.io . getNamedWindows $ context
 
   let windowStack = S.Stack 0 [] [fromIntegral x | x <- [1..length namedWindows - 1]]
-  let rectangles = C.pureLayout l r windowStack
+
+  (rectangles, _) <- C.runLayout (S.Workspace "OS X" (C.layoutHook xmc) (Just windowStack)) r
 
   let windows' = map (\(i, r) -> rectangleWindow r (namedWindows !! fromIntegral i)) rectangles
 
   if null namedWindows
      then return ()
-     else mapM_ updateWindow windows'
+     else XM.io $ mapM_ updateWindow windows'
 
---tile :: C.Layout XM.Window -> Rectangle -> IO ()
-tile layout rectangle = do
-  transitioning <- isSpaceTransitioning
+tile :: Rectangle -> XM.X ()
+tile rectangle = do
+  transitioning <- XM.io $ isSpaceTransitioning
   if transitioning
     then return ()
     else do
-      bracket
-         (new (Windows nullPtr))
-         (\context -> do
-            freeWindows context
-            free context)
-         (tile' layout rectangle)
+      context <- XM.io . new $ Windows nullPtr
+      tile' rectangle context
+      XM.io . freeWindows $ context
+      XM.io . free $ context
 
 screen :: IO Rectangle
 screen = do
 
 osxmonad :: (C.LayoutClass l XM.Window, Read (l XM.Window)) => XM.XConfig l -> IO ()
 osxmonad initxmc = do
+  setupEventCallback
+
+  let display = error "display"
+      xmc = initxmc { C.layoutHook = C.Layout $ C.layoutHook initxmc }
+      theRoot = 0
+      normalBorder = 0
+      focusedBorder = 0
+      buttonActions = Map.empty
+      mouseFocused = False
+      mousePosition = Nothing
+
+      windowset = error "windowset"
+      mapped = error "mapped"
+      waitingUnmap = error "waitingUnmap"
+      dragging = error "dragging"
+      numberlockMask = error "numberlockMask"
+      extensibleState = error "extensibleState"
+
+      conf = C.XConf display xmc theRoot normalBorder focusedBorder (XM.keys xmc xmc) buttonActions mouseFocused mousePosition
+      state = C.XState windowset mapped waitingUnmap dragging numberlockMask extensibleState
+
   hasAPI <- axAPIEnabled
   if not hasAPI
     then do
       exitWith $ ExitFailure 1
     else do
       s <- screen
-      forever $ do
-           tile (C.layoutHook initxmc) s
-           threadDelay $ 1000 * 500
+      XM.runX conf state . forever $ do
+           tile s
+           XM.io . threadDelay $ 1000 * 500
+      return ()
+module OSXMonad.Keys where
+
+import XMonad
+
+-- From HIToolbox/Events.h
+
+osxKeyToX11 :: Int -> KeySym
+osxKeyToX11 0x00 = xK_a
+osxKeyToX11 0x01 = xK_s
+osxKeyToX11 0x02 = xK_d
+osxKeyToX11 0x03 = xK_f
+osxKeyToX11 0x04 = xK_h
+osxKeyToX11 0x05 = xK_g
+osxKeyToX11 0x06 = xK_z
+osxKeyToX11 0x07 = xK_x
+osxKeyToX11 0x08 = xK_c
+osxKeyToX11 0x09 = xK_v
+osxKeyToX11 0x0B = xK_b
+osxKeyToX11 0x0C = xK_q
+osxKeyToX11 0x0D = xK_w
+osxKeyToX11 0x0E = xK_e
+osxKeyToX11 0x0F = xK_r
+osxKeyToX11 0x10 = xK_y
+osxKeyToX11 0x11 = xK_t
+osxKeyToX11 0x12 = xK_1
+osxKeyToX11 0x13 = xK_2
+osxKeyToX11 0x14 = xK_3
+osxKeyToX11 0x15 = xK_4
+osxKeyToX11 0x16 = xK_6
+osxKeyToX11 0x17 = xK_5
+osxKeyToX11 0x18 = xK_equal
+osxKeyToX11 0x19 = xK_9
+osxKeyToX11 0x1A = xK_7
+osxKeyToX11 0x1B = xK_minus
+osxKeyToX11 0x1C = xK_8
+osxKeyToX11 0x1D = xK_0
+osxKeyToX11 0x1E = xK_bracketright
+osxKeyToX11 0x1F = xK_o
+osxKeyToX11 0x20 = xK_u
+osxKeyToX11 0x21 = xK_bracketleft
+osxKeyToX11 0x22 = xK_i
+osxKeyToX11 0x23 = xK_p
+osxKeyToX11 0x25 = xK_l
+osxKeyToX11 0x26 = xK_j
+-- TODO: 0x27
+osxKeyToX11 0x28 = xK_k
+osxKeyToX11 0x29 = xK_semicolon
+osxKeyToX11 0x2A = xK_backslash
+osxKeyToX11 0x2B = xK_comma
+osxKeyToX11 0x2C = xK_slash
+osxKeyToX11 0x2D = xK_n
+osxKeyToX11 0x2E = xK_m
+osxKeyToX11 0x2F = xK_period
+osxKeyToX11 0x32 = xK_grave
+osxKeyToX11 0x41 = xK_KP_Decimal
+osxKeyToX11 0x43 = xK_KP_Multiply
+osxKeyToX11 0x45 = xK_KP_Add
+-- TODO: 0x47
+osxKeyToX11 0x48 = xK_KP_Divide
+osxKeyToX11 0x4C = xK_KP_Enter
+osxKeyToX11 0x4E = xK_KP_Subtract
+osxKeyToX11 0x51 = xK_KP_Equal
+osxKeyToX11 0x52 = xK_KP_0
+osxKeyToX11 0x53 = xK_KP_1
+osxKeyToX11 0x54 = xK_KP_2
+osxKeyToX11 0x55 = xK_KP_3
+osxKeyToX11 0x56 = xK_KP_4
+osxKeyToX11 0x57 = xK_KP_5
+osxKeyToX11 0x58 = xK_KP_6
+osxKeyToX11 0x59 = xK_KP_7
+osxKeyToX11 0x5B = xK_KP_8
+osxKeyToX11 0x5C = xK_KP_9
+
+osxKeyToX11 0x24 = xK_Return
+osxKeyToX11 0x30 = xK_Tab
+osxKeyToX11 0x31 = xK_space
+osxKeyToX11 0x33 = xK_Delete
+osxKeyToX11 0x35 = xK_Escape
+osxKeyToX11 0x37 = xK_Super_L
+osxKeyToX11 0x38 = xK_Shift_L
+osxKeyToX11 0x39 = xK_Caps_Lock
+osxKeyToX11 0x3A = xK_Alt_L
+osxKeyToX11 0x3B = xK_Control_L
+osxKeyToX11 0x3C = xK_Shift_R
+osxKeyToX11 0x3D = xK_Alt_R
+osxKeyToX11 0x3E = xK_Control_R
+-- TODO: 0x3F
+osxKeyToX11 0x40 = xK_F17
+-- TODO: 0x48
+-- TODO: 0x49
+-- TODO: 0x4A
+osxKeyToX11 0x4F = xK_F18
+osxKeyToX11 0x50 = xK_F19
+osxKeyToX11 0x5A = xK_F20
+osxKeyToX11 0x60 = xK_F5
+osxKeyToX11 0x61 = xK_F6
+osxKeyToX11 0x62 = xK_F7
+osxKeyToX11 0x63 = xK_F3
+osxKeyToX11 0x64 = xK_F8
+osxKeyToX11 0x65 = xK_F9
+osxKeyToX11 0x67 = xK_F11
+osxKeyToX11 0x69 = xK_F13
+osxKeyToX11 0x6A = xK_F16
+osxKeyToX11 0x6B = xK_F14
+osxKeyToX11 0x6D = xK_F10
+osxKeyToX11 0x6F = xK_F12
+osxKeyToX11 0x71 = xK_F15
+osxKeyToX11 0x72 = xK_Help
+osxKeyToX11 0x73 = xK_Home
+osxKeyToX11 0x74 = xK_Page_Up
+osxKeyToX11 0x75 = xK_Delete
+osxKeyToX11 0x76 = xK_F4
+osxKeyToX11 0x77 = xK_End
+osxKeyToX11 0x78 = xK_F2
+osxKeyToX11 0x79 = xK_Page_Down
+osxKeyToX11 0x7A = xK_F1
+osxKeyToX11 0x7B = xK_Left
+osxKeyToX11 0x7C = xK_Right
+osxKeyToX11 0x7D = xK_Down
+osxKeyToX11 0x7E = xK_Up
+
+osxKeyToX11 _ = 0

OSXMonad/Window.hsc

 foreign import ccall "utils.h getFrame"
   getFrame :: Ptr CGPoint -> Ptr CGSize -> IO ()
 
+foreign import ccall "utils.h setupEventCallback"
+  setupEventCallback :: IO ()
+
+foreign import ccall "utils.h &globalEvent"
+  globalEvent :: Ptr Event
+
+foreign import ccall "utils.h collectEvent"
+  collectEvent :: IO ()
+
 foreign import ccall "utils.h isSpaceTransitioning"
   isSpaceTransitioning :: IO Bool
 
       size :: CGSize
     } deriving Show
 
+data Event = Event {
+      keyCode :: CInt,
+      altKey :: CInt,
+      commandKey :: CInt,
+      controlKey :: CInt,
+      shiftKey :: CInt
+    } deriving Show
+
 data Windows = Windows { elements :: Ptr (Ptr Window) } deriving Show
 
 instance Storable CGPoint where
       return $ Windows elements'
     poke ptr (Windows elements') = do
         (#poke Windows, elements) ptr elements'
+
+instance Storable Event where
+    sizeOf _ = (#size Event)
+    alignment _ = alignment (undefined :: CInt)
+    peek ptr = do
+      keyCode' <- (#peek Event, keyCode) ptr
+      altKey' <- (#peek Event, altKey) ptr
+      commandKey' <- (#peek Event, commandKey) ptr
+      controlKey' <- (#peek Event, controlKey) ptr
+      shiftKey' <- (#peek Event, shiftKey) ptr
+      return $ Event keyCode' altKey' commandKey' controlKey' shiftKey'
+    poke ptr (Event keyCode' altKey' commandKey' controlKey' shiftKey') = do
+        (#poke Event, keyCode) ptr keyCode'
+        (#poke Event, altKey) ptr altKey'
+        (#poke Event, commandKey) ptr commandKey'
+        (#poke Event, controlKey) ptr controlKey'
+        (#poke Event, shiftKey) ptr shiftKey'
 
 library
   exposed-modules:     OSXMonad.Core
-  other-modules:       OSXMonad.Window
+  other-modules:       OSXMonad.Window, OSXMonad.Keys
   ghc-options:         -framework Cocoa
   c-sources:           src/utils.m
   include-dirs:        src
-  build-depends:       base ==4.5.*, xmonad ==0.10.1, X11 ==1.5.0.1
+  build-depends:       base ==4.5.*, containers ==0.4.*, xmonad ==0.10.1, X11 ==1.5.0.1
   build-tools:         hsc2hs
   extensions:
     EmptyDataDecls
     Window **elements;
 } Windows;
 
+typedef struct {
+    int keyCode;
+    int altKey;
+    int commandKey;
+    int controlKey;
+    int shiftKey;
+} Event;
+
+Event globalEvent;
+
 int getWindows(Windows *);
 void freeWindows(Windows *);
 void setWindow(Window *);
 void getFrame(CGPoint *, CGSize *);
+void setupEventCallback();
+void collectEvent();
 bool isSpaceTransitioning();
     size->width = visibleFrame.size.width;
     size->height = visibleFrame.size.height;
 }
+
+void collectEvent() {
+    CFRunLoopRunInMode(kCFRunLoopDefaultMode, INT_MAX, YES);
+}
+
+CGEventRef callback(CGEventTapProxy proxy, CGEventType type, CGEventRef event, void *ref) {
+    globalEvent.keyCode = CGEventGetIntegerValueField(event, kCGKeyboardEventKeycode);
+
+    CGEventFlags eventMask = CGEventGetFlags(event);
+    globalEvent.altKey = (eventMask & kCGEventFlagMaskAlternate) != 0;
+    globalEvent.commandKey = (eventMask & kCGEventFlagMaskCommand) != 0;
+    globalEvent.controlKey = (eventMask & kCGEventFlagMaskControl) != 0;
+    globalEvent.shiftKey = (eventMask & kCGEventFlagMaskShift) != 0;
+
+    return event;
+}
+
+void setupEventCallback() {
+    CGEventMask eventMask = CGEventMaskBit(kCGEventKeyDown);
+    CFMachPortRef eventTap = CGEventTapCreate(kCGSessionEventTap, kCGHeadInsertEventTap, kCGEventTapOptionListenOnly, eventMask, callback, NULL);
+
+    CFRunLoopSourceRef runLoopSource = CFMachPortCreateRunLoopSource(kCFAllocatorDefault, eventTap, 0);
+
+    CFRunLoopAddSource(CFRunLoopGetCurrent(), runLoopSource, kCFRunLoopCommonModes);
+
+    CGEventTapEnable(eventTap, YES);
+}
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.