diff --git a/bindings/init.lua b/bindings/init.lua
new file mode 100644
index 0000000..08cd4c8
--- /dev/null
+++ b/bindings/init.lua
@@ -0,0 +1,194 @@
+--[[
+-- handle key- and mousebindings in a sane and readable way
+--]]
+
+-- needs
+local awful = require("awful")
+local gears = require("gears")
+local notifications = require("strangesome.notifications")
+local debug = notifications.debug_enabled
+local debug_msg = notifications.debug_msg
+local wrequire = require("strangesome.loader").wrequire
+
+-- define standard commands local to speed up things a little bit
+local next = next
+local setmetatable = setmetatable
+local tonumber = tonumber
+
+-- strangesome.bindings
+local bindings = { _NAME = "strangesome.bindings" }
+
+local gearstable = awful.util.table or gears.table
+local internalbindings = {}
+local separator = "+"
+local keyregex = "([^"..separator.."]+)"
+
+-- define named keys with usable aliases
+local named_keys = {
+ { "Escape", { "esc", "escape" } },
+ { "Left", {} },
+ { "Right", {} },
+ { "Up", {} },
+ { "Down", {} },
+ { "Enter", {} },
+ { "Return", {} },
+ { "Print", {} },
+ { "Space", {} },
+ { "Backspace", {} },
+ { "Tab", {} },
+ { "XF86AudioMute", {} },
+ { "XF86HomePage", {} },
+ { "XF86Calculator", {} },
+ { "XF86AudioMedia", {} },
+ { "XF86AudioPrev", {} },
+ { "XF86AudioNext", {} },
+ { "XF86AudioPlay", {} },
+ { "XF86AudioStop", {} },
+ { "XF86MyComputer", {} },
+ { "XF86AudioRaiseVolume", {} },
+ { "XF86AudioLowerVolume", {} },
+ -- more to come...
+}
+
+local mod_keys = {
+ { "Control", { "control", "ctrl" } },
+ { "Shift", {} },
+ { "Mod1", { "alt", "mod1" } },
+ { "Mod4", { "super", "meta", "mod4" } },
+}
+
+local mouse_keys = {
+ { 1, { "left", "mouseleft", "leftkey", "leftclick" } },
+ { 2, { "middle", "mousemiddle", "middlekey", "middleclick" } },
+ { 3, { "right", "mouseright", "rightkey", "rightclick" } },
+ { 4, { "up", "mouseup", "scrollup" } },
+ { 5, { "down", "mousedown", "scrolldown" } },
+ -- more to come...
+}
+
+
+--[[
+-- map = {
+-- { "Ctrl+Alt+Super+L", description, function() }
+-- }
+--]]
+
+function bindings.addkeymap(target, category, map)
+ if debug then debug_msg("Type of internalbindings["..target.."]: "..type(internalbindings[target])) end
+ if type(internalbindings[target]) == "nil" then internalbindings[target] = {} end
+ for _, mapentry in ipairs(map) do
+ local keys = mapentry[1]
+ local desc = mapentry[2]
+ local bindfunc = mapentry[3]
+ internalbindings[target] = gearstable.join(internalbindings[target],
+ awful.key(getmodkeys(keys), getkey(keys), bindfunc, {description = desc, group = category})
+ )
+ end
+
+ if debug then debug_msg("Type of internalbindings["..target.."]: "..type(internalbindings[target])) end
+ return internalbindings[target]
+end
+
+function bindings.addmousemap(target, map)
+ if debug then debug_msg("Type of internalbindings["..target.."]: "..type(internalbindings[target])) end
+ if type(internalbindings[target]) == "nil" then internalbindings[target] = {} end
+ for _, mapentry in ipairs(map) do
+ local keys = mapentry[1]
+ local bindfunc = mapentry[2]
+ internalbindings[target] = gearstable.join(internalbindings[target],
+ awful.button(getmodkeys(keys), getmousekey(keys), bindfunc)
+ )
+ end
+
+ if debug then debug_msg("Type of internalbindings["..target.."]: "..type(internalbindings[target])) end
+ return internalbindings[target]
+end
+
+function bindings.export(target)
+ if type(internalbindings[target]) == "nil" then return {} end
+ return internalbindings[target]
+end
+
+function getmodkeys(keys)
+ local modkeys = {}
+ local mkey
+
+ for key in string.gmatch(keys, keyregex) do
+ mkey = ismodkey(key)
+ if mkey then
+ modkeys[#modkeys+1] = mkey
+ end
+ end
+
+ return modkeys
+end
+
+function getkey(keys)
+ local sepregex = "["..separator.."]["..separator.."]"
+ local key = ""
+ for str in string.gmatch(keys, keyregex) do
+ -- single char, always lower case
+ if string.len(str) == 1 then
+ key = string.lower(str)
+ -- named key, see table named_keys above
+ elseif isnamedkey(str) then
+ key = isnamedkey(str)
+ -- match separator key, e.g in "Alt+Super++" for Alt, Super and "+"
+ elseif string.match(keys, sepregex) then
+ key = string.lower(separator)
+ end
+ end
+
+ return key
+end
+
+function getmousekey(keys)
+ local keyregex = "([^"..separator.."]+)"
+ local key = 0
+ local mkey
+ for str in string.gmatch(keys, keyregex) do
+ -- is number and between 1 and 5
+ if type(str.tonumber) == "number" then
+ local num = str.tonumber
+ if num > 0 and num < 6 then key = num end
+ -- mousekey, see table mouse_keys above (integers 1 to 5)
+ elseif ismousekey(str) then
+ key = ismousekey(str)
+ end
+ end
+
+ return key
+end
+
+function isnamedkey(key)
+ -- there are no named keys with length 1
+ if string.len(key) == 1 then return false end
+ return check_keys_table(key, named_keys)
+end
+
+function ismodkey(key)
+ return check_keys_table(key, mod_keys)
+end
+
+function ismousekey(key)
+ return check_keys_table(key, mouse_keys)
+end
+
+function check_keys_table(key, table)
+ for _, entry in ipairs(table) do
+ local tkey = entry[1]
+ local aliases = entry[2]
+ if next(aliases) == nil then
+ --no aliases given, check against tkey
+ if string.lower(key) == string.lower(tkey) then return tkey end
+ else
+ for _, alias in ipairs(aliases) do
+ if string.lower(key) == string.lower(alias) then return tkey end
+ end
+ end
+ end
+ return false
+end
+
+
+return setmetatable(bindings, { __index = wrequire })
diff --git a/init.lua b/init.lua
new file mode 100644
index 0000000..2ea1ef9
--- /dev/null
+++ b/init.lua
@@ -0,0 +1,8 @@
+--[[
+-- Make awesome configuration more readable
+--]]
+
+return {
+ bindings = require("strangesome.bindings"),
+ notifications = require("strangesome.notifications")
+}
diff --git a/loader.lua b/loader.lua
new file mode 100644
index 0000000..3ace181
--- /dev/null
+++ b/loader.lua
@@ -0,0 +1,12 @@
+--[[
+-- module loader, inspired by lain
+--]]
+local rawget = rawget
+
+local loader = {}
+
+function loader.wrequire(t, k)
+ return rawget(t, k) or require(t._NAME .. '.' .. k)
+end
+
+return loader
diff --git a/notifications/init.lua b/notifications/init.lua
new file mode 100644
index 0000000..2a1424d
--- /dev/null
+++ b/notifications/init.lua
@@ -0,0 +1,65 @@
+--[[
+-- notifications and debug
+--]]
+
+-- needs
+local awful = require("awful")
+local gears = require("gears")
+local naughty = require("naughty")
+--local addkeymap = require("strangesome.bindings").addkeymap
+local wrequire = require("strangesome.loader").wrequire
+
+-- define standard commands local to speed up things a little bit
+local setmetatable = setmetatable
+local next = next
+
+-- strangesome.notifications
+local notifications = { _NAME = "strangesome.notifications" }
+
+-- debug settings
+local debug = false
+local debug_window = nil
+local debug_window_title = "Strangesome Debug Window"
+local debug_text = ""
+local debug_text_max_lines = 30
+
+function notifications.enable_debug()
+ debug = true
+ init_debug_window()
+
+ return debug_window
+end
+
+function notifications.debug_enabled()
+ return debug
+end
+
+function notifications.debug_msg(msg)
+ if not debug then return false end
+ debug_text = debug_text..""..msg.."\n"
+ naughty.replace_text(debug_window, debug_window_title, debug_text)
+
+ return debug_text
+end
+
+function init_debug_window()
+ debug_window = naughty.notify({
+ title = debug_window_title,
+ text = "Starting Debug Window\n",
+ timeout = 0,
+ position = "bottom_right",
+ ontop = false,
+ height = 500,
+ width = 950,
+ opacity = 0.7,
+ ignore_suspend = true
+ })
+
+ return debug_window
+end
+
+function toggle_debug_window()
+ notifications.debug_msg("Toggle debug window")
+end
+
+return setmetatable(notifications, { __index = wrequire })