ckb-next  v0.2.8 at branch master
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 // Lightbar LED size
9 #define LBS 17, 6
10 // Key positions (K95 - English)
11 // This is the master key map that includes ANSI, ISO and JP-106 layouts - use patchANSI(), patchISO() or patchJP106() to finalize it
12 static const Key K95Keys[] = {
13  {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},
14  {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},
15  {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, "¥", "yen", 194, 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},
16  {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},
17  {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},
18  {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, "_", "ro", 185, 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},
19  {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, "無変換", "muhenkan", 80, 75, NS, true, true}, {0, "Space", "space", 116, 75, 84, 12, true, true}, {0, "変換", "henkan", 150, 75, NS, true, true}, {0, "ひらがな カタカナ ローマ字", "katahira", 162, 75, NS, 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}
20 };
21 #define KEYCOUNT_K95 (sizeof(K95Keys) / sizeof(Key))
22 
23 // ANSI layouts use a different Enter/LShift key
24 #define ANSI_ENTER_X 199
25 #define ANSI_ENTER_Y 51
26 #define ANSI_ENTER_W 26
27 #define ANSI_ENTER_H 12
28 #define ANSI_LSHIFT_X 45
29 #define ANSI_LSHIFT_W 26
30 
31 // Layout "patches" for different regions
32 struct KeyPatch {
33  const char* _storageName;
34  const char* _friendlyName;
35  const char* name;
36 };
37 
38 static const KeyPatch patchDK[] = {
39  {0, "§", "grave"}, {0, "+", "minus"}, {0, "´", "equal"},
40  {0, "Å", "lbrace"}, {0, "¨", "rbrace"},
41  {0, "Æ", "colon"}, {0, "Ø", "quote"}, {0, "'", "hash"},
42  {0, "<", "bslash_iso"}, {0, "-", "slash"},
43 };
44 
45 static const KeyPatch patchEU[] = {
46  {0, "\\ (R)", "hash"},
47  {0, "\\ (L)", "bslash_iso"},
48 };
49 
50 static const KeyPatch patchFR[] = {
51  {"sup2", "²", "grave"}, {0, "&", "1"}, {0, "É", "2"}, {0, "\"", "3"}, {0, "'", "4"}, {0, "(", "5"}, {0, "-", "6"}, {0, "È", "7"}, {0, "_", "8"}, {0, "Ç", "9"}, {0, "À", "0"}, {"rparen", ")", "minus"},
52  {"a", "A", "q"}, {"z", "Z", "w"}, {"caret", "^", "lbrace"}, {"dollar", "$", "rbrace"},
53  {"q", "Q", "a"}, {"m", "M", "colon"}, {"percent", "Ù", "quote"}, {"star", "*", "hash"},
54  {"angle", "<", "bslash_iso"}, {"w", "W", "z"}, {"comma", ",", "m"}, {"semicolon", ";", "comma"}, {"colon", ":", "dot"}, {"exclam", "!", "slash"},
55 };
56 
57 static const KeyPatch patchDE[] = {
58  {"caret", "^", "grave"}, {"ss", "ß", "minus"}, {"grave", "´", "equal"},
59  {"z", "Z", "y"}, {"ue", "Ü", "lbrace"}, {"plus", "+", "rbrace"},
60  {"oe", "Ö", "colon"}, {"ae", "Ä", "quote"},
61  {"angle", "<", "bslash_iso"}, {"y", "Y", "z"}, {"minus", "-", "slash"}
62 };
63 
64 static const KeyPatch patchIT[] = {
65  {0, "\\", "grave"}, {0, "'", "minus"}, {0, "Ì", "equal"},
66  {0, "È", "lbrace"}, {0, "+", "rbrace"},
67  {0, "Ò", "colon"}, {0, "À", "quote"}, {0, "Ù", "hash"},
68  {0, "<", "bslash_iso"}, {0, "-", "slash"},
69 };
70 
71 static const KeyPatch patchNO[] = {
72  {0, "§", "grave"}, {0, "+", "minus"}, {0, "´", "equal"},
73  {0, "Å", "lbrace"}, {0, "¨", "rbrace"},
74  {0, "Ø", "colon"}, {0, "Æ", "quote"}, {0, "'", "hash"},
75  {0, "<", "bslash_iso"}, {0, "-", "slash"},
76 };
77 
78 static const KeyPatch patchMX[] = {
79  {0, "|", "grave"}, {0, "'", "minus"}, {0, "¿", "equal"},
80  {0, "´", "lbrace"}, {0, "+", "rbrace"},
81  {0, "Ñ", "colon"}, {0, "{", "quote"}, {0, "}", "hash"},
82  {0, "<", "bslash_iso"}, {0, "-", "slash"},
83 };
84 
85 static const KeyPatch patchPTBR[] = {
86  {"quote", "'", "grave"},
87  {"accent", "´", "lbrace"}, {"lbrace", "[", "rbrace"},
88  {"cc", "Ç", "colon"}, {"tilde", "~", "quote"}, {"rbrace", "]", "hash"},
89  {"colon", ";", "slash"}, {"slash", "/", "ro"}, {"numcomma", ",", "numdot"},
90 };
91 
92 static const KeyPatch patchES[] = {
93  {"oa", "º", "grave"}, {"quote", "'", "minus"}, {"lexclam", "¡", "equal"},
94  {"grave", "`", "lbrace"}, {"plus", "+", "rbrace"},
95  {"nn", "Ñ", "colon"}, {"accent", "´", "quote"}, {"cc", "Ç", "hash"},
96  {"angle", "<", "bslash_iso"}, {"minus", "-", "slash"},
97 };
98 
99 static const KeyPatch patchSE[] = {
100  {"section", "§", "grave"}, {"plus", "+", "minus"}, {"grave", "´", "equal"},
101  {"aa", "Å", "lbrace"}, {"umlaut", "¨", "rbrace"},
102  {"oe", "Ö", "colon"}, {"ae", "Ä", "quote"}, {"quote", "'", "hash"},
103  {"angle", "<", "bslash_iso"}, {"minus", "-", "slash"},
104 };
105 
106 static const KeyPatch patchJP[] = {
107  /*{"lbrace", "[", "rbrace"},
108  {"rbrace", "]", "hash"},*/
109 };
110 
111 static const KeyPatch patchDvorak[] = {
112  {0, "[", "minus"}, {0, "]", "equal"},
113  {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"},
114  {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"},
115  {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"},
116 };
117 
118 // Apply a patch to a key map
119 #define PATCH_COUNT(patch) (sizeof(patch) / sizeof(KeyPatch))
120 #define patch(map, patches) _patch(map, patches, PATCH_COUNT(patches))
121 static void _patch(QHash<QString, Key>& map, const KeyPatch* patches, int patchCount){
122  for(const KeyPatch* p = patches; p < patches + patchCount; p++){
123  Key& key = map[p->name];
124  key._storageName = p->_storageName;
125  key._friendlyName = p->_friendlyName;
126  }
127 }
128 
129 // Patch a key map for ANSI/ISO layout
130 static void patchnonJP106(QHash<QString, Key>& map){
131  map.remove("yen");
132  map.remove("henkan");
133  map.remove("muhenkan");
134  map.remove("katahira");
135  map.remove("ro");
136 }
137 static void patchISO(QHash<QString, Key>& map){
138  patchnonJP106(map);
139  map.remove("bslash");
140 }
141 static void patchANSI(QHash<QString, Key>& map){
142  patchnonJP106(map);
143  map.remove("bslash_iso");
144  map.remove("hash");
145  Key& enter = map["enter"];
146  enter.x = ANSI_ENTER_X;
147  enter.y = ANSI_ENTER_Y;
148  enter.width = ANSI_ENTER_W;
149  enter.height = ANSI_ENTER_H;
150  Key& lshift = map["lshift"];
151  lshift.x = ANSI_LSHIFT_X;
152  lshift.width = ANSI_LSHIFT_W;
153 }
154 static void patchJP106(QHash<QString, Key>& map){
155  // First apply the ISO patch
156  map.remove("bslash");
157 
158  // Resize Backspace
159  Key& bspace = map["bspace"];
160  bspace.width -= 12;
161  bspace.x = 206;
162 
163  // Resize RShift
164  Key& rshift = map["rshift"];
165  rshift.width -= 12;
166  rshift.x += 6;
167 
168  // Resize Spacebar
169  Key& space = map["space"];
170  space.width -= 26;
171  space.x -= 1;
172 
173  // Left shift
174  Key& lshift = map["lshift"];
175  lshift.x = ANSI_LSHIFT_X;
176  lshift.width = ANSI_LSHIFT_W;
177 
178  map.remove("bslash_iso");
179 
180  // Resize and move ralt to make space for the extra keys
181  Key& ralt = map["ralt"];
182  ralt.x += 11;
183  ralt.width += 2;
184 
185  // None of these layouts have rwin
186  map.remove("rwin");
187 }
188 // Used to fix the Fn size and remove Alt when necessary in JP layouts for compatible devices
189 static void patchJP106fn(QHash<QString, Key>& map){
190  if(map.contains("fn")){
191  map.remove("ralt");
192  Key& fn = map["fn"];
193  fn.width += 4;
194  fn.x -= 2;
195  }
196 }
197 // Patch for ABNT 2 layout
198 static void patchABNT2(QHash<QString, Key>& map){
199  map.remove("yen");
200  map.remove("henkan");
201  map.remove("muhenkan");
202  map.remove("katahira");
203  map.remove("bslash");
204 
205  // Resize RShift
206  Key& rshift = map["rshift"];
207  rshift.width -= 12;
208  rshift.x += 6;
209 }
210 
211 // Total width/height
212 #define K95_WIDTH 298
213 #define K95_HEIGHT 76
214 
215 #define K95P_HEIGHT 82
216 #define K95P_X_START 20
217 #define K95P_WIDTH (K95_WIDTH - K95P_X_START + 1)
218 
219 // K70 cuts off the G keys on the left, as well as MR/M1/M2/M3
220 #define K70_X_START 38
221 #define K70_WIDTH (K95_WIDTH - K70_X_START)
222 #define K70_HEIGHT K95_HEIGHT
223 
224 #define K68_WIDTH K70_WIDTH
225 #define K68_HEIGHT K70_HEIGHT
226 
227 // K65 additionally removes the numpad on the right, and has a different top row
228 #define K65_WIDTH 209
229 #define K65_HEIGHT K70_HEIGHT
230 
231 // K63 is the same as the K65 in terms of size
232 #define K63_WIDTH K65_WIDTH
233 #define K63_HEIGHT K65_HEIGHT
234 
235 static const Key K68TopRow[] = {
236  {0, "Volume Down", "voldn", 285 - K70_X_START, 0, 13, 8, true, true}, {0, "Volume Up", "volup", 297 - K70_X_START, 0, 13, 8, true, true},
237 };
238 #define K68_TOP_COUNT (sizeof(K68TopRow) / sizeof(Key))
239 
240 static const Key K65TopRow[] = {
241  {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}
242 };
243 #define K65_TOP_COUNT (sizeof(K65TopRow) / sizeof(Key))
244 
245 static const Key K63TopRow[] = {
246  {0, "Stop", "stop", K70_X_START - 37, 0, 12, 8, true, true}, {0, "Previous", "prev", K70_X_START - 26, 0, 12, 8, true, true}, {0, "Play/Pause", "play", K70_X_START - 15, 0, 12, 8, true, true}, {0, "Next", "next", K70_X_START - 4, 0, 12, 8, true, true}, {0, "Brightness", "light", 170 - K70_X_START, 0, 12, 12, true, true}, {0, "Windows Lock", "lock", 180 - K70_X_START, 0, 12, 12, true, true}, {0, "Mute", "mute", 222 - K70_X_START, 0, 13, 8, true, true}, {0, "Volume Down", "voldn", 234 - K70_X_START, 0, 13, 8, true, true}, {0, "Volume Up", "volup", 246 - K70_X_START, 0, 13, 8, true, true}
247 };
248 #define K63_TOP_COUNT (sizeof(K63TopRow) / sizeof(Key))
249 
250 // Strafe has side lights
251 #define KSTRAFE_X_START 12
252 #define KSTRAFE_WIDTH (K70_WIDTH + (KSTRAFE_X_START * 2))
253 #define KSTRAFE_HEIGHT K95_HEIGHT
254 
255 static const Key KStrafeKeys[] = {
256  {0, "Sidelight", "lsidel", 0, KSTRAFE_HEIGHT/2, KSTRAFE_X_START, KSTRAFE_HEIGHT, true, false},
257  {0, "Sidelight", "rsidel", KSTRAFE_WIDTH, KSTRAFE_HEIGHT/2, KSTRAFE_X_START, KSTRAFE_HEIGHT, true, false},
258  {0, "Logo", "logo", KSTRAFE_X_START, 0, NS, true, false},
259  {0, "Function", "fn", 152, 75, NS, true, true}
260 };
261 
262 // Mouse map - M65
263 static const Key M65Keys[] = {
264  {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},
265  {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},
266  {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},
267  {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},
268  {0, "Logo", "back", 14, 55, 24, 12, true, false}
269 };
270 #define KEYCOUNT_M65 (sizeof(M65Keys) / sizeof(Key))
271 
272 #define M65_WIDTH 52
273 #define M65_HEIGHT 67
274 
275 // Sabre
276 static const Key SabreKeys[] = {
277  {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 },
278  {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},
279  {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},
280  {0, "Forward", "mouse5", 5, 24, 5, 9, false, true}, {0, "Back", "mouse4", 5, 33, 5, 10, false, true},
281  {0, "Logo", "back", 14, 50, 24, 12, true, false}
282 };
283 #define KEYCOUNT_SABRE (sizeof(SabreKeys) / sizeof(Key))
284 
285 #define SABRE_WIDTH M65_WIDTH
286 #define SABRE_HEIGHT M65_HEIGHT
287 
288 // Harpoon
289 static const Key HarpoonKeys[] = {
290  {0, "Left Mouse", "mouse1", 10, 5, 14, 26, false, true}, {0, "Right Mouse", "mouse2", 30, 5, 14, 26, false, true}, {0, "Middle Mouse", "mouse3", 25, 11, 6, 7, false, true},
291  {0, "Wheel Up", "wheelup", 25, 7, 6, 5, false, true}, {0, "Wheel Down", "wheeldn", 25, 17, 6, 5, false, true},
292  {0, "DPI Cycle", "dpiup", 25, 23, 6, 10, false, true}, {0, "Logo Light", "dpi", 17, 40, 20, 20, true, false},
293  {0, "Forward", "mouse5", 3, 24, 5, 10, false, true}, {0, "Back", "mouse4", 3, 33, 5, 10, false, true}
294  };
295 #define KEYCOUNT_HARPOON (sizeof(HarpoonKeys) / sizeof(Key))
296 
297 #define HARPOON_WIDTH M65_WIDTH
298 #define HARPOON_HEIGHT M65_HEIGHT
299 
300 // Glaive
301 static const Key GlaiveKeys[] = {
302  {0, "Left Mouse", "mouse1", 17, 3, 14, 18, false, true}, {0, "Right Mouse", "mouse2", 37, 3, 14, 18, false, true}, {0, "Middle Mouse", "mouse3", 31, 9, 7, 7, false, true}, {0, "Front light", "front", 16, -5, 36, 8, true, false },
303  {0, "Wheel Up", "wheelup", 31, 5, 7, 5, false, true}, {0, "Wheel Down", "wheeldn", 31, 15, 7, 5, false, true}, {0, "Side Lights", "side", 22, 24, 7, 20, true, false},
304  {0, "DPI Cycle", "dpiup", 31, 19, 6, 12, false, true}, {0, "Logo Light", "back", 24, 43, 20, 20, true, false},
305  {0, "Forward", "mouse5", 15, 22, 5, 11, false, true}, {0, "Back", "mouse4", 15, 32, 5, 11, false, true}
306  };
307 #define KEYCOUNT_GLAIVE (sizeof(GlaiveKeys) / sizeof(Key))
308 
309 #define GLAIVE_WIDTH M65_WIDTH
310 #define GLAIVE_HEIGHT M65_HEIGHT
311 
312 // Scimitar
313 static const Key ScimKeys[] = {
314  {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 },
315  {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},
316  {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},
317  {0, "Thumb light", "thumb", 0, 21, 10, 24, true, false},
318  {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},
319  {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},
320  {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},
321  {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},
322  {0, "Logo", "back", 14, 50, 24, 16, true, false}
323 };
324 #define KEYCOUNT_SCIM (sizeof(ScimKeys) / sizeof(Key))
325 
326 #define SCIM_WIDTH M65_WIDTH
327 #define SCIM_HEIGHT M65_HEIGHT
328 
329 // K95 Platinum lightbar
330 static const Key K95PLbar[] = {
331  {0, 0, "topbar1", 4, -3, LBS, true, false}, {0, 0, "topbar2", 19, -3, LBS, true, false}, {0, 0, "topbar3", 34, -3, LBS, true, false}, {0, 0, "topbar4", 49, -3, LBS, true, false}, {0, 0, "topbar5", 64, -3, LBS, true, false}, {0, 0, "topbar6", 79, -3, LBS, true, false},
332  {0, 0, "topbar7", 94, -3, LBS, true, false}, {0, 0, "topbar8", 109, -3, LBS, true, false}, {0, 0, "topbar9", 124, -3, LBS, true, false}, {0, 0, "topbar10", 139, -3, LBS, true, false}, {0, 0, "topbar11", 154, -3, LBS, true, false}, {0, 0, "topbar12", 169, -3, LBS, true, false},
333  {0, 0, "topbar13", 184, -3, LBS, true, false}, {0, 0, "topbar14", 199, -3, LBS, true, false}, {0, 0, "topbar15", 214, -3, LBS, true, false}, {0, 0, "topbar16", 229, -3, LBS, true, false}, {0, 0, "topbar17", 244, -3, LBS, true, false}, {0, 0, "topbar18", 259, -3, LBS, true, false},
334  {0, 0, "topbar19", 274, -3, LBS, true, false},
335 };
336 #define LBARCOUNT_K95P (sizeof(K95PLbar) / sizeof(Key))
337 
338 
339 // Map getter. Each model/layout pair only needs to be constructed once; after that, future KeyMaps can copy the existing maps.
340 #define N_MODELS KeyMap::_MODEL_MAX
341 #define N_LAYOUTS KeyMap::_LAYOUT_MAX
342 static QHash<QString, Key> K95BaseMap;
343 static QHash<QString, Key> standardMaps[N_MODELS][N_LAYOUTS];
344 static QHash<QString, Key> getMap(KeyMap::Model model, KeyMap::Layout layout){
345  if(model < 0 || layout < 0 || model >= N_MODELS || layout >= N_LAYOUTS)
346  return QHash<QString, Key>();
347  // Return the map if it's already filled out
348  QHash<QString, Key>& map = standardMaps[model][layout];
349  if(!map.empty())
350  return map;
351  // Otherwise, create it
352  switch(model){
353  case KeyMap::K95:{
354  // The K95 maps serve as bases for all the other keyboards
355  // Fetch the master map, or create it if not yet done
356  if(K95BaseMap.empty()){
357  for(const Key* key = K95Keys; key < K95Keys + KEYCOUNT_K95; key++)
358  K95BaseMap[key->name] = *key;
359  }
360  map = K95BaseMap;
361  // Patch the map for the layout
362  switch(layout){
363  case KeyMap::DK:
364  patch(map, patchDK);
365  break;
366  case KeyMap::EU_DVORAK:
367  patch(map, patchDvorak); // fall through
368  case KeyMap::EU:
369  patch(map, patchEU);
370  break;
371  case KeyMap::GB_DVORAK:
372  case KeyMap::US_DVORAK:
373  patch(map, patchDvorak);
374  break;
375  case KeyMap::FR:
376  patch(map, patchFR);
377  break;
378  case KeyMap::DE:
379  patch(map, patchDE);
380  break;
381  case KeyMap::IT:
382  patch(map, patchIT);
383  break;
384  case KeyMap::NO:
385  patch(map, patchNO);
386  break;
387  case KeyMap::MX:
388  patch(map, patchMX);
389  break;
390  case KeyMap::PT_BR:
391  patch(map, patchPTBR);
392  break;
393  case KeyMap::ES:
394  patch(map, patchES);
395  break;
396  case KeyMap::SE:
397  patch(map, patchSE);
398  break;
399  case KeyMap::JP:
400  patch(map, patchJP);
401  break;
402  default:;
403  // English QWERTY - no patch needed
404  }
405  if(KeyMap::isJP(layout))
406  patchJP106(map);
407  else if(KeyMap::isPTBR(layout))
408  patchABNT2(map);
409  else if(KeyMap::isISO(layout))
410  patchISO(map);
411  else
412  patchANSI(map);
413  // Done! return the map
414  break;
415  }
416  case KeyMap::K95P:{
417  // The K95 Platinum map is based on the K95
418  map = getMap(KeyMap::K95, layout);
419  // Remove excess G keys
420  map.remove("g7");
421  map.remove("g8");
422  map.remove("g9");
423  map.remove("g10");
424  map.remove("g11");
425  map.remove("g12");
426  map.remove("g13");
427  map.remove("g14");
428  map.remove("g15");
429  map.remove("g16");
430  map.remove("g17");
431  map.remove("g18");
432  // Place the remaining G keys vertically
433  map["g1"].x = 22;
434  map["g2"].x = 22;
435  map["g3"].x = 22;
436  map["g4"].x = 22;
437  map["g5"].x = 22;
438  map["g6"].x = 22;
439  //map["g1"].y = 14+(12*0);
440  map["g2"].y = 26; //14+(12*1)
441  map["g3"].y = 38; //14+(12*2)
442  map["g4"].y = 50; //14+(12*3)
443  map["g5"].y = 62; //14+(12*4)
444  map["g6"].y = 74; //14+(12*5)
445  // Remove M keys
446  map.remove("m1");
447  map.remove("m2");
448  map.remove("m3");
449  // Centre MR/Brightness/Winlock between F1 and F4
450  map["mr"].x = 64;
451  map["light"].x = 75;
452  map["lock"].x = 86;
453  // Resize them
454  map["mr"].height = 8;
455  map["light"].height = 8;
456  map["lock"].height = 8;
457  map["mr"].width = 11;
458  map["light"].width = 11;
459  map["lock"].width = 11;
460  // Mute is above Stop
461  map["mute"].x -= 11;
462  map["voldn"].x -= 11;
463  map["volup"].x -= 11;
464  // Move the buttons on the top a bit further down to centre them
465  map["mr"].y += 1;
466  map["light"].y += 1;
467  map["lock"].y += 1;
468  map["mute"].y += 1;
469  map["voldn"].y += 1;
470  map["volup"].y += 1;
471  // Shift all keys down (to make room for the lightbar), and to the left
472  QMutableHashIterator<QString, Key> i(map);
473  while(i.hasNext()){
474  i.next();
475  i.value().x -= K95P_X_START;
476  i.value().y += 6;
477  }
478  // Add lightbar
479  for(const Key* key = K95PLbar; key < K95PLbar + LBARCOUNT_K95P; key++)
480  map.insert(key->name, *key);
481 
482  break;
483  }
484  case KeyMap::K70:{
485  // The K70 maps are based on the K95 maps. However all the keys are shifted left and the G keys are removed
486  map = getMap(KeyMap::K95, layout);
487  QMutableHashIterator<QString, Key> i(map);
488  while(i.hasNext()){
489  i.next();
490  // Move key to left. Remove it if it fell off the edge
491  if((i.value().x -= K70_X_START) < 0)
492  i.remove();
493  }
494  // Remove the M buttons as well
495  map.remove("mr");
496  map.remove("m1");
497  map.remove("m2");
498  map.remove("m3");
499  // Done!
500  break;
501  }
502  case KeyMap::K68:{
503  // Same as the K70, except volume up and down keys
504  map = getMap(KeyMap::K70, layout);
505  for(const Key* key = K68TopRow; key < K68TopRow + K68_TOP_COUNT; key++)
506  map[key->name] = *key;
507 
508  break;
509  }
510  case KeyMap::K65:{
511  // The K65 maps additionally remove the numpad and have a modified top row
512  map = getMap(KeyMap::K70, layout);
513  QMutableHashIterator<QString, Key> i(map);
514  while(i.hasNext()){
515  i.next();
516  if(i.value().x >= K65_WIDTH)
517  i.remove();
518  }
519  for(const Key* key = K65TopRow; key < K65TopRow + K65_TOP_COUNT; key++)
520  map[key->name] = *key;
521 
522  map.remove("rwin");
523  map["fn"] = KStrafeKeys[3];
524  map["fn"].x -= 12;
525 
526  if(KeyMap::isJP(layout))
527  patchJP106fn(map);
528 
529  // Done!
530  break;
531  }
532  case KeyMap::K63:{
533  // Same as the K65 but without the Fn key
534  map = getMap(KeyMap::K70, layout);
535  QMutableHashIterator<QString, Key> i(map);
536  while(i.hasNext()){
537  i.next();
538  if(i.value().x >= K65_WIDTH)
539  i.remove();
540  }
541  for(const Key* key = K63TopRow; key < K63TopRow + K63_TOP_COUNT; key++)
542  map[key->name] = *key;
543 
544  break;
545  }
546  case KeyMap::STRAFE:{
547  // The Strafe RGB maps are based on the K70 map minus the media keys
548  map = getMap(KeyMap::K70, layout);
549  //move light and lock right
550  map["light"].x=285 - K70_X_START;
551  //map["light"].hasLed=false;
552  map["lock"].x=297 - K70_X_START;
553  //map["lock"].hasLed=false;
554  // move everything right to make the space for the left sidelight
555  QMutableHashIterator<QString, Key> i(map);
556  while(i.hasNext()){
557  i.next();
558  i.value().x += KSTRAFE_X_START;
559  }
560  // Add Strafe lights and keys
561  map["lsidel"] = KStrafeKeys[0];
562  map["rsidel"] = KStrafeKeys[1];
563  map["logo"] = KStrafeKeys[2];
564  map["fn"] = KStrafeKeys[3];
565  map.remove("rwin");
566  // remove media controls
567  map.remove("mute");
568  map.remove("volup");
569  map.remove("voldn");
570  map.remove("stop");
571  map.remove("prev");
572  map.remove("play");
573  map.remove("next");
574 
575  if(KeyMap::isJP(layout))
576  patchJP106fn(map);
577 
578  // Done!
579  break;
580  }
581  case KeyMap::M65:{
582  // M65 isn't a keyboard; all mouse maps are unique.
583  for(const Key* key = M65Keys; key < M65Keys + KEYCOUNT_M65; key++){
584  // Keyboard keys are written from the center because that's where the LEDs are, but the mouse buttons are odd shapes so they're
585  // written from the upper left
586  Key translatedKey = *key;
587  translatedKey.x += translatedKey.width / 2;
588  translatedKey.y += translatedKey.height / 2;
589  map[key->name] = translatedKey;
590  }
591  // Mice also have no layout patches - no other changes necessary
592  break;
593  }
594  case KeyMap::SABRE:{
595  // Sabre mouse
596  for(const Key* key = SabreKeys; key < SabreKeys + KEYCOUNT_SABRE; key++){
597  // Like the M65, the keys are upper-left justified
598  Key translatedKey = *key;
599  translatedKey.x += translatedKey.width / 2;
600  translatedKey.y += translatedKey.height / 2;
601  map[key->name] = translatedKey;
602  }
603  break;
604  }
605  case KeyMap::SCIMITAR:{
606  // Scimitar mouse
607  for(const Key* key = ScimKeys; key < ScimKeys + KEYCOUNT_SCIM; key++){
608  Key translatedKey = *key;
609  translatedKey.x += translatedKey.width / 2;
610  translatedKey.y += translatedKey.height / 2;
611  map[key->name] = translatedKey;
612  }
613  break;
614  }
615  case KeyMap::HARPOON:{
616  // Harpoon mouse
617  for(const Key* key = HarpoonKeys; key < HarpoonKeys + KEYCOUNT_HARPOON; key++){
618  Key translatedKey = *key;
619  translatedKey.x += translatedKey.width / 2;
620  translatedKey.y += translatedKey.height / 2;
621  map[key->name] = translatedKey;
622  }
623  break;
624  }
625  case KeyMap::GLAIVE:{
626  // Glaive mouse
627  for(const Key* key = GlaiveKeys; key < GlaiveKeys + KEYCOUNT_GLAIVE; key++){
628  Key translatedKey = *key;
629  translatedKey.x += translatedKey.width / 2;
630  translatedKey.y += translatedKey.height / 2;
631  map[key->name] = translatedKey;
632  }
633  break;
634  }
635  default:; // <- stop GCC from complaining
636  }
637  // Map is finished, return result
638  return map;
639 }
640 
642  setlocale(LC_ALL, "");
643  QString loc = setlocale(LC_CTYPE, 0);
644  loc = loc.toLower().replace('_', '-');
645  if(loc.startsWith("dk-"))
646  return KeyMap::DK;
647  else if(loc.startsWith("fr-"))
648  return KeyMap::FR;
649  else if(loc.startsWith("de-"))
650  return KeyMap::DE;
651  else if(loc.startsWith("it-"))
652  return KeyMap::IT;
653  else if(loc.startsWith("ja-"))
654  return KeyMap::JP;
655  else if(loc.startsWith("pl-"))
656  return KeyMap::PL;
657  else if(loc.startsWith("pt-br"))
658  return KeyMap::PT_BR;
659  else if(loc.startsWith("no-"))
660  return KeyMap::NO;
661  else if(loc.startsWith("es-es"))
662  // Spain uses the ES layout
663  return KeyMap::ES;
664  else if(loc.startsWith("es-"))
665  // Other Spanish locales use MX
666  return KeyMap::MX;
667  else if(loc.startsWith("se-"))
668  return KeyMap::SE;
669  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"))
670  // Most English locales use US
671  return KeyMap::US;
672  else
673  // Default to GB
674  return KeyMap::GB;
675 }
676 
677 KeyMap::Layout KeyMap::getLayout(const QString& name){
678  QString lower = name.toLower();
679  if(lower == "dk")
680  return DK;
681  if(lower == "eu")
682  return EU;
683  if(lower == "eu_dvorak")
684  return EU_DVORAK;
685  if(lower == "gb_dvorak")
686  return GB_DVORAK;
687  if(lower == "us")
688  return US;
689  if(lower == "us_dvorak")
690  return US_DVORAK;
691  if(lower == "fr")
692  return FR;
693  if(lower == "de")
694  return DE;
695  if(lower == "it")
696  return IT;
697  if(lower == "no")
698  return NO;
699  if(lower == "jp")
700  return JP;
701  if(lower == "pl")
702  return PL;
703  if(lower == "pt_br")
704  return PT_BR;
705  if(lower == "mx")
706  return MX;
707  if(lower == "es")
708  return ES;
709  if(lower == "se")
710  return SE;
711  if(lower == "gb")
712  return GB;
713  return NO_LAYOUT;
714 }
715 
717  switch(layout){
718  case DK:
719  return "dk";
720  case EU:
721  return "eu";
722  case EU_DVORAK:
723  return "eu_dvorak";
724  case GB:
725  return "gb";
726  case GB_DVORAK:
727  return "gb_dvorak";
728  case US:
729  return "us";
730  case US_DVORAK:
731  return "us_dvorak";
732  case FR:
733  return "fr";
734  case DE:
735  return "de";
736  case IT:
737  return "it";
738  case JP:
739  return "jp";
740  case NO:
741  return "no";
742  case PL:
743  return "pl";
744  case PT_BR:
745  return "pt_br";
746  case MX:
747  return "mx";
748  case ES:
749  return "es";
750  case SE:
751  return "se";
752  default:
753  return "";
754  }
755 }
756 
757 QStringList KeyMap::layoutNames(){
758  return QStringList()
759  << "Danish"
760  << "English (ISO/European)" << "English (ISO/European, Dvorak)"
761  << "English (United Kingdom)" << "English (United Kingdom, Dvorak)"
762  << "English (United States)" << "English (United States, Dvorak)"
763  << "French"
764  << "German"
765  << "Italian"
766  << "Japanese"
767  << "Norwegian"
768  << "Polish"
769  << "Portuguese (Brazil)"
770  << "Spanish (Latin America)"
771  << "Spanish (Spain)"
772  << "Swedish";
773 }
774 
775 KeyMap::Model KeyMap::getModel(const QString& name){
776  QString lower = name.toLower();
777  if(lower == "k63")
778  return K63;
779  if(lower == "k65")
780  return K65;
781  if(lower == "k68")
782  return K68;
783  if(lower == "k70")
784  return K70;
785  if(lower == "k95")
786  return K95;
787  if(lower == "k95p")
788  return K95P;
789  if(lower == "strafe")
790  return STRAFE;
791  if(lower == "m65")
792  return M65;
793  if(lower == "sabre")
794  return SABRE;
795  if(lower == "scimitar")
796  return SCIMITAR;
797  if(lower == "harpoon")
798  return HARPOON;
799  if(lower == "glaive")
800  return GLAIVE;
801  return NO_MODEL;
802 }
803 
805  switch(model){
806  case K63:
807  return "k63";
808  case K65:
809  return "k65";
810  case K68:
811  return "k68";
812  case K70:
813  return "k70";
814  case K95:
815  return "k95";
816  case K95P:
817  return "k95P";
818  case STRAFE:
819  return "strafe";
820  case M65:
821  return "m65";
822  case SABRE:
823  return "sabre";
824  case SCIMITAR:
825  return "scimitar";
826  case HARPOON:
827  return "harpoon";
828  case GLAIVE:
829  return "glaive";
830  default:
831  return "";
832  }
833 }
834 
835 KeyMap KeyMap::fromName(const QString &name){
836  QStringList list = name.trimmed().split(" ");
837  if(list.length() != 2)
838  return KeyMap();
839  return KeyMap(getModel(list[0]), getLayout(list[1]));
840 }
841 
843  switch(model){
844  case K63:
845  return K63_WIDTH;
846  case K65:
847  return K65_WIDTH;
848  case K68:
849  return K68_WIDTH;
850  case K70:
851  return K70_WIDTH;
852  case K95:
853  return K95_WIDTH;
854  case K95P:
855  return K95P_WIDTH;
856  case STRAFE:
857  return KSTRAFE_WIDTH;
858  case M65:
859  case SABRE:
860  case SCIMITAR:
861  case HARPOON:
862  case GLAIVE:
863  return M65_WIDTH;
864  default:
865  return 0;
866  }
867 }
868 
870  switch(model){
871  case K63:
872  case K65:
873  case K68:
874  case K70:
875  case K95:
876  case STRAFE:
877  return K95_HEIGHT;
878  case K95P:
879  return K95P_HEIGHT;
880  case M65:
881  case SABRE:
882  case SCIMITAR:
883  case HARPOON:
884  case GLAIVE:
885  return M65_HEIGHT;
886  default:
887  return 0;
888  }
889 }
890 
891 KeyMap::KeyMap(Model _keyModel, Layout _keyLayout) :
892  _keys(getMap(_keyModel, _keyLayout)),
893  keyWidth(modelWidth(_keyModel)), keyHeight(modelHeight(_keyModel)),
894  keyModel(_keyModel), keyLayout(_keyLayout)
895 {}
896 
898  keyWidth(0), keyHeight(0),
899  keyModel(NO_MODEL), keyLayout(NO_LAYOUT)
900 {}
901 
902 QStringList KeyMap::byPosition() const {
903  // Use QMaps to order the keys
904  QMap<int, QMap<int, QString> > ordered;
905  QHashIterator<QString, Key> i(*this);
906  while(i.hasNext()){
907  i.next();
908  const Key& key = i.value();
909  ordered[key.y][key.x] = i.key();
910  }
911  // Merge them into a single list
912  QStringList result;
913  QMapIterator<int, QMap<int, QString> > y(ordered);
914  while(y.hasNext()){
915  y.next();
916  QMapIterator<int, QString> x(y.value());
917  while(x.hasNext()){
918  x.next();
919  result << x.value();
920  }
921  }
922  return result;
923 }
924 
925 QString KeyMap::friendlyName(const QString& key, Layout layout){
926  // Try K95 map first
927  // FIXME: This is an odd function and probably should be refactored
928  // it would probably be best to remove the friendly names from the maps and have a completely separate name->friendlyName store
929  KeyMap map(K95, layout);
930  if(map.contains(key))
931  return map[key].friendlyName();
932 
933  // The only key missing from it should be Fn, which is found on STRAFE
934  map = KeyMap(STRAFE, layout);
935  if(map.contains(key))
936  return map[key].friendlyName();
937 
938  // Additionally, there are a handful of keys not present on any physical keyboard, but we need names for them
939  if(key == "f13" || key == "f14" || key == "f15" || key == "f16" || key == "f17" || key == "f18" || key == "f19" || key == "f20")
940  return key.toUpper();
941  else if(key == "lightup")
942  return "Screen Brightness Up";
943  else if(key == "lightdn")
944  return "Screen Brightness Down";
945  else if(key == "eject" || key == "power")
946  return key[0].toUpper() + key.mid(1); // capitalize first letter
947 
948  // All other names are found on mice
949  map = KeyMap(SCIMITAR, layout);
950  if(map.contains(key))
951  return map[key].friendlyName();
952  map = KeyMap(M65, layout);
953  if(map.contains(key))
954  return map[key].friendlyName();
955  map = KeyMap(HARPOON, layout);
956  if(map.contains(key))
957  return map[key].friendlyName();
958 
959  // Not found at all
960  return "";
961 }
Layout
Definition: keymap.h:70
static const KeyPatch patchDE[]
Definition: keymap.cpp:57
static QHash< QString, Key > getMap(KeyMap::Model model, KeyMap::Layout layout)
Definition: keymap.cpp:344
#define N_MODELS
Definition: keymap.cpp:340
static void patchJP106(QHash< QString, Key > &map)
Definition: keymap.cpp:154
KeyMap()
Definition: keymap.cpp:897
float y
Definition: main.c:66
static const KeyPatch patchEU[]
Definition: keymap.cpp:45
QStringList byPosition() const
Definition: keymap.cpp:902
#define K95P_WIDTH
Definition: keymap.cpp:217
static void patchABNT2(QHash< QString, Key > &map)
Definition: keymap.cpp:198
static QString friendlyName(const QString &key, Layout layout=US)
Definition: keymap.cpp:925
#define NS
Definition: keymap.cpp:6
#define K65_TOP_COUNT
Definition: keymap.cpp:243
#define KEYCOUNT_HARPOON
Definition: keymap.cpp:295
#define ANSI_ENTER_W
Definition: keymap.cpp:26
static const KeyPatch patchFR[]
Definition: keymap.cpp:50
static const KeyPatch patchJP[]
Definition: keymap.cpp:106
const char * _storageName
Definition: keymap.cpp:33
float x
Definition: main.c:66
static QStringList layoutNames()
Definition: keymap.cpp:757
short width
Definition: keymap.h:17
static const Key K65TopRow[]
Definition: keymap.cpp:240
#define K70_WIDTH
Definition: keymap.cpp:221
#define K68_WIDTH
Definition: keymap.cpp:224
#define KEYCOUNT_GLAIVE
Definition: keymap.cpp:307
#define KSTRAFE_X_START
Definition: keymap.cpp:251
static const KeyPatch patchMX[]
Definition: keymap.cpp:78
static Model getModel(const QString &name)
Definition: keymap.cpp:775
static const Key K95PLbar[]
Definition: keymap.cpp:330
static const KeyPatch patchIT[]
Definition: keymap.cpp:64
#define ANSI_ENTER_H
Definition: keymap.cpp:27
short height
Definition: keymap.h:17
static const Key GlaiveKeys[]
Definition: keymap.cpp:301
#define K63_WIDTH
Definition: keymap.cpp:232
bool contains(const QString &name) const
Definition: keymap.h:143
Definition: keymap.h:49
static const Key K68TopRow[]
Definition: keymap.cpp:235
#define ANSI_ENTER_X
Definition: keymap.cpp:24
const char * name
Definition: keymap.cpp:35
const char * _storageName
Definition: keymap.h:10
#define KEYCOUNT_M65
Definition: keymap.cpp:270
static const KeyPatch patchDK[]
Definition: keymap.cpp:38
static const Key KStrafeKeys[]
Definition: keymap.cpp:255
#define LBARCOUNT_K95P
Definition: keymap.cpp:336
static Layout getLayout(const QString &name)
Definition: keymap.cpp:677
#define K95P_X_START
Definition: keymap.cpp:216
#define K95P_HEIGHT
Definition: keymap.cpp:215
static const KeyPatch patchES[]
Definition: keymap.cpp:92
static void patchISO(QHash< QString, Key > &map)
Definition: keymap.cpp:137
bool isJP() const
Definition: keymap.h:99
static QHash< QString, Key > standardMaps[KeyMap::_MODEL_MAX][KeyMap::_LAYOUT_MAX]
Definition: keymap.cpp:343
#define KSTRAFE_WIDTH
Definition: keymap.cpp:252
static void patchANSI(QHash< QString, Key > &map)
Definition: keymap.cpp:141
static const Key K95Keys[]
Definition: keymap.cpp:12
#define KSTRAFE_HEIGHT
Definition: keymap.cpp:253
const QHash< QString, Key > & map() const
Definition: keymap.h:145
#define K95_WIDTH
Definition: keymap.cpp:212
#define K70_X_START
Definition: keymap.cpp:220
short x
Definition: keymap.h:16
const char * name
Definition: keymap.h:50
#define ANSI_ENTER_Y
Definition: keymap.cpp:25
static const KeyPatch patchPTBR[]
Definition: keymap.cpp:85
bool isISO() const
Definition: keymap.h:95
#define N_LAYOUTS
Definition: keymap.cpp:341
static QHash< QString, Key > K95BaseMap
Definition: keymap.cpp:342
#define K95_HEIGHT
Definition: keymap.cpp:213
static void patchnonJP106(QHash< QString, Key > &map)
Definition: keymap.cpp:130
Model
Definition: keymap.h:51
#define K65_WIDTH
Definition: keymap.cpp:228
#define patch(map, patches)
Definition: keymap.cpp:120
static int modelWidth(Model model)
Definition: keymap.cpp:842
Definition: keymap.h:8
const char * _friendlyName
Definition: keymap.cpp:34
Definition: keymap.h:49
#define KEYCOUNT_K95
Definition: keymap.cpp:21
static const KeyPatch patchNO[]
Definition: keymap.cpp:71
#define K63_TOP_COUNT
Definition: keymap.cpp:248
static Layout locale()
Definition: keymap.cpp:641
static const Key M65Keys[]
Definition: keymap.cpp:263
static void patchJP106fn(QHash< QString, Key > &map)
Definition: keymap.cpp:189
static const Key SabreKeys[]
Definition: keymap.cpp:276
static const Key ScimKeys[]
Definition: keymap.cpp:313
#define M65_WIDTH
Definition: keymap.cpp:272
static KeyMap fromName(const QString &name)
Definition: keymap.cpp:835
bool isPTBR() const
Definition: keymap.h:103
#define ANSI_LSHIFT_X
Definition: keymap.cpp:28
static int modelHeight(Model model)
Definition: keymap.cpp:869
const char * _friendlyName
Definition: keymap.h:13
static void _patch(QHash< QString, Key > &map, const KeyPatch *patches, int patchCount)
Definition: keymap.cpp:121
#define LBS
Definition: keymap.cpp:9
#define KEYCOUNT_SCIM
Definition: keymap.cpp:324
static const Key K63TopRow[]
Definition: keymap.cpp:245
#define K68_TOP_COUNT
Definition: keymap.cpp:238
#define ANSI_LSHIFT_W
Definition: keymap.cpp:29
static const Key HarpoonKeys[]
Definition: keymap.cpp:289
static const KeyPatch patchSE[]
Definition: keymap.cpp:99
#define M65_HEIGHT
Definition: keymap.cpp:273
#define KEYCOUNT_SABRE
Definition: keymap.cpp:283
short y
Definition: keymap.h:16
static const KeyPatch patchDvorak[]
Definition: keymap.cpp:111