diff options
author | Jaakko Keränen <jaakko.keranen@iki.fi> | 2021-03-03 11:57:40 +0200 |
---|---|---|
committer | Jaakko Keränen <jaakko.keranen@iki.fi> | 2021-03-03 11:58:51 +0200 |
commit | 5b1b19d6d0e07103cdeb8df2dcd838fe67a923cd (patch) | |
tree | 6509e3f70c9fb23f6575cbcf5a35754635e5d27c | |
parent | 12630f504b022b0718655a615d2fbb1d045ded18 (diff) |
Load keyboard modifier mapping from modmap.txt
IssueID #87
-rw-r--r-- | src/app.c | 9 | ||||
-rw-r--r-- | src/ui/keys.c | 68 | ||||
-rw-r--r-- | src/ui/window.c | 7 |
3 files changed, 77 insertions, 7 deletions
@@ -896,6 +896,15 @@ void processEvents_App(enum iAppEventMode eventMode) { | |||
896 | d->isIdling = iFalse; | 896 | d->isIdling = iFalse; |
897 | #endif | 897 | #endif |
898 | gotEvents = iTrue; | 898 | gotEvents = iTrue; |
899 | /* Keyboard modifier mapping. */ { | ||
900 | if (ev.type == SDL_KEYDOWN || ev.type == SDL_KEYUP) { | ||
901 | /* Track Caps Lock state as a modifier. */ | ||
902 | if (ev.key.keysym.sym == SDLK_CAPSLOCK) { | ||
903 | setCapsLockDown_Keys(ev.key.state == SDL_PRESSED); | ||
904 | } | ||
905 | ev.key.keysym.mod = mapMods_Keys(ev.key.keysym.mod & ~KMOD_CAPS); | ||
906 | } | ||
907 | } | ||
899 | iBool wasUsed = processEvent_Window(d->window, &ev); | 908 | iBool wasUsed = processEvent_Window(d->window, &ev); |
900 | if (!wasUsed) { | 909 | if (!wasUsed) { |
901 | /* There may be a key bindings for this. */ | 910 | /* There may be a key bindings for this. */ |
diff --git a/src/ui/keys.c b/src/ui/keys.c index ce80d9f0..60f06f77 100644 --- a/src/ui/keys.c +++ b/src/ui/keys.c | |||
@@ -43,6 +43,29 @@ enum iModMap { | |||
43 | max_ModMap | 43 | max_ModMap |
44 | }; | 44 | }; |
45 | 45 | ||
46 | static const char *modToStr_[max_ModMap] = { | ||
47 | "none", | ||
48 | "Lshift", | ||
49 | "Lctrl", | ||
50 | "Lalt", | ||
51 | "Lgui", | ||
52 | "Rshift", | ||
53 | "Rctrl", | ||
54 | "Ralt", | ||
55 | "Rgui", | ||
56 | "caps", | ||
57 | }; | ||
58 | |||
59 | static int strToMod_(iRangecc str) { | ||
60 | trim_Rangecc(&str); | ||
61 | for (int i = 0; i < max_ModMap; i++) { | ||
62 | if (equalCase_Rangecc(str, modToStr_[i])) { | ||
63 | return i; | ||
64 | } | ||
65 | } | ||
66 | return none_ModMap; | ||
67 | } | ||
68 | |||
46 | static int modMap_[max_ModMap]; | 69 | static int modMap_[max_ModMap]; |
47 | static iBool capsLockDown_; | 70 | static iBool capsLockDown_; |
48 | 71 | ||
@@ -87,6 +110,50 @@ void setCapsLockDown_Keys(iBool isDown) { | |||
87 | capsLockDown_ = isDown; | 110 | capsLockDown_ = isDown; |
88 | } | 111 | } |
89 | 112 | ||
113 | static void loadModMap_Keys_(const char *saveDir) { | ||
114 | iFile *f = iClob(newCStr_File(concatPath_CStr(saveDir, "modmap.txt"))); | ||
115 | if (open_File(f, readOnly_FileMode | text_FileMode)) { | ||
116 | const iString *text = collect_String(readString_File(f)); | ||
117 | iRangecc textLine = iNullRange; | ||
118 | while (nextSplit_Rangecc(range_String(text), "\n", &textLine)) { | ||
119 | iRangecc line = textLine; | ||
120 | trim_Rangecc(&line); | ||
121 | if (isEmpty_Range(&line) || startsWith_Rangecc(line, "#")) { | ||
122 | continue; /* comment */ | ||
123 | } | ||
124 | iRangecc seg = iNullRange; | ||
125 | if (nextSplit_Rangecc(line, "->", &seg)) { | ||
126 | const int fromMod = strToMod_(seg); | ||
127 | if (fromMod && nextSplit_Rangecc(line, "->", &seg)) { | ||
128 | const int toMod = strToMod_(seg); | ||
129 | modMap_[fromMod] = toMod; | ||
130 | } | ||
131 | } | ||
132 | } | ||
133 | close_File(f); | ||
134 | } | ||
135 | else { | ||
136 | open_File(f, writeOnly_FileMode | text_FileMode); | ||
137 | printf_Stream(stream_File(f), | ||
138 | "# This is a translation table for keyboard modifiers. The syntax is:\n" | ||
139 | "#\n" | ||
140 | "# (hardware key) -> (effective modifier)\n" | ||
141 | "#\n" | ||
142 | "# A modifier can be mapped to \"none\" to disable it. For example:\n" | ||
143 | "#\n" | ||
144 | "# Lalt -> none\n" | ||
145 | "#\n" | ||
146 | "# When using CapsLock as a modifier key, its toggled state will still affect\n" | ||
147 | "# text entry. You may need to remap or disable CapsLock in your window system.\n" | ||
148 | "#\n" | ||
149 | "# You may delete this file and it will be recreated with the default mapping.\n\n"); | ||
150 | for (int i = 1; i < max_ModMap; i++) { | ||
151 | printf_Stream(stream_File(f), "%s -> %s\n", modToStr_[i], modToStr_[i]); | ||
152 | } | ||
153 | close_File(f); | ||
154 | } | ||
155 | } | ||
156 | |||
90 | /*----------------------------------------------------------------------------------------------*/ | 157 | /*----------------------------------------------------------------------------------------------*/ |
91 | 158 | ||
92 | iDeclareType(Keys) | 159 | iDeclareType(Keys) |
@@ -270,6 +337,7 @@ void deinit_Keys(void) { | |||
270 | 337 | ||
271 | void load_Keys(const char *saveDir) { | 338 | void load_Keys(const char *saveDir) { |
272 | iKeys *d = &keys_; | 339 | iKeys *d = &keys_; |
340 | loadModMap_Keys_(saveDir); | ||
273 | iFile *f = iClob(newCStr_File(concatPath_CStr(saveDir, filename_Keys_))); | 341 | iFile *f = iClob(newCStr_File(concatPath_CStr(saveDir, filename_Keys_))); |
274 | if (open_File(f, readOnly_FileMode | text_FileMode)) { | 342 | if (open_File(f, readOnly_FileMode | text_FileMode)) { |
275 | iBlock * src = collect_Block(readAll_File(f)); | 343 | iBlock * src = collect_Block(readAll_File(f)); |
diff --git a/src/ui/window.c b/src/ui/window.c index bfa95f90..fb5daa80 100644 --- a/src/ui/window.c +++ b/src/ui/window.c | |||
@@ -1596,13 +1596,6 @@ iBool processEvent_Window(iWindow *d, const SDL_Event *ev) { | |||
1596 | As a workaround, ignore these events. */ | 1596 | As a workaround, ignore these events. */ |
1597 | return iTrue; /* won't go to bindings, either */ | 1597 | return iTrue; /* won't go to bindings, either */ |
1598 | } | 1598 | } |
1599 | /* Apply keyboard modifier mapping. */ | ||
1600 | if (event.type == SDL_KEYDOWN || event.type == SDL_KEYUP) { | ||
1601 | if (event.key.keysym.sym == SDLK_CAPSLOCK) { | ||
1602 | setCapsLockDown_Keys(event.key.state == SDL_PRESSED); | ||
1603 | } | ||
1604 | event.key.keysym.mod = mapMods_Keys(event.key.keysym.mod & ~KMOD_CAPS); | ||
1605 | } | ||
1606 | if (event.type == SDL_MOUSEBUTTONDOWN && d->ignoreClick) { | 1599 | if (event.type == SDL_MOUSEBUTTONDOWN && d->ignoreClick) { |
1607 | d->ignoreClick = iFalse; | 1600 | d->ignoreClick = iFalse; |
1608 | return iTrue; | 1601 | return iTrue; |