Commits

Micah Nordland committed 79fade8

Adding key press handling, everything works.

  • Participants
  • Parent commits 31742c0

Comments (0)

Files changed (7)

 program_OBJS := $(program_C_OBJS) $(program_CXX_OBJS)
 program_INCLUDE_DIRS := include
 program_LIBRARY_DIRS :=
-program_LIBRARIES := xcb xcb-util xcb-icccm xcb-ewmh
+program_LIBRARIES := xcb xcb-util xcb-icccm xcb-ewmh xcb-keysyms
 
 CPPFLAGS += $(foreach includedir,$(program_INCLUDE_DIRS),-I$(includedir)) -std=c++11 -g
 LDFLAGS += $(foreach librarydir,$(program_LIBRARY_DIRS),-L$(librarydir))
 
 }
 
-
-
 #endif //EVENT_H

include/eventHandlers.h

+#ifndef EVENTHANDERS_H
+#define EVENTHANDERS_H
 #include <string>
 
 #include <xcb/xcb.h>
         void handleDestroyNotify(EventPtr event);
         void handleUnmapNotify(EventPtr event);
         void handleEnterNotify(EventPtr event);
+        void handleKeyRelease(EventPtr event);
 
     private:
         Setup *setup;
         int boxUid;
 };
+
+#endif //EVENTHANDERS_H

include/keyHandlers.h

+#ifndef KEYHANDLER_H
+#define KEYHANDLER_H
+#define BadAccess 10
+
+#include <iostream>
+#include <map>
+#include <functional>
+#include <vector>
+#include <utility>
+
+#include <xcb/xcb.h>
+#include <xcb/xcb_keysyms.h>
+#include <X11/keysym.h>
+
+#include "event.h"
+#include "setup.h"
+
+typedef std::function<void ()> KeyCallback;
+typedef std::map<std::pair<uint32_t, xcb_keysym_t>, KeyCallback> KeyCallbackMap;
+
+typedef enum
+{
+	Press,
+	Release
+} KeyEventType;
+
+class KeyHandler
+{
+    public:
+        KeyHandler(Setup *setup);
+        ~KeyHandler();
+        void handleMappingNotify(EventPtr event);
+		void handleKeyPress(EventPtr event);
+        void handleKeyRelease(EventPtr event);
+        void grabKey(uint32_t mods, xcb_keysym_t, KeyEventType type, KeyCallback callback);
+        uint32_t getMod(xcb_keysym_t keysym);
+
+    private:
+        void getLocks();
+        bool grab(uint32_t mods, xcb_keysym_t key);
+		void ungrab(xcb_keysym_t key);
+		void grabAll();
+		void ungrabAll();
+		bool grabWithLocks(uint32_t mods, xcb_keycode_t keycode);
+        Setup *setup;
+        xcb_key_symbols_t *symbols;
+        uint32_t numLock;
+        uint32_t capsLock;
+        uint32_t shiftLock;
+		uint32_t scrollLock;
+		KeyCallbackMap pressCallbackMap;
+		KeyCallbackMap releaseCallbackMap;
+};
+
+
+#endif //KEYHANDLER_H

src/eventHandlers.cpp

     if(winBox)
         tree.setFocused(winBox);
 }
+
+void EventHandler::handleKeyRelease(EventPtr event)
+{
+    
+}

src/keyHandlers.cpp

