Name | Total Lines | Lines of Code | Total Coverage | Code Coverage |
---|---|---|---|---|
lib/twiddler/config.rb | 414 | 356 | 93.96%
|
92.98%
|
Code reported as executed by Ruby looks like this...and this: this line is also marked as covered.Lines considered as run by rcov, but not reported by Ruby, look like this,and this: these lines were inferred by rcov (using simple heuristics).Finally, here's a line marked as not executed.
1 module Twiddler |
2 class Config |
3 class KeyTable |
4 class KeyData |
5 ModAliases = Hash.new{|h,k| k}.merge!( |
6 "rsft" => "shift", |
7 "lsft" => "shift", |
8 "rctl" => "control", |
9 "lctl" => "control", |
10 "lalt" => "alt", |
11 "ralt" => "alt", |
12 "lgui" => "gui", |
13 "rgui" => "gui" |
14 ) |
15 |
16 def initialize(num, name) |
17 @code = num |
18 @data = { :unmod => name } |
19 @tags = {} |
20 end |
21 attr_reader :code |
22 |
23 def tag(name) |
24 @tags[name.to_sym] = true |
25 end |
26 |
27 def tag?(name) |
28 @tags.has_key?(name) |
29 end |
30 |
31 def modified(mod, value) |
32 @data[normalized(mod)] = value |
33 end |
34 |
35 def string(mod=nil) |
36 return @data[:unmod] if mod.nil? or mod.empty? |
37 if data = @data[normalized(mod)] |
38 return data |
39 else |
40 return "#{mod}-#{@data[:unmod]}" |
41 end |
42 end |
43 |
44 def has_mod?(mod) |
45 @data.has_key?(normalized(mod)) |
46 end |
47 |
48 def ===(chord) |
49 chord.single? and chord[0][0] == @code |
50 end |
51 |
52 def self.normalized(mod) |
53 unless Array === mod |
54 mod = mod.split("-") |
55 end |
56 return mod.map{|i| ModAliases[i.downcase]}.sort.join("-") |
57 end |
58 |
59 def normalized(mod) |
60 self.class.normalized(mod) |
61 end |
62 end |
63 |
64 def initialize |
65 @data = Hash.new{|h,k| KeyData.new(k, "U/#{k.inspect}")} |
66 @ordered = [] |
67 @current_tags = {} |
68 end |
69 |
70 def normalized(stroke) |
71 mods = KeyData::normalized(stroke[1]) |
72 return [stroke[0], mods] |
73 end |
74 |
75 def unknowns(list) |
76 return list.reject do |item| |
77 @data.has_key?(item) |
78 end |
79 end |
80 |
81 def start_tag(name) |
82 @current_tags[name.to_sym] = true |
83 end |
84 |
85 def end_tag(name) |
86 @current_tags.delete(name.to_sym) |
87 end |
88 |
89 def clear_tags |
90 @current_tags.clear |
91 end |
92 |
93 def tagged(name) |
94 @ordered.find_all do |key| |
95 key.tag?(name) |
96 end |
97 end |
98 |
99 def is_tagged?(idx, tag) |
100 @data[idx].tag?(tag) |
101 end |
102 |
103 def [](idx, mod=nil) |
104 return @data[idx].string(mod) |
105 end |
106 |
107 def []=(idx, value) |
108 if @data.has_key?(idx) |
109 @ordered.delete(@data[idx]) |
110 end |
111 data = KeyData.new(idx, value) |
112 @current_tags.each_key do |name| |
113 data.tag(name) |
114 end |
115 @data[idx] = data |
116 @ordered << data |
117 end |
118 |
119 include Enumerable |
120 def each(&block) |
121 @ordered.each(&block) |
122 end |
123 |
124 def mod(idx, mod, value) |
125 @data[idx].modified(mod, value) |
126 end |
127 end |
128 |
129 def self.keytable |
130 @table ||= |
131 begin |
132 table = KeyTable.new |
133 |
134 table.start_tag(:normal) |
135 table.start_tag(:letters) |
136 (("a".."z").to_a).each_with_index do |ltr, idx| |
137 table[idx+4] = ltr |
138 end |
139 (("A".."Z").to_a).each_with_index do |ltr, idx| |
140 table.mod(idx+4, "shift", ltr) |
141 end |
142 table.end_tag(:letters) |
143 table.start_tag(:numbers) |
144 |
145 (("1".."9").to_a + ["0"]).each_with_index do |num, idx| |
146 table[idx+30] = num |
147 end |
148 %w[! @ # $ % ^ & * ( )].each_with_index do |shift_num, idx| |
149 table.mod(idx+30, "shift", shift_num) |
150 end |
151 table.end_tag(:numbers) |
152 |
153 table.start_tag(:punctuation) |
154 table[45] = "-" |
155 table.mod(45, "shift", "_") |
156 table[46] = "=" |
157 table.mod(46, "shift", "+") |
158 table[47] = "[" |
159 table.mod(47, "shift", "{") |
160 table[48] = "]" |
161 table.mod(48, "shift", "}") |
162 table[49] = "\\" |
163 table.mod(49, "shift", "|") |
164 table[56] = "/" |
165 table.mod(56, "shift", "?") |
166 table[51] = ";" |
167 table.mod(51, "shift", ":") |
168 table[52] = "'" |
169 table.mod(52, "shift", "\"") |
170 table[53] = "`" |
171 table.mod(53, "shift", "~") |
172 table[54] = "," |
173 table.mod(54, "shift", "<") |
174 table[55] = "." |
175 table.mod(55, "shift", ">") |
176 table[73] = "~" |
177 table.clear_tags |
178 |
179 table.start_tag(:special) |
180 table[40] = "<Rtrn>" |
181 table[41] = "<Esc>" |
182 table[42] = "<Bksp>" |
183 table[43] = "<Tab>" |
184 table[44] = "<Spc>" |
185 table[57] = "<Cplk>" |
186 table[71] = "<Scrlk>" |
187 table[74] = "<Home>" |
188 table[75] = "<PgUp>" |
189 table[76] = "<Delete>" |
190 table[77] = "<End>" |
191 table[78] = "<PgDn>" |
192 table[79] = "<Right>" |
193 table[80] = "<Left>" |
194 table[81] = "<Down>" |
195 table[82] = "<Up>" |
196 table[83] = "<Nmlk>" |
197 |
198 table.start_tag(:fkeys) |
199 ("1".."12").to_a.each_with_index do |fkey, idx| |
200 table[idx+58] = "F" + fkey |
201 end |
202 table.end_tag(:fkeys) |
203 |
204 table.start_tag(:hardware_control) |
205 table[-2] = "<<Mass Storage Mode>>" |
206 table[-3] = "<<Upgrade Mode>>" |
207 table[-4] = "<<Disable Mouse Mode>>" |
208 table[-5] = "<<Enable Mouse Mode>>" |
209 table.clear_tags |
210 |
211 table |
212 end |
213 end |
214 |
215 class Chord |
216 def initialize |
217 @rows = [:open, :open, :open, :open] |
218 @mods = {:num => false, |
219 :shift => false, :ctrl => false, :alt => false} |
220 end |
221 |
222 attr_reader :rows, :mods |
223 |
224 def extract_key(bits, idx, mod, range) |
225 @rows[idx] = case bits[range] |
226 when /1.../; :left |
227 when /.1../; :middle |
228 when /..1./; :right |
229 else :open |
230 end |
231 @mods[mod] = (bits[range.last] == ?1) |
232 |
233 end |
234 |
235 def keydata=(bits) |
236 extract_key(bits, 0, :num, 4..7) |
237 extract_key(bits, 1, :alt, 0..3) |
238 extract_key(bits, 2, :ctrl, 12..15) |
239 extract_key(bits, 3, :shift, 8..11) |
240 end |
241 |
242 def render_keys |
243 mods = |
244 (@mods[:num] ? "N" : "") + |
245 (@mods[:alt] ? "A" : "") + |
246 (@mods[:ctrl] ? "C" : "") + |
247 (@mods[:shift] ? "S" : "") |
248 if mods.empty? |
249 mods = "O" |
250 end |
251 |
252 chord = rows.map do |row| |
253 case row |
254 when :open; "O" |
255 when :left; "L" |
256 when :right; "R" |
257 when :middle; "M" |
258 else "wtf?" |
259 end |
260 end.join("") |
261 |
262 return "#{mods} #{chord}" |
263 end |
264 |
265 def render_action |
266 "" |
267 end |
268 |
269 def render |
270 "#{render_keys} => #{render_action}" |
271 end |
272 end |
273 |
274 class KeyChord < Chord |
275 ModKeys = %w{RGui RAlt RSft RCtl LGui LAlt LSft LCtl} |
276 |
277 def initialize |
278 super |
279 @keystrokes = [] |
280 end |
281 |
282 attr_reader :keystrokes |
283 |
284 def [](idx) |
285 @keystrokes[idx] |
286 end |
287 |
288 def single? |
289 @keystrokes.length == 1 |
290 end |
291 |
292 def add_keystroke(mod_bits, idx) |
293 mods = ModKeys.zip(mod_bits.split('')).delete_if{|mod,bit| bit != "1"}.map{|mod,bit| mod} |
294 @keystrokes << [idx, mods] |
295 end |
296 |
297 def keytable |
298 Config.keytable |
299 end |
300 |
301 def render_action |
302 output = [] |
303 (@keystrokes || []).each do |code, mods| |
304 output << keytable[code, mods] |
305 end |
306 |
307 return output.join() |
308 end |
309 end |
310 |
311 class MouseChord < Chord |
312 |
313 def initialize |
314 super |
315 @mods = { |
316 :ctrl => false, |
317 :alt => false, |
318 :shift => false, |
319 :double => false, |
320 :toggle => false |
321 } |
322 @buttons = { |
323 :left => false, |
324 :middle => false, |
325 :right => false |
326 } |
327 end |
328 |
329 attr_reader :mods, :buttons |
330 |
331 def data=(bits) |
332 if bits[0] == ?1 |
333 @mods[:ctrl] = true |
334 end |
335 if bits[1] == ?1 |
336 @mods[:alt] = true |
337 end |
338 if bits[2] == ?1 |
339 @mods[:shift] = true |
340 end |
341 if bits[3] == ?1 |
342 @mods[:double] = true |
343 end |
344 if bits[4] == ?1 |
345 @mods[:toggle] = true |
346 end |
347 if bits[5] == ?1 |
348 @buttons[:middle] = true |
349 end |
350 if bits[6] == ?1 |
351 @buttons[:right] = true |
352 end |
353 if bits[7] == ?1 |
354 @buttons[:left] = true |
355 end |
356 end |
357 |
358 def render_action |
359 action = "" |
360 if @mods[:ctrl] |
361 action << "Ctl-" |
362 end |
363 if @mods[:alt] |
364 action << "Alt-" |
365 end |
366 if @mods[:shift] |
367 action << "Shf-" |
368 end |
369 if @mods[:double] |
370 action << "Dbl-" |
371 end |
372 if @mods[:toggle] |
373 action << "Tgl-" |
374 end |
375 if @buttons[:middle] |
376 action << "M" |
377 end |
378 if @buttons[:right] |
379 action << "R" |
380 end |
381 if @buttons[:left] |
382 action << "L" |
383 end |
384 return action |
385 end |
386 end |
387 |
388 |
389 def initialize() |
390 @mouse = [] |
391 @keyboard = [] |
392 @configs = {} |
393 end |
394 |
395 def keytable |
396 self.class.keytable |
397 end |
398 |
399 attr_reader :mouse, :keyboard, :configs |
400 |
401 def inspect |
402 "<Twiddler::Config: \n " + |
403 "Config: #{@configs.inspect}\n " + |
404 @keyboard.map do |chord| |
405 chord.render |
406 end.join("\n ") + |
407 "\n ---\n " + |
408 @mouse.map do |chord| |
409 chord.render |
410 end.join("\n ") + "\n" + |
411 ">" |
412 end |
413 end |
414 end |
Generated on Tue May 03 12:22:31 -0700 2011 with rcov 0.9.7.1