1 module scone.input.os.posix.keyboard_event_tree;
2 
3 version (Posix)
4 {
5     import scone.input.scone_control_key : SCK;
6     import scone.input.scone_key : SK;
7     import scone.input.keyboard_event : KeyboardEvent;
8     import std.typecons : Nullable;
9 
10     // todo this logic for inserting values has some problems
11     // i believe it does not safeguard a node from having both children and a value
12     // also, getting multiple inputs from a sequence is not 100% reliable. it should work for known sequences, but i would not consider this reliable yet.
13     class KeyboardEventTree
14     {
15         public KeyboardEvent[] find(uint[] sequence)
16         {
17             assert(sequence.length);
18 
19             // special case for escape key until i figure out this logic
20             if (sequence == [27])
21             {
22                 return [KeyboardEvent(SK.escape, SCK.none)];
23             }
24 
25             KeyboardEvent[] keypresses = [];
26             auto node = this.root;
27 
28             foreach (n, number; sequence)
29             {
30                 const bool hasNodeChild = (number in node.children) !is null;
31 
32                 if (node.value.isNull() && !hasNodeChild)
33                 {
34                     if (!(keypresses.length && keypresses[$ - 1].key == SK.unknown))
35                     {
36                         keypresses ~= KeyboardEvent(SK.unknown, SCK.none);
37                     }
38 
39                     node = this.root;
40                     continue;
41                 }
42 
43                 if (hasNodeChild)
44                 {
45                     node = node.children[number];
46                 }
47 
48                 if (!node.value.isNull())
49                 {
50                     keypresses ~= node.value.get();
51                     node = this.root;
52                     continue;
53                 }
54             }
55 
56             return keypresses;
57         }
58 
59         public bool insert(in uint[] sequence, KeyboardEvent data)
60         {
61             // special case for escape key until i figure out this logic
62             if (sequence == [27])
63             {
64                 return true;
65             }
66 
67             auto node = this.root;
68 
69             foreach (number; sequence)
70             {
71                 if ((number in node.children) is null)
72                 {
73                     if (!node.value.isNull())
74                     {
75                         return false;
76                     }
77 
78                     node.children[number] = new KeyboardEventNode();
79                 }
80 
81                 node = node.children[number];
82             }
83 
84             node.value = data;
85 
86             return true;
87         }
88 
89         private KeyboardEventNode root = new KeyboardEventNode();
90     }
91 
92     unittest
93     {
94         auto tree = new KeyboardEventTree();
95         tree.insert([27], KeyboardEvent(SK.escape, SCK.none));
96         tree.insert([27, 91, 67], KeyboardEvent(SK.right, SCK.none));
97         tree.insert([27, 91, 66], KeyboardEvent(SK.down, SCK.none));
98         tree.insert([48], KeyboardEvent(SK.key_0, SCK.none));
99         tree.insert([49], KeyboardEvent(SK.key_1, SCK.none));
100 
101         KeyboardEvent[] find;
102 
103         find = tree.find([1]);
104         assert(find.length == 1);
105         assert(SK.unknown == find[0].key);
106 
107         find = tree.find([48]);
108         assert(find.length == 1);
109         assert(SK.key_0 == find[0].key);
110 
111         find = tree.find([27]);
112         assert(find.length == 1);
113         assert(SK.escape == find[0].key);
114 
115         find = tree.find([27, 91, 67]);
116         assert(find.length == 1);
117         assert(SK.right == find[0].key);
118 
119         find = tree.find([27, 91, 66]);
120         assert(find.length == 1);
121         assert(SK.down == find[0].key);
122 
123         find = tree.find([48, 49]);
124         assert(find.length == 2);
125         assert(SK.key_0 == find[0].key);
126         assert(SK.key_1 == find[1].key);
127 
128         find = tree.find([27, 91, 67, 27, 91, 66]);
129         assert(find.length == 2);
130         assert(SK.right == find[0].key);
131         assert(SK.down == find[1].key);
132 
133         find = tree.find([27, 6, 67, 27, 91, 66]);
134         assert(find.length == 2);
135         assert(SK.unknown == find[0].key);
136         assert(SK.down == find[1].key);
137     }
138 
139     private class KeyboardEventNode
140     {
141         KeyboardEventNode[uint] children;
142         Nullable!KeyboardEvent value;
143     }
144 }