+#include "keyHandlers.h"
+
+KeyHandler::KeyHandler(Setup *setup):
+    setup(setup),
+    symbols(xcb_key_symbols_alloc(setup->conn)),
+	numLock(0),
+	capsLock(0),
+	shiftLock(0),
+	scrollLock(0)
+
+{
+    getLocks();
+}
+
+KeyHandler::~KeyHandler()
+{
+    xcb_key_symbols_free(symbols);
+}
+
+void KeyHandler::handleMappingNotify(EventPtr event)
+{
+	auto ev = convertEvent<xcb_mapping_notify_event_t>(event);
+	xcb_refresh_keyboard_mapping(symbols, ev.get());
+	getLocks();
+	ungrabAll();
+	grabAll();
+
+}
+
+void KeyHandler::handleKeyPress(EventPtr event)
+{
+	auto ev = convertEvent<xcb_key_press_event_t>(event);
+	uint32_t mods = ev->state & ~(numLock|capsLock|shiftLock|scrollLock);
+	mods &= 0xFF;
+	auto key = std::make_pair(mods, xcb_key_symbols_get_keysym(symbols, ev->detail, 0));
+	auto iter = pressCallbackMap.find(key);
+	if (iter != pressCallbackMap.end())
+	{
+		auto callback = iter->second;
+		callback();
+	}
+
+}
+
+void KeyHandler::handleKeyRelease(EventPtr event)
+{
+	auto ev = convertEvent<xcb_key_release_event_t>(event);
+	uint32_t mods = ev->state & ~(numLock|capsLock|shiftLock|scrollLock);
+	mods &= 0xFF;
+	auto key = std::make_pair(mods, xcb_key_symbols_get_keysym(symbols, ev->detail, 0));
+	auto iter = releaseCallbackMap.find(key);
+	if (iter != releaseCallbackMap.end())
+	{
+		auto callback = iter->second;
+		callback();
+	}
+}
+
+void KeyHandler::getLocks()
+{
+    numLock = getMod(XK_Num_Lock);
+    shiftLock = getMod(XK_Shift_Lock);
+    capsLock = getMod(XK_Caps_Lock);
+	scrollLock = getMod(XK_Scroll_Lock);
+
+}
+
+//this algorithm is taken from i3, this stuff just 
+//seems way more complex than it has to be.
+//Maybe I'll think different once I've figured it out completely.
+//This is the most reasonable and reusable implementation of this,
+//but they all look very much the same. I've changed some naming to 
+//match my style rules.
+uint32_t KeyHandler::getMod(xcb_keysym_t keysym)
+{
+    xcb_get_modifier_mapping_reply_t *modmapReply;
+
+    xcb_flush(setup->conn);
+
+    /* Get the current modifier mapping (this is blocking!) */
+    if (!(modmapReply = xcb_get_modifier_mapping_reply(setup->conn, xcb_get_modifier_mapping(setup->conn), nullptr)))
+        return 0;
+    
+    xcb_keycode_t *codes, *modmap;
+    xcb_keycode_t modCode;
+
+    modmap = xcb_get_modifier_mapping_keycodes(modmapReply);
+
+    /* Get the list of keycodes for the given symbol */
+    if (!(codes = xcb_key_symbols_get_keycode(symbols, keysym)))
+        return 0;
+
+    /* Loop through all modifiers (Mod1-Mod5, Shift, Control, Lock) */
+    for (int mod = 0; mod < 8; mod++)
+        for (int j = 0; j < modmapReply->keycodes_per_modifier; j++) {
+            /* Store the current keycode (for modifier 'mod') */
+            modCode = modmap[(mod * modmapReply->keycodes_per_modifier) + j];
+            /* Check if that keycode is in the list of previously resolved
+             * keycodes for our symbol. If so, return the modifier mask. */
+            for (xcb_keycode_t *code = codes; *code; code++) {
+                if (*code != modCode)
+                    continue;
+
+                free(codes);
+                /* This corresponds to the XCB_MOD_MASK_* constants */
+                return (1 << mod);
+            }
+        }
+
+    return 0;
+}
+
+bool KeyHandler::grab(uint32_t mods, xcb_keysym_t key)
+{
+    std::cout << "keysym is: " << key << std::endl;
+    xcb_keycode_t *keycodes = xcb_key_symbols_get_keycode(symbols, key); 
+    xcb_keycode_t keycode;
+	
+	if (not keycodes)
+		return false;
+	
+    int i = 0;
+    while (keycodes[i] != XCB_NO_SYMBOL)
+    {
+        keycode = keycodes[i];
+		grabWithLocks(mods, keycode);
+		i++;
+    }
+	return true;
+}
+
+void KeyHandler::ungrab(xcb_keysym_t key)
+{
+    xcb_keycode_t *keycodes = xcb_key_symbols_get_keycode(symbols, key); 
+    xcb_keycode_t keycode;
+	if (not keycodes)
+		return;
+    int i = 0;
+    while (keycodes[i]!= XCB_NO_SYMBOL)
+    {
+		keycode = keycodes[i];
+		xcb_ungrab_key(setup->conn, keycode, setup->root, XCB_BUTTON_MASK_ANY);
+		i++;
+	}	
+}
+
+void KeyHandler::grabKey(uint32_t mods, xcb_keysym_t keysym, KeyEventType type, KeyCallback callback)
+{
+	if (grab(mods, keysym))
+	{
+		auto key = std::make_pair(mods, keysym);
+		if (type == Press)
+		{
+			auto iter = pressCallbackMap.find(key);
+			if (iter == pressCallbackMap.end())
+				pressCallbackMap[key] = callback;
+		}
+
+		else
+		{
+			auto iter = releaseCallbackMap.find(key);
+			if (iter == releaseCallbackMap.end())
+				releaseCallbackMap[key] = callback;
+
+		}
+
+	}
+}
+
+void KeyHandler::grabAll()
+{
+	for (auto &key : pressCallbackMap)
+	{
+		grab(key.first.first, key.first.second);
+	}
+	for (auto &key : releaseCallbackMap)
+	{
+		grab(key.first.first, key.first.second);
+	}
+}
+
+void KeyHandler::ungrabAll()
+{
+	for (auto &key : pressCallbackMap)
+	{
+		ungrab(key.first.first);
+	}
+	for (auto &key : releaseCallbackMap)
+	{
+		ungrab(key.first.first);
+	}
+
+}
+
+bool KeyHandler::grabWithLocks(uint32_t mods, xcb_keycode_t keycode)
+{
+    xcb_void_cookie_t grabCookie = xcb_grab_key_checked(setup->conn, true, setup->root, mods, keycode, XCB_GRAB_MODE_ASYNC, XCB_GRAB_MODE_ASYNC);
+	xcb_generic_error_t *grabError;
+    if ((grabError = xcb_request_check(setup->conn, grabCookie)))
+	{
+		if (grabError->error_code == BadAccess)
+			return false;	
+	}
+	if (numLock != 0)
+		xcb_grab_key(setup->conn, true, setup->root, mods|numLock, keycode, XCB_GRAB_MODE_ASYNC, XCB_GRAB_MODE_ASYNC);
+	if (capsLock != 0)
+		xcb_grab_key(setup->conn, true, setup->root, mods|capsLock, keycode, XCB_GRAB_MODE_ASYNC, XCB_GRAB_MODE_ASYNC);
+	if (shiftLock != 0)
+		xcb_grab_key(setup->conn, true, setup->root, mods|shiftLock, keycode, XCB_GRAB_MODE_ASYNC, XCB_GRAB_MODE_ASYNC);
+	if (scrollLock != 0)
+		xcb_grab_key(setup->conn, true, setup->root, mods|scrollLock, keycode, XCB_GRAB_MODE_ASYNC, XCB_GRAB_MODE_ASYNC);
+	if (numLock != 0 and capsLock != 0)
+		xcb_grab_key(setup->conn, true, setup->root, mods|numLock|capsLock, keycode, XCB_GRAB_MODE_ASYNC, XCB_GRAB_MODE_ASYNC);
+	if (numLock != 0 and scrollLock != 0)
+		xcb_grab_key(setup->conn, true, setup->root, mods|numLock|scrollLock, keycode, XCB_GRAB_MODE_ASYNC, XCB_GRAB_MODE_ASYNC);
+	if (numLock != 0 and shiftLock != 0)
+		xcb_grab_key(setup->conn, true, setup->root, mods|numLock|shiftLock, keycode, XCB_GRAB_MODE_ASYNC, XCB_GRAB_MODE_ASYNC);
+	if (capsLock != 0 and shiftLock != 0)
+		xcb_grab_key(setup->conn, true, setup->root, mods|capsLock|shiftLock, keycode, XCB_GRAB_MODE_ASYNC, XCB_GRAB_MODE_ASYNC);
+	if (capsLock != 0 and scrollLock != 0)
+		xcb_grab_key(setup->conn, true, setup->root, mods|capsLock|scrollLock, keycode, XCB_GRAB_MODE_ASYNC, XCB_GRAB_MODE_ASYNC);
+	if (shiftLock != 0 and scrollLock !=0)
+		xcb_grab_key(setup->conn, true, setup->root, mods|shiftLock|scrollLock, keycode, XCB_GRAB_MODE_ASYNC, XCB_GRAB_MODE_ASYNC);
+	if (numLock != 0 and capsLock != 0 and shiftLock != 0 and scrollLock != 0)
+		xcb_grab_key(setup->conn, true, setup->root, mods|numLock|capsLock|shiftLock|scrollLock, keycode, XCB_GRAB_MODE_ASYNC, XCB_GRAB_MODE_ASYNC);
+	return true;
+}
 #include <functional>
 
 #include <xcb/xcb.h>
