#!/usr/bin/env ruby # -*- encoding: utf-8 -*- # Copyright muflax , 2015 # License: GNU GPLv3 (or later) require "muflax" LayoutDir = "src/keyboard/ergodox/layout" LayoutFile = "#{LayoutDir}/saneo-mod.c" puts "generating #{LayoutFile}..." Layer = Struct.new :code, :up, :down class Key attr_reader :layers Layers = [ :basic, :mod3, :mod4, :mod5 ] Functions = { # down up "basic" => [ "&kbfun_press_release", ], "toggle" => [ "&kbfun_toggle", ], "transparent" => [ "&kbfun_transparent", ], # down up "mod3" => [ "&kbfun_layer_push_1", "&kbfun_layer_pop_1" ], "mod4" => [ "&kbfun_layer_push_2", "&kbfun_layer_pop_2" ], "mod5" => [ "&kbfun_layer_push_3", "&kbfun_layer_pop_3" ], "latch_mod3" => [ "&kbfun_layer_sticky_1", ], "latch_mod4" => [ "&kbfun_layer_sticky_2", ], "latch_mod5" => [ "&kbfun_layer_sticky_3", ], # down up "shifted" => [ "&kbfun_shift_press_release", ], "ctrled" => [ "&kbfun_control_press_release", ], "capslock" => [ "&kbfun_2_keys_capslock_press_release", ], } Keys = { "a" => "KEY_a_A", "b" => "KEY_b_B", "c" => "KEY_c_C", "d" => "KEY_d_D", "e" => "KEY_e_E", "f" => "KEY_f_F", "g" => "KEY_g_G", "h" => "KEY_h_H", "i" => "KEY_i_I", "j" => "KEY_j_J", "k" => "KEY_k_K", "l" => "KEY_l_L", "m" => "KEY_m_M", "n" => "KEY_n_N", "o" => "KEY_o_O", "p" => "KEY_p_P", "q" => "KEY_q_Q", "r" => "KEY_r_R", "s" => "KEY_s_S", "t" => "KEY_t_T", "u" => "KEY_u_U", "v" => "KEY_v_V", "w" => "KEY_w_W", "x" => "KEY_x_X", "y" => "KEY_y_Y", "z" => "KEY_z_Z", # "0" => "KEY_0_RightParenthesis", "1" => "KEY_1_Exclamation", "2" => "KEY_2_At", "3" => "KEY_3_Pound", "4" => "KEY_4_Dollar", "5" => "KEY_5_Percent", "6" => "KEY_6_Caret", "7" => "KEY_7_Ampersand", "8" => "KEY_8_Asterisk", "9" => "KEY_9_LeftParenthesis", # "f1" => "KEY_F1", "f2" => "KEY_F2", "f3" => "KEY_F3", "f4" => "KEY_F4", "f5" => "KEY_F5", "f6" => "KEY_F6", "f7" => "KEY_F7", "f8" => "KEY_F8", "f9" => "KEY_F9", "f10" => "KEY_F10", "f11" => "KEY_F11", "f12" => "KEY_F12", "f13" => "KEY_F13", "f14" => "KEY_F14", "f15" => "KEY_F15", "f16" => "KEY_F16", "f17" => "KEY_F17", "f18" => "KEY_F18", "f19" => "KEY_F19", "f20" => "KEY_F20", "f21" => "KEY_F21", "f22" => "KEY_F22", "f23" => "KEY_F23", "f24" => "KEY_F24", # "\\" => "KEY_Backslash_Pipe", "{" => "KEY_LeftBracket_LeftBrace", "}" => "KEY_RightBracket_RightBrace", "[" => "KEY_LeftBracket_LeftBrace", "]" => "KEY_RightBracket_RightBrace", "," => "KEY_Comma_LessThan", "-" => "KEY_Dash_Underscore", "=" => "KEY_Equal_Plus", "`" => "KEY_GraveAccent_Tilde", "." => "KEY_Period_GreaterThan", "\'" => "KEY_SingleQuote_DoubleQuote", ";" => "KEY_Semicolon_Colon", "/" => "KEY_Slash_Question", "~" => "KEY_GraveAccent_Tilde", "%" => "KEY_5_Percent", "*" => "KEY_8_Asterisk", ":" => "KEY_Semicolon_Colon", "^" => "KEY_6_Caret", "<" => "KEY_Comma_LessThan", ">" => "KEY_Period_GreaterThan", "?" => "KEY_Slash_Question", "!" => "KEY_1_Exclamation", "(" => "KEY_9_LeftParenthesis", ")" => "KEY_0_RightParenthesis", "|" => "KEY_Backslash_Pipe", "@" => "KEY_2_At", "\"" => "KEY_SingleQuote_DoubleQuote", "_" => "KEY_Dash_Underscore", "+" => "KEY_Equal_Plus", "$" => "KEY_4_Dollar", "&" => "KEY_7_Ampersand", "#" => "KEY_3_Pound", "hash" => "KEY_3_Pound", # "enter" => "KEY_ReturnEnter", "return" => "KEY_ReturnEnter", "space" => "KEY_Spacebar", "tab" => "KEY_Tab", "backspace" => "KEY_DeleteBackspace", "delete" => "KEY_DeleteForward", "home" => "KEY_Home", "end" => "KEY_End", "page_up" => "KEY_PageUp", "page_down" => "KEY_PageDown", "up" => "KEY_UpArrow", "down" => "KEY_DownArrow", "left" => "KEY_LeftArrow", "right" => "KEY_RightArrow", "escape" => "KEY_Escape", "insert" => "KEY_Insert", "menu" => "KEY_Application", # "alt" => "KEY_LeftAlt", "alt_gr" => "KEY_RightAlt", "umlaut" => "KEY_RightAlt", "control" => "KEY_LeftControl", "control_l" => "KEY_LeftControl", "control_r" => "KEY_RightControl", "win" => "KEY_LeftGUI", "shift_l" => "KEY_LeftShift", "shift_r" => "KEY_RightShift", "scroll_lock" => "KEY_ScrollLock", # "mod3" => "1", "mod4" => "2", "mod5" => "3", # "NULL" => "NULL", } def initialize layers @layers = layers.map do |key, type| raise "key not found: #{key}" if not Keys.include? key and not key.nil? raise "type not found: #{type}" if not Functions.include? type and not type.nil? # just fall through by default type = "transparent" if type.nil? and key.nil? key = Keys[key] || "NULL" up, down = Functions[type] || Functions["basic"] down ||= up Layer.new key, down, up end end end class Layout def initialize name, keys @name = name @keys = keys end def keys_to_matrix method Key::Layers.map.with_index do |_, layer| "KB_MATRIX_LAYER(\n#{@keys.map{|key| key.layers[layer].send(method)}.join(",\n")}),\n" end.join("\n") end def save! file puts "saving #{@name}..." header =<
#include #include #include "../../../lib/data-types/misc.h" #include "../../../lib/usb/usage-page/keyboard--short-names.h" #include "../../../lib/key-functions/public.h" #include "../matrix.h" #include "../layout.h" // ---------------------------------------------------------------------------- HEADER keys = keys_to_matrix :code downs = keys_to_matrix :down ups = keys_to_matrix :up File.save(LayoutFile) do |f| f.puts header f.puts "const uint8_t PROGMEM _kb_layout[KB_LAYERS][KB_ROWS][KB_COLUMNS] = { #{keys} };" f.puts "const void_funptr_t PROGMEM _kb_layout_press[KB_LAYERS][KB_ROWS][KB_COLUMNS] = { #{downs} };" f.puts "const void_funptr_t PROGMEM _kb_layout_release[KB_LAYERS][KB_ROWS][KB_COLUMNS] = { #{ups} };" end end end keys_string =< shifted ┃ " shifted ┃ ] ┃ ` ┃ ` # pun ┃ ┃ ┃ f21 ┃ f22 ┃ f23 ┃ f24 ┃ # nav ┃ ┃ ┃ ┃ ┃ ┃ ┃ # funk # ┰ s ┰ n ┰ r ┰ t ┰ d ┰ ◼ # ┃ s ┃ n ┃ r ┃ t ┃ d ┃ umlaut # basic ┃ ) shifted ┃ _ shifted ┃ / ┃ \} shifted ┃ . ┃ # pun ┃ ┃ f13 ┃ f14 ┃ f15 ┃ f16 ┃ # nav ┃ ┃ ┃ ┃ ┃ ┃ # funk # ┰ ◼ ┰ b ┰ ┰ j ┰ y ┰ ; ┰ ◼ # ┃ enter ┃ b ┃ m ┃ j ┃ y ┃ ; ┃ shift_r capslock # basic ┃ ┃ + shifted ┃ $ shifted ┃ & shifted ┃ hash shifted ┃ ^ shifted ┃ # pun ┃ ┃ ┃ f17 ┃ f18 ┃ f19 ┃ f20 ┃ # nav ┃ ┃ ┃ ┃ ┃ ┃ ┃ # funk ] [╳6 # R UNDERTHUMB (? to ?) # ┰ ◼ # ┃ mod4 mod4 # basic ┃ # pun ┃ # nav ┃ # funk ] [╳7 # R UNDER (? to ?) # ┰ ◼ ┰ ◼ ┰ ◼ ┰ ◼ # ┃ left ┃ up ┃ down ┃ right # basic ┃ ┃ ┃ ┃ # pun ┃ ┃ ┃ ┃ # nav ┃ ┃ ┃ ┃ # funk ] [╳8 # R THUMB (? to ?) # ┰ c3 ┰ b3 # ┃ ┃ # basic ┃ ┃ # pun ┃ ┃ # nav ┃ ┃ # funk # ┰ c2 ┰ b2* ┰ a2* # ┃ menu ┃ alt ┃ mod3 latch_mod3 # basic ┃ ┃ ┃ NULL # pun ┃ ┃ ┃ NULL # nav ┃ ┃ ┃ NULL # funk # ┰ c1 ┰ b1 ┰ a1 # ┃ menu ┃ alt ┃ mod3 latch_mod3 # basic ┃ ┃ ┃ NULL # pun ┃ ┃ ┃ NULL # nav ┃ ┃ ┃ NULL # funk ] EOL groups = keys_string.gsub(/#.*$/, '').split(/\[╳/).reject(&:blank?).map(&:lines) groups = groups.sort_by(&:first) groups = groups.map{|g| g.drop(1).reject(&:blank?)} keys_parsed = [ # dummy key Key::Layers.map{[]} ] groups.each do |group| layers = Key::Layers.size # sanity check raise "wrong number of key layers" if group.size % layers != 0 slices = group.map{|l| l.split("┃").drop(1)} (0..(group.size-1)).step(layers).each do |row| slices[row].size.times do |col| key = layers.times.map do |layer| slices[row+layer][col] end key = key.map{|l| l.strip.split(/\s+/, 2)} keys_parsed << key end end end keys = keys_parsed.map do |layers| Key.new layers end saneo = Layout.new :saneo, keys saneo.save! LayoutFile