Skip to content

Commit 3b3d0b0

Browse files
feat(layouts): add multi layout support
- add 2 layouts (dvorak, colemak) - add an example file to show demonstrate how config works
1 parent c08b8a5 commit 3b3d0b0

4 files changed

Lines changed: 176 additions & 2 deletions

File tree

.gitignore

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1 @@
1-
*.autosave.xopp
2-
*~
1+
config.lua

config.lua.example

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
-- Configuration for vi-xournalpp plugin
2+
-- Copy this file to config.lua and customize
3+
4+
local layouts = require('layouts')
5+
6+
-- Set your keyboard layout: 'qwerty', 'dvorak', or 'colemak'
7+
layouts.active_layout = 'qwerty'
8+
9+
-- Optional: Override specific keys
10+
-- layouts.key_overrides = {
11+
-- ['w'] = 'j',
12+
-- }
13+
14+
return layouts

layouts.lua

Lines changed: 126 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,126 @@
1+
-- Keyboard layout mappings for vi-xournalpp plugin
2+
-- This file contains default layout definitions
3+
-- To customize, copy config.lua.example to config.lua and modify it
4+
5+
local config = {}
6+
7+
-- Active keyboard layout
8+
-- Options: 'qwerty', 'dvorak', 'colemak', or your custom layout name
9+
config.active_layout = 'qwerty'
10+
11+
-- Custom key overrides (optional)
12+
-- Use this to override specific keys for your personal preference
13+
-- This applies AFTER layout mapping
14+
-- Example: config.key_overrides = { ['w'] = 'j', ['s'] = 'k' }
15+
config.key_overrides = {}
16+
17+
-- Keyboard layout mappings
18+
-- Maps QWERTY keys to their physical equivalents on other layouts
19+
-- This preserves hand movement and muscle memory across layouts
20+
config.layout_map = {
21+
qwerty = {},
22+
23+
dvorak = {
24+
['q'] = 'apostrophe',
25+
['w'] = 'comma',
26+
['e'] = 'period',
27+
['r'] = 'p',
28+
['t'] = 'y',
29+
['y'] = 'f',
30+
['u'] = 'g',
31+
['i'] = 'c',
32+
['o'] = 'r',
33+
['p'] = 'l',
34+
['a'] = 'a',
35+
['s'] = 'o',
36+
['d'] = 'e',
37+
['f'] = 'u',
38+
['g'] = 'i',
39+
['h'] = 'd',
40+
['j'] = 'h',
41+
['k'] = 't',
42+
['l'] = 'n',
43+
['z'] = 'semicolon',
44+
['x'] = 'q',
45+
['c'] = 'j',
46+
['v'] = 'k',
47+
['b'] = 'x',
48+
['n'] = 'b',
49+
['m'] = 'm',
50+
['comma'] = 'w',
51+
['period'] = 'v',
52+
['slash'] = 'z',
53+
['less'] = '<Shift>w',
54+
['greater'] = '<Shift>v',
55+
['question'] = '<Shift>z',
56+
},
57+
58+
colemak = {
59+
['q'] = 'q',
60+
['w'] = 'w',
61+
['e'] = 'f',
62+
['r'] = 'p',
63+
['t'] = 'g',
64+
['y'] = 'j',
65+
['u'] = 'l',
66+
['i'] = 'u',
67+
['o'] = 'y',
68+
['p'] = 'semicolon',
69+
['a'] = 'a',
70+
['s'] = 'r',
71+
['d'] = 's',
72+
['f'] = 't',
73+
['g'] = 'd',
74+
['h'] = 'h',
75+
['j'] = 'n',
76+
['k'] = 'e',
77+
['l'] = 'i',
78+
['z'] = 'z',
79+
['x'] = 'x',
80+
['c'] = 'c',
81+
['v'] = 'v',
82+
['b'] = 'b',
83+
['n'] = 'k',
84+
['m'] = 'm',
85+
},
86+
}
87+
88+
-- Helper function to map keys with modifiers dynamically
89+
function config.map_key(key, layout_map)
90+
if not key or key == '' or not layout_map then
91+
return key
92+
end
93+
94+
-- Extract modifiers and base key
95+
local modifiers = {}
96+
local base_key = key
97+
98+
for modifier in key:gmatch('<([^>]+)>') do
99+
table.insert(modifiers, modifier)
100+
end
101+
102+
-- Get base key (everything after last >)
103+
if #modifiers > 0 then
104+
base_key = key:match('[^>]+$') or ''
105+
end
106+
107+
if base_key == '' then
108+
return key
109+
end
110+
111+
-- Map the base key
112+
local mapped_base = layout_map[base_key] or base_key
113+
114+
-- Reconstruct with modifiers
115+
if #modifiers > 0 then
116+
local result = ''
117+
for _, mod in ipairs(modifiers) do
118+
result = result .. '<' .. mod .. '>'
119+
end
120+
return result .. mapped_base
121+
end
122+
123+
return mapped_base
124+
end
125+
126+
return config

main.lua

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,41 @@ require('modes')
33

44
f = {}
55

6+
-- Apply config if it exists
7+
local function apply_config()
8+
local success, config = pcall(require, 'config')
9+
if not success or type(config) ~= 'table' then
10+
if success and type(config) ~= 'table' then
11+
print('vi-xournalpp: config.lua exists but does not return a table')
12+
end
13+
return
14+
end
15+
16+
local layout = config.active_layout or 'qwerty'
17+
local layout_map = config.layout_map and config.layout_map[layout]
18+
local key_overrides = config.key_overrides or {}
19+
20+
if not layout_map and layout ~= 'qwerty' then
21+
print("vi-xournalpp: Unknown layout '" .. layout .. "', using qwerty.")
22+
layout_map = config.layout_map and config.layout_map.qwerty
23+
end
24+
25+
for _, binding in pairs(keybindings) do
26+
local new_buttons = {}
27+
for _, button in ipairs(binding.buttons) do
28+
local mapped_button = button
29+
if layout_map and layout ~= 'qwerty' then
30+
mapped_button = config.map_key(button, layout_map)
31+
end
32+
mapped_button = key_overrides[mapped_button] or mapped_button
33+
table.insert(new_buttons, mapped_button)
34+
end
35+
binding.buttons = new_buttons
36+
end
37+
end
38+
39+
apply_config()
40+
641
function initUi()
742
index = 1
843
for _, binding in pairs(keybindings) do

0 commit comments

Comments
 (0)