+#include <xcb/xcb_keysyms.h>
+#include <X11/keysym.h>
 
 #include "event.h"
 #include "setup.h"
 #include "eventHandlers.h"
+#include "keyHandlers.h"
 
 
 int main()
         Setup setup;
         EventDispatcher eventDispatch(setup.conn);
         EventHandler handler(&setup);
+        KeyHandler keyHandler(&setup);
         eventDispatch.setHandler("ConfigureRequest", std::bind(&EventHandler::handleConfigureRequest, &handler, std::placeholders::_1));
         eventDispatch.setHandler("MapRequest", std::bind(&EventHandler::handleMapRequest, &handler, std::placeholders::_1));
         eventDispatch.setHandler("DestroyNotify", std::bind(&EventHandler::handleDestroyNotify, &handler, std::placeholders::_1));
         eventDispatch.setHandler("UnmapNotify", std::bind(&EventHandler::handleUnmapNotify, &handler, std::placeholders::_1));
         eventDispatch.setHandler("EnterNotify", std::bind(&EventHandler::handleEnterNotify, &handler, std::placeholders::_1));
+        eventDispatch.setHandler("MappingNotify", std::bind(&KeyHandler::handleMappingNotify, &keyHandler, std::placeholders::_1));
+        eventDispatch.setHandler("KeyPress", std::bind(&KeyHandler::handleKeyPress, &keyHandler, std::placeholders::_1));
+        eventDispatch.setHandler("KeyRelease", std::bind(&KeyHandler::handleKeyRelease, &keyHandler, std::placeholders::_1));
+        keyHandler.grabKey(XCB_MOD_MASK_4, XK_Escape, Press, [&]{ std::cout << "got a key press!!!"<< std::endl; });
         eventDispatch.eventLoop();
     }
     catch (OtherWindowManager &ex)