1#[macro_use]
2extern crate lazy_static;
3extern crate petgraph;
4
5pub use petgraph::graphmap::DiGraphMap;
6
7pub type Keyboard = DiGraphMap<Key, Edge>;
8
9#[derive(Hash, Debug, Clone, Copy, Ord, PartialOrd, Eq, PartialEq)]
11pub struct Key {
12 pub value: char,
14 pub shifted: char,
16}
17
18impl Key {
19 pub fn is_shifted(&self, val: char) -> bool {
20 self.shifted == val && val != '\0'
21 }
22
23 pub fn is_unshifted(&self, val: char) -> bool {
24 self.value == val && val != '\0'
25 }
26}
27
28#[test]
29fn is_shifted_test() {
30 let t = Key {
31 value: 'a',
32 shifted: 'A'
33 };
34 assert!(t.is_shifted('A'));
35 assert!(t.is_unshifted('a'));
36 assert!(!t.is_shifted('a'));
37 assert!(!t.is_unshifted('A'));
38 assert!(!(t.is_shifted('Y') || t.is_unshifted('y')));
39}
40
41pub trait KeySearch {
45 fn find_key(&self, v: char) -> Option<Key>;
48}
49
50impl KeySearch for DiGraphMap<Key, Edge> {
52 fn find_key(&self, v: char) -> Option<Key> {
53 if v == '\0' {
54 None
55 } else {
56 self.nodes().filter(|x| x.value == v || x.shifted == v).nth(0)
57 }
58 }
59}
60
61#[derive(Debug, PartialEq, Clone, Copy)]
64pub enum Direction {
65 Previous = -1,
67 Next = 1,
69 Same = 0,
71}
72
73#[derive(Debug, PartialEq, Clone, Copy)]
76pub struct Edge {
77 pub horizontal: Direction,
79 pub vertical: Direction,
81}
82
83#[derive(PartialEq)]
88enum KeyboardStyle {
89 Slanted,
91 Aligned,
93}
94
95fn get_slanted_positions() -> Vec<Edge> {
98 use Direction::{Previous, Next, Same};
99 vec![
100 Edge{ horizontal: Previous, vertical: Same },
101 Edge{ horizontal: Same, vertical: Previous },
102 Edge{ horizontal: Next, vertical: Previous },
103 Edge{ horizontal: Next, vertical: Same },
104 Edge{ horizontal: Same, vertical: Next },
105 Edge{ horizontal: Previous, vertical: Next },
106 ]
107}
108
109fn get_aligned_positions() -> Vec<Edge> {
112 use Direction::{Previous, Next, Same};
113 vec![
114 Edge{ horizontal: Previous, vertical: Same },
115 Edge{ horizontal: Previous, vertical: Previous },
116 Edge{ horizontal: Same, vertical: Previous },
117 Edge{ horizontal: Next, vertical: Previous },
118 Edge{ horizontal: Next, vertical: Same },
119 Edge{ horizontal: Next, vertical: Next },
120 Edge{ horizontal: Same, vertical: Next },
121 Edge{ horizontal: Previous, vertical: Next },
122 ]
123}
124
125lazy_static! {
127 pub static ref QWERTY_US: Keyboard = generate_qwerty_us();
128 pub static ref QWERTY_UK: Keyboard = generate_qwerty_uk();
129 pub static ref DVORAK: Keyboard = generate_dvorak();
130 pub static ref STANDARD_NUMPAD: Keyboard = generate_standard_numpad();
131 pub static ref MAC_NUMPAD: Keyboard = generate_mac_numpad();
132}
133
134
135static ALPHABET: &'static str = "abcdefghijklmnopqrstuvwxyz";
137static NUMBERS: &'static str = "0123456789";
138
139
140fn add_alphabetics(graph: &mut Keyboard) {
147 for c in ALPHABET.chars() {
148 graph.add_node(Key {
149 value: c,
150 shifted: c.to_uppercase().nth(0).unwrap(),
151 });
152 }
153}
154
155fn add_unshifted_number_keys(graph: &mut Keyboard) {
161
162 for c in NUMBERS.chars() {
163 graph.add_node(Key {
164 value: c,
165 shifted: '\0',
166 });
167 }
168}
169
170
171fn connect_keyboard_nodes(keyboard: &str,
182 graph: &mut Keyboard,
183 style: KeyboardStyle,
184 add_missing_keys: bool) {
185
186 let relative_positions = if style == KeyboardStyle::Slanted {
187 get_slanted_positions()
188 } else {
189 get_aligned_positions()
190 };
191 let rows = keyboard.lines()
192 .map(|x| x.chars().filter(|y| y != &' ').collect::<Vec<char>>())
193 .collect::<Vec<Vec<char>>>();
194
195 let rowcount = rows.iter().count() as i32;
196 for (i, row) in rows.iter().enumerate() {
197 for (j, key) in row.iter().enumerate() {
198 let k = graph.find_key(*key);
200 if k.is_none() && !add_missing_keys {
201 continue;
202 }
203 let k = if k.is_some() {
204 k.unwrap()
205 } else {
206 Key {
207 value: *key,
208 shifted: '\0',
209 }
210 };
211
212 for dir in relative_positions.iter() {
213 let y: i32 = i as i32 + dir.vertical as i32;
214 let x: i32 = j as i32 + dir.horizontal as i32;
215 if y > -1 && y < rowcount && x > -1 {
216 let temp_row = if dir.vertical == Direction::Same {
217 row
218 } else {
219 rows.get(y as usize).unwrap()
220 };
221
222 if let Some(temp_char) = temp_row.get(x as usize) {
223
224 let n = graph.find_key(*temp_char);
225
226 if n.is_none() && !add_missing_keys {
227 continue;
228 }
229
230 let n = if n.is_some() {
231 n.unwrap()
232 } else {
233 Key {
234 value: *temp_char,
235 shifted: '\0',
236 }
237 };
238
239 graph.add_edge(k, n, *dir);
240 }
241 }
242 }
243 }
244 }
245}
246
247fn add_remaining_keys(keys: Vec<Key>, graph: &mut Keyboard) {
250
251 for k in keys.iter() {
252 graph.add_node(k.clone());
253 }
254}
255
256pub fn generate_qwerty_us() -> Keyboard {
258 let mut result = DiGraphMap::<Key, Edge>::new();
259 let qwerty_us = "` 1 2 3 4 5 6 7 8 9 0 - =\n\
262 \0 q w e r t y u i o p [ ] \\\n\
263 \0 a s d f g h j k l ; '\n\
264 \0 z x c v b n m , . /";
265
266 add_alphabetics(&mut result);
267
268 let remaining_keys = vec![
269 Key{ value: '`', shifted: '~'},
270 Key{ value: '1', shifted: '!'},
271 Key{ value: '2', shifted: '@'},
272 Key{ value: '3', shifted: '#'},
273 Key{ value: '4', shifted: '$'},
274 Key{ value: '5', shifted: '%'},
275 Key{ value: '6', shifted: '^'},
276 Key{ value: '7', shifted: '&'},
277 Key{ value: '8', shifted: '*'},
278 Key{ value: '9', shifted: '('},
279 Key{ value: '0', shifted: ')'},
280 Key{ value: '-', shifted: '_'},
281 Key{ value: '=', shifted: '+'},
282 Key{ value: '[', shifted: '{'},
283 Key{ value: ']', shifted: '}'},
284 Key{ value: '\\', shifted: '|'},
285 Key{ value: ';', shifted: ':'},
286 Key{ value: '\'', shifted: '\"'},
287 Key{ value: ',', shifted: '<'},
288 Key{ value: '.', shifted: '>'},
289 Key{ value: '/', shifted: '?'}
290 ];
291 add_remaining_keys(remaining_keys, &mut result);
292
293 connect_keyboard_nodes(qwerty_us, &mut result, KeyboardStyle::Slanted, false);
294
295 result
296}
297
298pub fn generate_qwerty_uk() -> Keyboard {
300 let mut result = DiGraphMap::<Key, Edge>::new();
301 let qwerty_uk = "` 1 2 3 4 5 6 7 8 9 0 - =\n\
304 \0 q w e r t y u i o p [ ] \\\n\
305 \0 a s d f g h j k l ; ' #\n\
306 \0 z x c v b n m , . /";
307
308 add_alphabetics(&mut result);
309
310 let remaining_keys = vec![
311 Key{ value: '`', shifted: '¬'},
312 Key{ value: '1', shifted: '!'},
313 Key{ value: '2', shifted: '\"'},
314 Key{ value: '3', shifted: '£'},
315 Key{ value: '4', shifted: '$'},
316 Key{ value: '5', shifted: '%'},
317 Key{ value: '6', shifted: '^'},
318 Key{ value: '7', shifted: '&'},
319 Key{ value: '8', shifted: '*'},
320 Key{ value: '9', shifted: '('},
321 Key{ value: '0', shifted: ')'},
322 Key{ value: '-', shifted: '_'},
323 Key{ value: '=', shifted: '+'},
324 Key{ value: '[', shifted: '{'},
325 Key{ value: ']', shifted: '}'},
326 Key{ value: '\\', shifted: '|'},
327 Key{ value: ';', shifted: ':'},
328 Key{ value: '\'', shifted: '@'},
329 Key{ value: ',', shifted: '<'},
330 Key{ value: '.', shifted: '>'},
331 Key{ value: '/', shifted: '?'},
332 Key{ value: '#', shifted: '~'}
333 ];
334 add_remaining_keys(remaining_keys, &mut result);
335
336 connect_keyboard_nodes(qwerty_uk, &mut result, KeyboardStyle::Slanted, false);
337
338 result
339}
340
341pub fn generate_dvorak() -> Keyboard {
343 let mut result = DiGraphMap::<Key, Edge>::new();
344 let qwerty_us = "` 1 2 3 4 5 6 7 8 9 0 [ ]\n\
347 \0 ' , . p y f g c r l / = \\\n\
348 \0 a o e u i d h t n s -\n\
349 \0 ; q j k x b m w v z";
350
351 add_alphabetics(&mut result);
352
353 let remaining_keys = vec![
354 Key{ value: '`', shifted: '~'},
355 Key{ value: '1', shifted: '!'},
356 Key{ value: '2', shifted: '@'},
357 Key{ value: '3', shifted: '#'},
358 Key{ value: '4', shifted: '$'},
359 Key{ value: '5', shifted: '%'},
360 Key{ value: '6', shifted: '^'},
361 Key{ value: '7', shifted: '&'},
362 Key{ value: '8', shifted: '*'},
363 Key{ value: '9', shifted: '('},
364 Key{ value: '0', shifted: ')'},
365 Key{ value: '-', shifted: '_'},
366 Key{ value: '=', shifted: '+'},
367 Key{ value: '[', shifted: '{'},
368 Key{ value: ']', shifted: '}'},
369 Key{ value: '\\', shifted: '|'},
370 Key{ value: ';', shifted: ':'},
371 Key{ value: '\'', shifted: '\"'},
372 Key{ value: ',', shifted: '<'},
373 Key{ value: '.', shifted: '>'},
374 Key{ value: '/', shifted: '?'}
375 ];
376 add_remaining_keys(remaining_keys, &mut result);
377
378 connect_keyboard_nodes(qwerty_us, &mut result, KeyboardStyle::Slanted, false);
379
380 result
381}
382
383pub fn generate_standard_numpad() -> Keyboard {
385 let mut result = DiGraphMap::<Key, Edge>::new();
386 let numpad = "\0 / * -\n7 8 9 +\n4 5 6\n1 2 3\n\0 0 .";
387
388 add_unshifted_number_keys(&mut result);
389
390 connect_keyboard_nodes(numpad, &mut result, KeyboardStyle::Aligned, true);
391 result
392}
393
394
395pub fn generate_mac_numpad() -> Keyboard {
397 let mut result = DiGraphMap::<Key, Edge>::new();
398 let numpad = "\0 = / *\n7 8 9 -\n4 5 6 +\n1 2 3\n\0 0 .";
399
400 connect_keyboard_nodes(numpad, &mut result, KeyboardStyle::Aligned, true);
401 result
402}
403
404
405#[test]
406fn test_alphabetics() {
407 assert_eq!(ALPHABET.chars().count(), 26);
408
409 let mut result = DiGraphMap::<Key, Edge>::new();
410 add_alphabetics(&mut result);
411
412 let uppercase = ALPHABET.to_uppercase();
413 for (l, u) in ALPHABET.chars().zip(uppercase.chars()) {
414 let test = Key {
415 value: l,
416 shifted: u
417 };
418 assert!(result.contains_node(test));
419 assert!(result.find_key(l).is_some());
421 assert!(result.find_key(u).is_some());
422 }
423}
424
425#[test]
426fn test_add_number_keys() {
427 assert_eq!(NUMBERS.chars().count(), 10);
428
429 let mut result = DiGraphMap::<Key, Edge>::new();
430 add_unshifted_number_keys(&mut result);
431 for c in NUMBERS.chars() {
432 let test = Key {
433 value: c,
434 shifted: '\0'
435 };
436 assert!(result.contains_node(test));
437 assert!(result.find_key(c).is_some());
438 }
439 assert!(result.find_key('\0').is_none());
440}