ckb-next  beta-v0.2.8 at branch testing
ckb-next driver for corsair devices
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
keymap.cpp
Go to the documentation of this file.
1 #include <clocale>
2 #include <QMap>
3 #include "keymap.h"
4 
5 // Normal key size
6 #define NS 12, 12
7 
8 // Key positions (K95 - English)
9 // This is the master key map that includes both ANSI and ISO layouts - use ansiPatch() or isoPatch() to finalize it
10 static const Key K95Keys[] = {
11  {0, 0, "mr", 38, 0, NS, true, true}, {0, 0, "m1", 50, 0, NS, true, true}, {0, 0, "m2", 62, 0, NS, true, true}, {0, 0, "m3", 74, 0, NS, true, true}, {0, "Brightness", "light", 222, 0, NS, true, true}, {0, "Windows Lock", "lock", 234, 0, NS, true, true}, {0, "Mute", "mute", 273, 0, 13, 8, true, true}, {0, "Volume Up", "volup", 290, -2, 18, 6, false, true}, {0, "Volume down", "voldn", 290, 2, 18, 6, false, true},
12  {0, 0, "g1", 0, 14, NS, true, true}, {0, 0, "g2", 11, 14, NS, true, true}, {0, 0, "g3", 22, 14, NS, true, true}, {0, "Esc", "esc", 38, 14, NS, true, true}, {0, 0, "f1", 58, 14, NS, true, true}, {0, 0, "f2", 70, 14, NS, true, true}, {0, 0, "f3", 82, 14, NS, true, true}, {0, 0, "f4", 94, 14, NS, true, true}, {0, 0, "f5", 114, 14, NS, true, true}, {0, 0, "f6", 126, 14, NS, true, true}, {0, 0, "f7", 138, 14, NS, true, true}, {0, 0, "f8", 150, 14, NS, true, true}, {0, 0, "f9", 170, 14, NS, true, true}, {0, 0, "f10", 182, 14, NS, true, true}, {0, 0, "f11", 194, 14, NS, true, true}, {0, 0, "f12", 206, 14, NS, true, true}, {0, "Print Screen\nSysRq", "prtscn", 222, 14, NS, true, true}, {0, "Scroll Lock", "scroll", 234, 14, NS, true, true}, {0, "Pause\nBreak", "pause", 246, 14, NS, true, true}, {0, "Stop", "stop", 262, 14, 12, 8, true, true}, {0, "Previous", "prev", 273, 14, 13, 8, true, true}, {0, "Play/Pause", "play", 285, 14, 13, 8, true, true}, {0, "Next", "next", 296, 14, 12, 8, true, true},
13  {0, 0, "g4", 0, 25, NS, true, true}, {0, 0, "g5", 11, 25, NS, true, true}, {0, 0, "g6", 22, 25, NS, true, true}, {0, "`", "grave", 38, 27, NS, true, true}, {0, 0, "1", 50, 27, NS, true, true}, {0, 0, "2", 62, 27, NS, true, true}, {0, 0, "3", 74, 27, NS, true, true}, {0, 0, "4", 86, 27, NS, true, true}, {0, 0, "5", 98, 27, NS, true, true}, {0, 0, "6", 110, 27, NS, true, true}, {0, 0, "7", 122, 27, NS, true, true}, {0, 0, "8", 134, 27, NS, true, true}, {0, 0, "9", 146, 27, NS, true, true}, {0, 0, "0", 158, 27, NS, true, true}, {0, "-", "minus", 170, 27, NS, true, true}, {0, "=", "equal", 182, 27, NS, true, true}, {0, "Backspace", "bspace", 200, 27, 24, 12, true, true}, {0, "Insert", "ins", 222, 27, NS, true, true}, {0, "Home", "home", 234, 27, NS, true, true}, {0, "Page Up", "pgup", 246, 27, NS, true, true}, {0, "Num Lock", "numlock", 261, 27, NS, true, true}, {0, "NumPad /", "numslash", 273, 27, NS, true, true}, {0, "NumPad *", "numstar", 285, 27, NS, true, true}, {0, "NumPad -", "numminus", 297, 27, NS, true, true},
14  {0, 0, "g7", 0, 39, NS, true, true}, {0, 0, "g8", 11, 39, NS, true, true}, {0, 0, "g9", 22, 39, NS, true, true}, {0, "Tab", "tab", 41, 39, 18, 12, true, true}, {0, 0, "q", 56, 39, NS, true, true}, {0, 0, "w", 68, 39, NS, true, true}, {0, 0, "e", 80, 39, NS, true, true}, {0, 0, "r", 92, 39, NS, true, true}, {0, 0, "t", 104, 39, NS, true, true}, {0, 0, "y", 116, 39, NS, true, true}, {0, 0, "u", 128, 39, NS, true, true}, {0, 0, "i", 140, 39, NS, true, true}, {0, 0, "o", 152, 39, NS, true, true}, {0, 0, "p", 164, 39, NS, true, true}, {0, "[", "lbrace", 176, 39, NS, true, true}, {0, "]", "rbrace", 188, 39, NS, true, true}, {0, "\\", "bslash", 203, 39, 18, 12, true, true}, {0, "Enter", "enter", 203, 39, 18, 24, true, true}, {0, "Delete", "del", 222, 39, NS, true, true}, {0, "End", "end", 234, 39, NS, true, true}, {0, "Page Down", "pgdn", 246, 39, NS, true, true}, {0, "NumPad 7", "num7", 261, 39, NS, true, true}, {0, "NumPad 8", "num8", 273, 39, NS, true, true}, {0, "NumPad 9", "num9", 285, 39, NS, true, true}, {0, "NumPad +", "numplus", 297, 45, 12, 24, true, true},
15  {0, 0, "g10", 0, 50, NS, true, true}, {0, 0, "g11", 11, 50, NS, true, true}, {0, 0, "g12", 22, 50, NS, true, true}, {0, "Caps Lock", "caps", 42, 51, 20, 12, true, true}, {0, 0, "a", 59, 51, NS, true, true}, {0, 0, "s", 71, 51, NS, true, true}, {0, 0, "d", 83, 51, NS, true, true}, {0, 0, "f", 95, 51, NS, true, true}, {0, 0, "g", 107, 51, NS, true, true}, {0, 0, "h", 119, 51, NS, true, true}, {0, 0, "j", 131, 51, NS, true, true}, {0, 0, "k", 143, 51, NS, true, true}, {0, 0, "l", 155, 51, NS, true, true}, {0, ";", "colon", 167, 51, NS, true, true}, {0, "'", "quote", 179, 51, NS, true, true}, {0, "#", "hash", 191, 51, NS, true, true}, {0, "NumPad 4", "num4", 261, 51, NS, true, true}, {0, "NumPad 5", "num5", 273, 51, NS, true, true}, {0, "NumPad 6", "num6", 285, 51, NS, true, true},
16  {0, 0, "g13", 0, 64, NS, true, true}, {0, 0, "g14", 11, 64, NS, true, true}, {0, 0, "g15", 22, 64, NS, true, true}, {0, "Left Shift", "lshift", 39, 63, 14, 12, true, true}, {"bslash", "\\", "bslash_iso", 53, 63, NS, true, true}, {0, 0, "z", 65, 63, NS, true, true}, {0, 0, "x", 77, 63, NS, true, true}, {0, 0, "c", 89, 63, NS, true, true}, {0, 0, "v", 101, 63, NS, true, true}, {0, 0, "b", 113, 63, NS, true, true}, {0, 0, "n", 125, 63, NS, true, true}, {0, 0, "m", 137, 63, NS, true, true}, {0, ",", "comma", 149, 63, NS, true, true}, {0, ".", "dot", 161, 63, NS, true, true}, {0, "/", "slash", 173, 63, NS, true, true}, {0, "Right Shift", "rshift", 196, 63, 32, 12, true, true}, {0, "Up", "up", 234, 63, NS, true, true}, {0, "NumPad 1", "num1", 261, 63, NS, true, true}, {0, "NumPad 2", "num2", 273, 63, NS, true, true}, {0, "NumPad 3", "num3", 285, 63, NS, true, true}, {0, "NumPad Enter", "numenter", 297, 69, 12, 24, true, true},
17  {0, 0, "g16", 0, 75, NS, true, true}, {0, 0, "g17", 11, 75, NS, true, true}, {0, 0, "g18", 22, 75, NS, true, true}, {0, "Left Ctrl", "lctrl", 40, 75, 16, 12, true, true}, {0, "Left Windows", "lwin", 54, 75, NS, true, true}, {0, "Left Alt", "lalt", 67, 75, 14, 12, true, true}, {0, "Space", "space", 116, 75, 84, 12, true, true}, {0, "Right Alt", "ralt", 165, 75, 14, 12, true, true}, {0, "Right Windows", "rwin", 178, 75, NS, true, true}, {0, "Menu", "rmenu", 190, 75, NS, true, true}, {0, "Right Ctrl", "rctrl", 204, 75, 16, 12, true, true}, {0, "Left", "left", 222, 75, NS, true, true}, {0, "Down", "down", 234, 75, NS, true, true}, {0, "Right", "right", 246, 75, NS, true, true}, {0, "NumPad 0", "num0", 267, 75, 24, 12, true, true}, {0, "NumPad .", "numdot", 285, 75, NS, true, true}
18 };
19 #define KEYCOUNT_K95 (sizeof(K95Keys) / sizeof(Key))
20 
21 // ANSI layouts use a different Enter/LShift key
22 #define ANSI_ENTER_X 199
23 #define ANSI_ENTER_Y 51
24 #define ANSI_ENTER_W 26
25 #define ANSI_ENTER_H 12
26 #define ANSI_LSHIFT_X 45
27 #define ANSI_LSHIFT_W 26
28 
29 // Layout "patches" for different regions
30 struct KeyPatch {
31  const char* _storageName;
32  const char* _friendlyName;
33  const char* name;
34 };
35 
36 static const KeyPatch patchDK[] = {
37  {0, "§", "grave"}, {0, "+", "minus"}, {0, "´", "equal"},
38  {0, "Å", "lbrace"}, {0, "¨", "rbrace"},
39  {0, "Æ", "colon"}, {0, "Ø", "quote"}, {0, "'", "hash"},
40  {0, "<", "bslash_iso"}, {0, "-", "slash"},
41 };
42 
43 static const KeyPatch patchEU[] = {
44  {0, "\\ (R)", "hash"},
45  {0, "\\ (L)", "bslash_iso"}
46 };
47 
48 static const KeyPatch patchFR[] = {
49  {"sup2", "²", "grave"}, {0, "&", "1"}, {0, "É", "2"}, {0, "\"", "3"}, {0, "'", "4"}, {0, "(", "5"}, {0, "-", "6"}, {0, "È", "7"}, {0, "_", "8"}, {0, "Ç", "9"}, {0, "À", "0"}, {"rparen", ")", "minus"},
50  {"a", "A", "q"}, {"z", "Z", "w"}, {"caret", "^", "lbrace"}, {"dollar", "$", "rbrace"},
51  {"q", "Q", "a"}, {"m", "M", "colon"}, {"percent", "Ù", "quote"}, {"star", "*", "hash"},
52  {"angle", "<", "bslash_iso"}, {"w", "W", "z"}, {"comma", ",", "m"}, {"semicolon", ";", "comma"}, {"colon", ":", "dot"}, {"exclam", "!", "slash"},
53 };
54 
55 static const KeyPatch patchDE[] = {
56  {"caret", "^", "grave"}, {"ss", "ß", "minus"}, {"grave", "´", "equal"},
57  {"z", "Z", "y"}, {"ue", "Ü", "lbrace"}, {"plus", "+", "rbrace"},
58  {"oe", "Ö", "colon"}, {"ae", "Ä", "quote"},
59  {"angle", "<", "bslash_iso"}, {"y", "Y", "z"}, {"minus", "-", "slash"}
60 };
61 
62 static const KeyPatch patchIT[] = {
63  {0, "\\", "grave"}, {0, "'", "minus"}, {0, "Ì", "equal"},
64  {0, "È", "lbrace"}, {0, "+", "rbrace"},
65  {0, "Ò", "colon"}, {0, "À", "quote"}, {0, "Ù", "hash"},
66  {0, "<", "bslash_iso"}, {0, "-", "slash"},
67 };
68 
69 static const KeyPatch patchNO[] = {
70  {0, "§", "grave"}, {0, "+", "minus"}, {0, "´", "equal"},
71  {0, "Å", "lbrace"}, {0, "¨", "rbrace"},
72  {0, "Ø", "colon"}, {0, "Æ", "quote"}, {0, "'", "hash"},
73  {0, "<", "bslash_iso"}, {0, "-", "slash"},
74 };
75 
76 static const KeyPatch patchMX[] = {
77  {0, "|", "grave"}, {0, "'", "minus"}, {0, "¿", "equal"},
78  {0, "´", "lbrace"}, {0, "+", "rbrace"},
79  {0, "Ñ", "colon"}, {0, "{", "quote"}, {0, "}", "hash"},
80  {0, "<", "bslash_iso"}, {0, "-", "slash"},
81 };
82 
83 static const KeyPatch patchES[] = {
84  {"oa", "º", "grave"}, {"quote", "'", "minus"}, {"lexclam", "¡", "equal"},
85  {"grave", "`", "lbrace"}, {"plus", "+", "rbrace"},
86  {"nn", "Ñ", "colon"}, {"accent", "´", "quote"}, {"cc", "Ç", "hash"},
87  {"angle", "<", "bslash_iso"}, {"minus", "-", "slash"},
88 };
89 
90 static const KeyPatch patchSE[] = {
91  {"section", "§", "grave"}, {"plus", "+", "minus"}, {"grave", "´", "equal"},
92  {"aa", "Å", "lbrace"}, {"umlaut", "¨", "rbrace"},
93  {"oe", "Ö", "colon"}, {"ae", "Ä", "quote"}, {"quote", "'", "hash"},
94  {"angle", "<", "bslash_iso"}, {"minus", "-", "slash"},
95 };
96 
97 static const KeyPatch patchDvorak[] = {
98  {0, "[", "minus"}, {0, "]", "equal"},
99  {0, "'", "q"}, {0, ",", "w"}, {0, ".", "e"}, {0, "P", "r"}, {0, "Y", "t"}, {0, "F", "y"}, {0, "G", "u"}, {0, "C", "i"}, {0, "R", "o"}, {0, "L", "p"}, {0, "/", "lbrace"}, {0, "=", "rbrace"},
100  {0, "O", "s"}, {0, "E", "d"}, {0, "U", "f"}, {0, "I", "g"}, {0, "D", "h"}, {0, "H", "j"}, {0, "T", "k"}, {0, "N", "l"}, {0, "S", "colon"}, {0, "-", "quote"},
101  {0, ";", "z"}, {0, "Q", "x"}, {0, "J", "c"}, {0, "K", "v"}, {0, "X", "b"}, {0, "B", "n"}, {0, "W", "comma"}, {0, "V", "dot"}, {0, "Z", "slash"},
102 };
103 
104 // Apply a patch to a key map
105 #define PATCH_COUNT(patch) (sizeof(patch) / sizeof(KeyPatch))
106 #define patch(map, patches) _patch(map, patches, PATCH_COUNT(patches))
107 static void _patch(QHash<QString, Key>& map, const KeyPatch* patches, int patchCount){
108  for(const KeyPatch* p = patches; p < patches + patchCount; p++){
109  Key& key = map[p->name];
110  key._storageName = p->_storageName;
111  key._friendlyName = p->_friendlyName;
112  }
113 }
114 
115 // Patch a key map for ANSI/ISO layout
116 static void patchISO(QHash<QString, Key>& map){
117  map.remove("bslash");
118 }
119 static void patchANSI(QHash<QString, Key>& map){
120  map.remove("bslash_iso");
121  map.remove("hash");
122  Key& enter = map["enter"];
123  enter.x = ANSI_ENTER_X;
124  enter.y = ANSI_ENTER_Y;
125  enter.width = ANSI_ENTER_W;
126  enter.height = ANSI_ENTER_H;
127  Key& lshift = map["lshift"];
128  lshift.x = ANSI_LSHIFT_X;
129  lshift.width = ANSI_LSHIFT_W;
130 }
131 
132 // Total width/height
133 #define K95_WIDTH 298
134 #define K95_HEIGHT 76
135 
136 // K70 cuts off the G keys on the left, as well as MR/M1/M2/M3
137 #define K70_X_START 38
138 #define K70_WIDTH (K95_WIDTH - K70_X_START)
139 #define K70_HEIGHT K95_HEIGHT
140 
141 // K65 additionally removes the numpad on the right, and has a different top row
142 #define K65_WIDTH 209
143 #define K65_HEIGHT K70_HEIGHT
144 
145 static const Key K65TopRow[] = {
146  {0, "Brightness", "light", 164 - K70_X_START, 0, 12, 12, true, true}, {0, "Mute", "mute", 176 - K70_X_START, 0, 12, 12, true, true}, {0, "Volume Down", "voldn", 192 - K70_X_START, 0, 14, 8, true, true}, {0, "Volume Up", "volup", 205 - K70_X_START, 0, 14, 8, true, true}, {0, "Windows Lock", "lock", 222 - K70_X_START, 0, 12, 12, true, true}
147 };
148 #define K65_TOP_COUNT (sizeof(K65TopRow) / sizeof(Key))
149 
150 // Strafe has side lights
151 #define KSTRAFE_X_START 12
152 #define KSTRAFE_WIDTH (K70_WIDTH + (KSTRAFE_X_START * 2))
153 #define KSTRAFE_HEIGHT K95_HEIGHT
154 
155 static const Key KStrafeKeys[] = {
156  {0, "Sidelight", "lsidel", 0, KSTRAFE_HEIGHT/2, KSTRAFE_X_START, KSTRAFE_HEIGHT, true, false},
157  {0, "Sidelight", "rsidel", KSTRAFE_WIDTH, KSTRAFE_HEIGHT/2, KSTRAFE_X_START, KSTRAFE_HEIGHT, true, false},
158  {0, "Logo", "logo", KSTRAFE_X_START, 0, NS, true, false},
159  {0, "Function", "fn", 152, 75, NS, true, true}
160 };
161 
162 // Mouse map - M65
163 static const Key M65Keys[] = {
164  {0, "Left Mouse", "mouse1", 8, 0, 14, 32, false, true}, {0, "Right Mouse", "mouse2", 30, 0, 14, 32, false, true}, {0, "Middle Mouse", "mouse3", 22, 8, 8, 7, false, true},
165  {0, "Wheel Up", "wheelup", 22, 4, 8, 5, false, true}, {0, "Wheel Down", "wheeldn", 22, 14, 8, 5, false, true}, {0, "Wheel Light", "front", 22, 15, 8, 8, true, false},
166  {0, "DPI Up", "dpiup", 22, 19, 8, 6, false, true}, {0, "DPI Light", "dpi", 22, 24, 8, 8, true, false}, {0, "DPI Down", "dpidn", 22, 31, 8, 6, false, true},
167  {0, "Forward", "mouse5", 5, 24, 5, 9, false, true}, {0, "Back", "mouse4", 5, 33, 5, 10, false, true}, {0, "Sniper", "sniper", 0, 25, 5, 15, false, true},
168  {0, "Logo", "back", 14, 55, 24, 12, true, false}
169 };
170 #define KEYCOUNT_M65 (sizeof(M65Keys) / sizeof(Key))
171 
172 #define M65_WIDTH 52
173 #define M65_HEIGHT 67
174 
175 // Sabre
176 static const Key SabreKeys[] = {
177  {0, "Left Mouse", "mouse1", 8, 0, 14, 32, false, true}, {0, "Right Mouse", "mouse2", 30, 0, 14, 32, false, true}, {0, "Middle Mouse", "mouse3", 22, 9, 8, 7, false, true}, {0, "Front light", "front", 8, -2, 14, 8, true, false },
178  {0, "Wheel Up", "wheelup", 22, 5, 8, 5, false, true}, {0, "Wheel Down", "wheeldn", 22, 15, 8, 5, false, true}, {0, "Wheel Light", "wheel", 22, 5, 8, 15, true, false}, {0, "Extra button", "thumb1", 22, 20, 8, 18, false, true},
179  {0, "DPI Up", "dpiup", 5, 3, 5, 7, false, true}, {0, "DPI Down", "dpidn", 5, 10, 5, 7, false, true}, {0, "DPI Light", "dpi", 5, 4, 5, 12, true, false},
180  {0, "Forward", "mouse5", 5, 24, 5, 9, false, true}, {0, "Back", "mouse4", 5, 33, 5, 10, false, true},
181  {0, "Logo", "back", 14, 50, 24, 12, true, false}
182 };
183 #define KEYCOUNT_SABRE (sizeof(SabreKeys) / sizeof(Key))
184 
185 #define SABRE_WIDTH M65_WIDTH
186 #define SABRE_HEIGHT M65_HEIGHT
187 
188 // Scimitar
189 static const Key ScimKeys[] = {
190  {0, "Left Mouse", "mouse1", 8, 0, 14, 32, false, true}, {0, "Right Mouse", "mouse2", 30, 0, 12, 32, false, true}, {0, "Middle Mouse", "mouse3", 22, 9, 8, 6, false, true}, {0, "Front light", "front", 30, 0, 12, 8, true, false },
191  {0, "Wheel Up", "wheelup", 22, 3, 8, 6, false, true}, {0, "Wheel Down", "wheeldn", 22, 14, 8, 6, false, true}, {0, "Wheel Light", "wheel", 22, 3, 8, 17, true, false},
192  {0, "DPI Up", "dpiup", 22, 19, 8, 9, false, true}, {0, "DPI Light", "dpi", 1, 12, 8, 4, true, false}, {0, "DPI Down", "dpidn", 22, 28, 8, 9, false, true},
193  {0, "Thumb light", "thumb", 0, 21, 10, 24, true, false},
194  {0, "1", "thumb1", -13, 18, 7, 7, false, true}, {0, "2", "thumb2", -6, 18, 7, 7, false, true}, {0, "3", "thumb3", 1, 18, 7, 7, false, true},
195  {0, "4", "thumb4", -13, 25, 7, 7, false, true}, {0, "5", "thumb5", -6, 25, 7, 7, false, true}, {0, "6", "thumb6", 1, 25, 7, 7, false, true},
196  {0, "7", "thumb7", -13, 32, 7, 7, false, true}, {0, "8", "thumb8", -6, 32, 7, 7, false, true}, {0, "9", "thumb9", 1, 32, 7, 7, false, true},
197  {0, "10", "thumb10", -13, 39, 7, 7, false, true}, {0, "11", "thumb11", -6, 39, 7, 7, false, true}, {0, "12", "thumb12", 1, 39, 7, 7, false, true},
198  {0, "Logo", "back", 14, 50, 24, 16, true, false}
199 };
200 #define KEYCOUNT_SCIM (sizeof(ScimKeys) / sizeof(Key))
201 
202 #define SCIM_WIDTH M65_WIDTH
203 #define SCIM_HEIGHT M65_HEIGHT
204 
205 // Map getter. Each model/layout pair only needs to be constructed once; after that, future KeyMaps can copy the existing maps.
206 #define N_MODELS KeyMap::_MODEL_MAX
207 #define N_LAYOUTS KeyMap::_LAYOUT_MAX
208 static QHash<QString, Key> K95BaseMap;
209 static QHash<QString, Key> standardMaps[N_MODELS][N_LAYOUTS];
210 static QHash<QString, Key> getMap(KeyMap::Model model, KeyMap::Layout layout){
211  if(model < 0 || layout < 0 || model >= N_MODELS || layout >= N_LAYOUTS)
212  return QHash<QString, Key>();
213  // Return the map if it's already filled out
214  QHash<QString, Key>& map = standardMaps[model][layout];
215  if(!map.empty())
216  return map;
217  // Otherwise, create it
218  switch(model){
219  case KeyMap::K95:{
220  // The K95 maps serve as bases for all the other keyboards
221  // Fetch the master map, or create it if not yet done
222  if(K95BaseMap.empty()){
223  for(const Key* key = K95Keys; key < K95Keys + KEYCOUNT_K95; key++)
224  K95BaseMap[key->name] = *key;
225  }
226  map = K95BaseMap;
227  // Patch the map for the layout
228  switch(layout){
229  case KeyMap::DK:
230  patch(map, patchDK);
231  break;
232  case KeyMap::EU_DVORAK:
233  patch(map, patchDvorak); // fall through
234  case KeyMap::EU:
235  patch(map, patchEU);
236  break;
237  case KeyMap::GB_DVORAK:
238  case KeyMap::US_DVORAK:
239  patch(map, patchDvorak);
240  break;
241  case KeyMap::FR:
242  patch(map, patchFR);
243  break;
244  case KeyMap::DE:
245  patch(map, patchDE);
246  break;
247  case KeyMap::IT:
248  patch(map, patchIT);
249  break;
250  case KeyMap::NO:
251  patch(map, patchNO);
252  break;
253  case KeyMap::MX:
254  patch(map, patchMX);
255  break;
256  case KeyMap::ES:
257  patch(map, patchES);
258  break;
259  case KeyMap::SE:
260  patch(map, patchSE);
261  break;
262  default:;
263  // English QWERTY - no patch needed
264  }
265  if(KeyMap::isISO(layout))
266  patchISO(map);
267  else
268  patchANSI(map);
269  // Done! return the map
270  break;
271  }
272  case KeyMap::K70:{
273  // The K70 maps are based on the K95 maps. However all the keys are shifted left and the G keys are removed
274  map = getMap(KeyMap::K95, layout);
275  QMutableHashIterator<QString, Key> i(map);
276  while(i.hasNext()){
277  i.next();
278  // Move key to left. Remove it if it fell off the edge
279  if((i.value().x -= K70_X_START) < 0)
280  i.remove();
281  }
282  // Remove the M buttons as well
283  map.remove("mr");
284  map.remove("m1");
285  map.remove("m2");
286  map.remove("m3");
287  // Done!
288  break;
289  }
290  case KeyMap::K65:{
291  // The K65 maps additionally remove the numpad and have a modified top row
292  map = getMap(KeyMap::K70, layout);
293  QMutableHashIterator<QString, Key> i(map);
294  while(i.hasNext()){
295  i.next();
296  if(i.value().x >= K65_WIDTH)
297  i.remove();
298  }
299  for(const Key* key = K65TopRow; key < K65TopRow + K65_TOP_COUNT; key++)
300  map[key->name] = *key;
301  // Done!
302  break;
303  }
304  case KeyMap::STRAFE:{
305  // The Strafe RGB maps are based on the K70 map minus the media keys
306  map = getMap(KeyMap::K70, layout);
307  //move light and lock right
308  map["light"].x=285 - K70_X_START;
309  //map["light"].hasLed=false;
310  map["lock"].x=297 - K70_X_START;
311  //map["lock"].hasLed=false;
312  // move everything right to make the space for the left sidelight
313  QMutableHashIterator<QString, Key> i(map);
314  while(i.hasNext()){
315  i.next();
316  i.value().x += KSTRAFE_X_START;
317  }
318  // Add Strafe lights and keys
319  map["lsidel"] = KStrafeKeys[0];
320  map["rsidel"] = KStrafeKeys[1];
321  map["logo"] = KStrafeKeys[2];
322  map["fn"] = KStrafeKeys[3];
323  map.remove("rwin");
324  // remove media controls
325  map.remove("mute");
326  map.remove("volup");
327  map.remove("voldn");
328  map.remove("stop");
329  map.remove("prev");
330  map.remove("play");
331  map.remove("next");
332  // Done!
333  break;
334  }
335  case KeyMap::M65:{
336  // M65 isn't a keyboard; all mouse maps are unique.
337  for(const Key* key = M65Keys; key < M65Keys + KEYCOUNT_M65; key++){
338  // Keyboard keys are written from the center because that's where the LEDs are, but the mouse buttons are odd shapes so they're
339  // written from the upper left
340  Key translatedKey = *key;
341  translatedKey.x += translatedKey.width / 2;
342  translatedKey.y += translatedKey.height / 2;
343  map[key->name] = translatedKey;
344  }
345  // Mice also have no layout patches - no other changes necessary
346  break;
347  }
348  case KeyMap::SABRE:{
349  // Scimitar mouse
350  for(const Key* key = SabreKeys; key < SabreKeys + KEYCOUNT_SABRE; key++){
351  // Like the M65, the keys are upper-left justified
352  Key translatedKey = *key;
353  translatedKey.x += translatedKey.width / 2;
354  translatedKey.y += translatedKey.height / 2;
355  map[key->name] = translatedKey;
356  }
357  break;
358  }
359  case KeyMap::SCIMITAR:{
360  // Scimitar mouse
361  for(const Key* key = ScimKeys; key < ScimKeys + KEYCOUNT_SCIM; key++){
362  Key translatedKey = *key;
363  translatedKey.x += translatedKey.width / 2;
364  translatedKey.y += translatedKey.height / 2;
365  map[key->name] = translatedKey;
366  }
367  break;
368  }
369  default:; // <- stop GCC from complaining
370  }
371  // Map is finished, return result
372  return map;
373 }
374 
376  setlocale(LC_ALL, "");
377  QString loc = setlocale(LC_CTYPE, 0);
378  loc = loc.toLower().replace('_', '-');
379  if(loc.startsWith("dk-"))
380  return KeyMap::DK;
381  else if(loc.startsWith("fr-"))
382  return KeyMap::FR;
383  else if(loc.startsWith("de-"))
384  return KeyMap::DE;
385  else if(loc.startsWith("it-"))
386  return KeyMap::IT;
387  else if(loc.startsWith("pl-"))
388  return KeyMap::PL;
389  else if(loc.startsWith("no-"))
390  return KeyMap::NO;
391  else if(loc.startsWith("es-es"))
392  // Spain uses the ES layout
393  return KeyMap::ES;
394  else if(loc.startsWith("es-"))
395  // Other Spanish locales use MX
396  return KeyMap::MX;
397  else if(loc.startsWith("se-"))
398  return KeyMap::SE;
399  else if(loc.startsWith("en-us") || loc.startsWith("en-au") || loc.startsWith("en-ca") || loc.startsWith("en-hk") || loc.startsWith("en-in") || loc.startsWith("en-nz") || loc.startsWith("en-ph") || loc.startsWith("en-sg") || loc.startsWith("en-za"))
400  // Most English locales use US
401  return KeyMap::US;
402  else
403  // Default to GB
404  return KeyMap::GB;
405 }
406 
407 KeyMap::Layout KeyMap::getLayout(const QString& name){
408  QString lower = name.toLower();
409  if(lower == "dk")
410  return DK;
411  if(lower == "eu")
412  return EU;
413  if(lower == "eu_dvorak")
414  return EU_DVORAK;
415  if(lower == "gb_dvorak")
416  return GB_DVORAK;
417  if(lower == "us")
418  return US;
419  if(lower == "us_dvorak")
420  return US_DVORAK;
421  if(lower == "fr")
422  return FR;
423  if(lower == "de")
424  return DE;
425  if(lower == "it")
426  return IT;
427  if(lower == "no")
428  return NO;
429  if(lower == "pl")
430  return PL;
431  if(lower == "mx")
432  return MX;
433  if(lower == "es")
434  return ES;
435  if(lower == "se")
436  return SE;
437  if(lower == "gb")
438  return GB;
439  return NO_LAYOUT;
440 }
441 
443  switch(layout){
444  case DK:
445  return "dk";
446  case EU:
447  return "eu";
448  case EU_DVORAK:
449  return "eu_dvorak";
450  case GB:
451  return "gb";
452  case GB_DVORAK:
453  return "gb_dvorak";
454  case US:
455  return "us";
456  case US_DVORAK:
457  return "us_dvorak";
458  case FR:
459  return "fr";
460  case DE:
461  return "de";
462  case IT:
463  return "it";
464  case NO:
465  return "no";
466  case PL:
467  return "pl";
468  case MX:
469  return "mx";
470  case ES:
471  return "es";
472  case SE:
473  return "se";
474  default:
475  return "";
476  }
477 }
478 
479 QStringList KeyMap::layoutNames(){
480  return QStringList()
481  << "Danish"
482  << "English (ISO/European)" << "English (ISO/European, Dvorak)"
483  << "English (United Kingdom)" << "English (United Kingdom, Dvorak)"
484  << "English (United States)" << "English (United States, Dvorak)"
485  << "French"
486  << "German"
487  << "Italian"
488  << "Norwegian"
489  << "Polish"
490  << "Spanish (Latin America)"
491  << "Spanish (Spain)"
492  << "Swedish";
493 }
494 
495 KeyMap::Model KeyMap::getModel(const QString& name){
496  QString lower = name.toLower();
497  if(lower == "k65")
498  return K65;
499  if(lower == "k70")
500  return K70;
501  if(lower == "k95")
502  return K95;
503  if(lower == "strafe")
504  return STRAFE;
505  if(lower == "m65")
506  return M65;
507  if(lower == "sabre")
508  return SABRE;
509  if(lower == "scimitar")
510  return SCIMITAR;
511  return NO_MODEL;
512 }
513 
515  switch(model){
516  case K65:
517  return "k65";
518  case K70:
519  return "k70";
520  case K95:
521  return "k95";
522  case STRAFE:
523  return "strafe";
524  case M65:
525  return "m65";
526  case SABRE:
527  return "sabre";
528  case SCIMITAR:
529  return "scimitar";
530  default:
531  return "";
532  }
533 }
534 
535 KeyMap KeyMap::fromName(const QString &name){
536  QStringList list = name.trimmed().split(" ");
537  if(list.length() != 2)
538  return KeyMap();
539  return KeyMap(getModel(list[0]), getLayout(list[1]));
540 }
541 
543  switch(model){
544  case K65:
545  return K65_WIDTH;
546  case K70:
547  return K70_WIDTH;
548  case K95:
549  return K95_WIDTH;
550  case STRAFE:
551  return KSTRAFE_WIDTH;
552  case M65:
553  case SABRE:
554  case SCIMITAR:
555  return M65_WIDTH;
556  default:
557  return 0;
558  }
559 }
560 
562  switch(model){
563  case K65:
564  case K70:
565  case K95:
566  case STRAFE:
567  return K95_HEIGHT;
568  case M65:
569  case SABRE:
570  case SCIMITAR:
571  return M65_HEIGHT;
572  default:
573  return 0;
574  }
575 }
576 
577 KeyMap::KeyMap(Model _keyModel, Layout _keyLayout) :
578  _keys(getMap(_keyModel, _keyLayout)),
579  keyWidth(modelWidth(_keyModel)), keyHeight(modelHeight(_keyModel)),
580  keyModel(_keyModel), keyLayout(_keyLayout)
581 {}
582 
584  keyWidth(0), keyHeight(0),
585  keyModel(NO_MODEL), keyLayout(NO_LAYOUT)
586 {}
587 
588 QStringList KeyMap::byPosition() const {
589  // Use QMaps to order the keys
590  QMap<int, QMap<int, QString> > ordered;
591  QHashIterator<QString, Key> i(*this);
592  while(i.hasNext()){
593  i.next();
594  const Key& key = i.value();
595  ordered[key.y][key.x] = i.key();
596  }
597  // Merge them into a single list
598  QStringList result;
599  QMapIterator<int, QMap<int, QString> > y(ordered);
600  while(y.hasNext()){
601  y.next();
602  QMapIterator<int, QString> x(y.value());
603  while(x.hasNext()){
604  x.next();
605  result << x.value();
606  }
607  }
608  return result;
609 }
610 
611 QString KeyMap::friendlyName(const QString& key, Layout layout){
612  // Try K95 map first
613  // FIXME: This is an odd function and probably should be refactored
614  // it would probably be best to remove the friendly names from the maps and have a completely separate name->friendlyName store
615  KeyMap map(K95, layout);
616  if(map.contains(key))
617  return map[key].friendlyName();
618 
619  // The only key missing from it should be Fn, which is found on STRAFE
620  map = KeyMap(STRAFE, layout);
621  if(map.contains(key))
622  return map[key].friendlyName();
623 
624  // Additionally, there are a handful of keys not present on any physical keyboard, but we need names for them
625  if(key == "f13" || key == "f14" || key == "f15" || key == "f16" || key == "f17" || key == "f18" || key == "f19" || key == "f20")
626  return key.toUpper();
627  else if(key == "lightup")
628  return "Screen Brightness Up";
629  else if(key == "lightdn")
630  return "Screen Brightness Down";
631  else if(key == "eject" || key == "power")
632  return key[0].toUpper() + key.mid(1); // capitalize first letter
633 
634  // All other names are found on mice
635  map = KeyMap(SCIMITAR, layout);
636  if(map.contains(key))
637  return map[key].friendlyName();
638  map = KeyMap(M65, layout);
639  if(map.contains(key))
640  return map[key].friendlyName();
641 
642  // Not found at all
643  return "";
644 }
Layout
Definition: keymap.h:65
static const KeyPatch patchDE[]
Definition: keymap.cpp:55
static QHash< QString, Key > getMap(KeyMap::Model model, KeyMap::Layout layout)
Definition: keymap.cpp:210
#define N_MODELS
Definition: keymap.cpp:206
KeyMap()
Definition: keymap.cpp:583
static const KeyPatch patchEU[]
Definition: keymap.cpp:43
QStringList byPosition() const
Definition: keymap.cpp:588
static QString friendlyName(const QString &key, Layout layout=US)
Definition: keymap.cpp:611
#define NS
Definition: keymap.cpp:6
#define K65_TOP_COUNT
Definition: keymap.cpp:148
#define ANSI_ENTER_W
Definition: keymap.cpp:24
static const KeyPatch patchFR[]
Definition: keymap.cpp:48
const char * _storageName
Definition: keymap.cpp:31
static QStringList layoutNames()
Definition: keymap.cpp:479
short width
Definition: keymap.h:17
static const Key K65TopRow[]
Definition: keymap.cpp:145
#define K70_WIDTH
Definition: keymap.cpp:138
#define KSTRAFE_X_START
Definition: keymap.cpp:151
static const KeyPatch patchMX[]
Definition: keymap.cpp:76
static Model getModel(const QString &name)
Definition: keymap.cpp:495
static const KeyPatch patchIT[]
Definition: keymap.cpp:62
Key key(const QString &name) const
Definition: keymap.h:125
#define ANSI_ENTER_H
Definition: keymap.cpp:25
short height
Definition: keymap.h:17
bool contains(const QString &name) const
Definition: keymap.h:127
#define ANSI_ENTER_X
Definition: keymap.cpp:22
const char * name
Definition: keymap.cpp:33
const char * _storageName
Definition: keymap.h:10
#define KEYCOUNT_M65
Definition: keymap.cpp:170
static const KeyPatch patchDK[]
Definition: keymap.cpp:36
static const Key KStrafeKeys[]
Definition: keymap.cpp:155
static Layout getLayout(const QString &name)
Definition: keymap.cpp:407
static const KeyPatch patchES[]
Definition: keymap.cpp:83
static void patchISO(QHash< QString, Key > &map)
Definition: keymap.cpp:116
static QHash< QString, Key > standardMaps[KeyMap::_MODEL_MAX][KeyMap::_LAYOUT_MAX]
Definition: keymap.cpp:209
#define KSTRAFE_WIDTH
Definition: keymap.cpp:152
static void patchANSI(QHash< QString, Key > &map)
Definition: keymap.cpp:119
static const Key K95Keys[]
Definition: keymap.cpp:10
#define KSTRAFE_HEIGHT
Definition: keymap.cpp:153
const QHash< QString, Key > & map() const
Definition: keymap.h:129
#define K95_WIDTH
Definition: keymap.cpp:133
#define K70_X_START
Definition: keymap.cpp:137
short x
Definition: keymap.h:16
#define ANSI_ENTER_Y
Definition: keymap.cpp:23
bool isISO() const
Definition: keymap.h:88
#define N_LAYOUTS
Definition: keymap.cpp:207
static QHash< QString, Key > K95BaseMap
Definition: keymap.cpp:208
#define K95_HEIGHT
Definition: keymap.cpp:134
Model
Definition: keymap.h:51
#define K65_WIDTH
Definition: keymap.cpp:142
#define patch(map, patches)
Definition: keymap.cpp:106
static int modelWidth(Model model)
Definition: keymap.cpp:542
Definition: keymap.h:8
const char * _friendlyName
Definition: keymap.cpp:32
Definition: keymap.h:49
#define KEYCOUNT_K95
Definition: keymap.cpp:19
static const KeyPatch patchNO[]
Definition: keymap.cpp:69
static Layout locale()
Definition: keymap.cpp:375
static const Key M65Keys[]
Definition: keymap.cpp:163
static const Key SabreKeys[]
Definition: keymap.cpp:176
static const Key ScimKeys[]
Definition: keymap.cpp:189
#define M65_WIDTH
Definition: keymap.cpp:172
static KeyMap fromName(const QString &name)
Definition: keymap.cpp:535
#define ANSI_LSHIFT_X
Definition: keymap.cpp:26
static int modelHeight(Model model)
Definition: keymap.cpp:561
const char * _friendlyName
Definition: keymap.h:13
static void _patch(QHash< QString, Key > &map, const KeyPatch *patches, int patchCount)
Definition: keymap.cpp:107
#define KEYCOUNT_SCIM
Definition: keymap.cpp:200
#define ANSI_LSHIFT_W
Definition: keymap.cpp:27
static const KeyPatch patchSE[]
Definition: keymap.cpp:90
#define M65_HEIGHT
Definition: keymap.cpp:173
#define KEYCOUNT_SABRE
Definition: keymap.cpp:183
short y
Definition: keymap.h:16
static const KeyPatch patchDvorak[]
Definition: keymap.cpp:97