fingerpoken 0.2.20101209171641 → 0.2.20101216024109

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/bin/fingerpoken.rb CHANGED
@@ -26,19 +26,38 @@ class FingerPoken < Sinatra::Base
26
26
  end
27
27
 
28
28
  def main(args)
29
+ targets = []
29
30
  opts = OptionParser.new do |opts|
31
+ opts.banner = "Usage: #{$0} [options]"
32
+
33
+ opts.on("-t TARGET", "--target TARGET",
34
+ "Target a url. Can be given multiple times to target multiple things.") do |url|
35
+ target = URI.parse(url)
36
+ case target.scheme
37
+ when "xdo"
38
+ require "fingerpoken/#{target.scheme}"
39
+ targets << [:Xdo, {}]
40
+ when "vnc"
41
+ require "fingerpoken/#{target.scheme}"
42
+ targets << [:VNC, {}]
43
+ when "tivo"
44
+ require "fingerpoken/#{target.scheme}"
45
+ targets << [:Tivo, { :host => "192.168.0.134" }]
46
+ end
47
+ end
30
48
  end
49
+ opts.parse(args)
50
+
51
+ puts targets
52
+
31
53
  EventMachine::run do
32
54
  $:.unshift(File.dirname(__FILE__) + "/lib")
33
55
  channel = EventMachine::Channel.new
34
56
 
35
- # TODO(sissel): Pick up here and make command flags to choose the
36
- # target (vnc, xdo, etc)
37
- require "fingerpoken/xdo"
38
- target = FingerPoken::Target::Xdo.new :channel => channel
39
-
40
- #require "fingerpoken/vnc"
41
- #target = FingerPoken::Target::VNC.new :channel => channel
57
+ targets.each do |klass, args|
58
+ args.merge!({ :channel => channel })
59
+ puts FingerPoken::Target.const_get(klass).new(args)
60
+ end
42
61
 
43
62
  EventMachine::WebSocket.start(:host => "0.0.0.0", :port => 5001) do |ws|
44
63
  ws.onmessage do |message|
@@ -11,6 +11,8 @@ class FingerPoken::Target
11
11
  case request["action"]
12
12
  when "mousemove_relative"
13
13
  mousemove_relative(request["rel_x"], request["rel_y"])
14
+ when "move_end"
15
+ move_end()
14
16
  when "click"
15
17
  click(request["button"])
16
18
  when "mousedown"
@@ -60,4 +62,8 @@ class FingerPoken::Target
60
62
  def keyup(key)
61
63
  @logger.info("keyup not supported")
62
64
  end
65
+
66
+ def move_end()
67
+ @logger.info("move_end not supported")
68
+ end
63
69
  end # class FingerPoken::Target
@@ -0,0 +1,95 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ # TODO(sissel): Refactor the protocol into an EM::Tivo module.
4
+
5
+ require "rubygems"
6
+ require "fingerpoken/target"
7
+ require "ostruct"
8
+
9
+ class FingerPoken::Target::Tivo < FingerPoken::Target
10
+ def initialize(config)
11
+ super(config)
12
+ # TODO(sissel): Make this a config
13
+ @host = config[:host]
14
+ @tivo = EventMachine::connect(@host, 31339, TivoClient, self)
15
+
16
+ @state = OpenStruct.new # TODO(sissel): Make this not an open struct...
17
+
18
+ @state.speed = 0
19
+ end
20
+
21
+ def mousemove_relative(x, y)
22
+ direction = x < 0 ? -1 : 1
23
+ want_speed = [(x.abs / 30).to_i, 3].min
24
+
25
+ want_speed *= direction
26
+ if want_speed != @state.speed
27
+ p [want_speed]
28
+ end
29
+
30
+ if want_speed > @state.speed
31
+ # increase to it
32
+ 1.upto(want_speed - @state.speed).each do
33
+ puts "UP"
34
+ @tivo.send_data("IRCODE FORWARD\r\n")
35
+ end
36
+ elsif (want_speed < @state.speed)
37
+ 1.upto( (want_speed - @state.speed).abs ).each do
38
+ @tivo.send_data("IRCODE REVERSE\r\n")
39
+ puts "DOWN"
40
+ end
41
+ # decrease to it
42
+ end
43
+ @state.speed = want_speed
44
+ end
45
+
46
+ def move_end
47
+ @tivo.send_data("IRCODE PLAY\r\n")
48
+ end
49
+
50
+ def click(button)
51
+ case button.to_i
52
+ when 1
53
+ @tivo.send_data("IRCODE PAUSE\r\n")
54
+ when 2 # 'middle' click (three fingers)
55
+ @tivo.send_data("IRCODE SELECT\r\n")
56
+ #when 2 # 'middle' click (three fingers)
57
+ #@tivo.send_data("IRCODE TIVO\r\n")
58
+ when 4 # scroll up
59
+ @tivo.send_data("IRCODE UP\r\n")
60
+ when 5 # scroll down
61
+ @tivo.send_data("IRCODE DOWN\r\n")
62
+ end
63
+ end
64
+
65
+ # Hack for now
66
+ def keypress(key)
67
+ case key
68
+ when "Home"
69
+ @tivo.send_data("IRCODE TIVO\r\n")
70
+ when "Return"
71
+ @tivo.send_data("IRCODE SELECT\r\n")
72
+ end
73
+ end
74
+
75
+ class TivoClient < EventMachine::Connection
76
+ def initialize(target)
77
+ puts "init #{self} / #{target}"
78
+ @target = target
79
+ end
80
+
81
+ def connection_completed
82
+ @target.register
83
+ puts "Ready"
84
+ end
85
+
86
+ def receive_data(data)
87
+ p "Tivo says: #{data}"
88
+ end
89
+
90
+ def send_data(data)
91
+ puts "Sending: #{data}"
92
+ super(data)
93
+ end
94
+ end # class TivoClient
95
+ end # class FingerPoken::Target::Tivo
@@ -33,7 +33,6 @@ class FingerPoken::Target::VNC < FingerPoken::Target
33
33
  end
34
34
  end
35
35
 
36
-
37
36
  def mousemove_relative(x, y)
38
37
  @x += x
39
38
  @y += y
@@ -41,14 +40,14 @@ class FingerPoken::Target::VNC < FingerPoken::Target
41
40
  end
42
41
 
43
42
  def mousedown(button)
44
- button = (1 << (button - 1))
43
+ button = (1 << (button.to_i - 1))
45
44
  return if @buttonmask & button != 0
46
45
  @buttonmask |= button
47
46
  update
48
47
  end
49
48
 
50
49
  def mouseup(button)
51
- button = (1 << (button - 1))
50
+ button = (1 << (button.to_i - 1))
52
51
  return if @buttonmask & button == 0
53
52
  @buttonmask &= (~button)
54
53
  update
@@ -62,7 +62,7 @@ class FingerPoken::Target::Xdo < FingerPoken::Target
62
62
  else
63
63
  # type printables, key others.
64
64
  if 32.upto(127).include?(key)
65
- LibXdo::xdo_type(@xdo, 0, request["key"].chr, 12000)
65
+ LibXdo::xdo_type(@xdo, 0, key.chr, 12000)
66
66
  else
67
67
  case key
68
68
  when 8
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
@@ -2,6 +2,19 @@
2
2
  /* TODO(sissel): This could use some serious refactoring. */
3
3
 
4
4
  $(document).ready(function() {
5
+ var status = $("#status");
6
+ var config = function (key, value, default_value) {
7
+ if (value) {
8
+ status.html("config[" + key + "] = " + value);
9
+ //alert(key + " => " + value);
10
+
11
+ window.localStorage[key] = value
12
+ return value
13
+ } else {
14
+ return window.localStorage[key] || default_value
15
+ }
16
+ };
17
+
5
18
  var state = {
6
19
  x: -1,
7
20
  y: -1,
@@ -10,8 +23,27 @@
10
23
  width: window.innerWidth,
11
24
  height: window.innerHeight,
12
25
  key: undefined,
13
- }
14
- var status = $("#status");
26
+ mouse: { },
27
+ scroll: {
28
+ y: 0,
29
+ }
30
+ };
31
+
32
+ /* Sync configuration elements */
33
+
34
+ /* Mouse movement */
35
+ console.log(config("fingerpoken/mouse/movement"));
36
+ $("input[name = \"mouse-config\"]")
37
+ .bind("change", function(event) {
38
+ config("fingerpoken/mouse/movement", event.target.value);
39
+ }).filter("[value = \"" + config("fingerpoken/mouse/movement") + "\"]")
40
+ .attr("checked", "checked").click()
41
+
42
+ $("input[name = \"mouse-acceleration\"]")
43
+ .bind("change", function(event) {
44
+ config("fingerpoken/mouse/acceleration", parseInt(event.target.value));
45
+ //status.html(event.target.value);
46
+ }).val(config("fingerpoken/mouse/acceleration")).change();
15
47
 
16
48
  /* Changing orientation sometimes leaves the viewport
17
49
  * not starting at 0,0. Fix it with this hack.
@@ -70,6 +102,8 @@
70
102
  //});
71
103
 
72
104
 
105
+ /* TODO(sissel): add mousedown/mousemove/mouseup support */
106
+ console.log($("#touchpad-surface"));
73
107
  $("#area").bind("touchstart", function(event) {
74
108
  event.preventDefault();
75
109
  var e = event.originalEvent;
@@ -95,9 +129,15 @@
95
129
  }))
96
130
  state.dragging = true;
97
131
  }
98
- }).bind("touchend", function(event) { /* $("#area").bind("touchend" ... */
132
+ }).bind("touchend", function(event) { /* $("#touchpadsurface").bind("touchend" ... */
99
133
  var e = event.originalEvent;
100
134
  var touches = e.touches;
135
+
136
+ if (state.mouse.vectorTimer) {
137
+ clearInterval(state.mouse.vectorTimer);
138
+ state.mouse.vectorTimer = null;
139
+ }
140
+
101
141
  if (state.dragging) {
102
142
  state.websocket.send(JSON.stringify({
103
143
  action: "mouseup",
@@ -105,7 +145,7 @@
105
145
  }));
106
146
  state.dragging = false;
107
147
  } else {
108
- if (state.moving) {
148
+ if (state.moving && !state.scrolling) {
109
149
  var e = state.last_move;
110
150
  var r = e.rotation;
111
151
  if (r < 0) {
@@ -114,7 +154,7 @@
114
154
 
115
155
  status.html(r);
116
156
  if (r > 75 && r < 105) {
117
- /* Activate the keyboard when there's a 90-dgree rotation*/
157
+ /* Activate the keyboard when there's a ~90-degree rotation*/
118
158
  var keyboard = $("<textarea id='keyboard' rows='10'></textarea>");
119
159
  keyboard.css("width", "100%");
120
160
  keyboard.css("height", "100%");
@@ -184,7 +224,14 @@
184
224
  });
185
225
  //status.html("<textarea id='keyboard'></textarea>");
186
226
  //$("#keyboard").focus();
227
+ } else { /* Otherwise, we didn't rotate */
228
+ state.websocket.send(JSON.stringify({
229
+ action: "move_end",
230
+ now: (new Date()),
231
+ }));
187
232
  }
233
+ } else if (state.scrolling) {
234
+ /* nothing for now */
188
235
  } else {
189
236
  /* No movement, click! */
190
237
  status.html("Click!");
@@ -196,16 +243,17 @@
196
243
  }
197
244
  }
198
245
  state.moving = false;
246
+ state.scrolling = false;
199
247
  event.preventDefault();
200
- }).bind("touchmove", function(event) { /* $("#area").bind("touchmove" ... */
248
+ }).bind("touchmove", function(event) { /* $("#touchpadsurface").bind("touchmove" ... */
201
249
  var e = event.originalEvent;
202
250
  var touches = e.touches;
203
251
  event.preventDefault();
204
252
  if (!state.moving) {
205
253
  /* Start calculating delta offsets now */
206
254
  state.moving = true;
207
- state.x = touches[0].clientX;
208
- state.y = touches[0].clientY;
255
+ state.start_x = state.x = touches[0].clientX;
256
+ state.start_y = state.y = touches[0].clientY;
209
257
  /* Skip this event */
210
258
  return;
211
259
  }
@@ -224,28 +272,33 @@
224
272
  output += "rotation: " + r + "\n";
225
273
  output += "scale: " + e.scale + "\n";
226
274
 
227
- x = touches[0].clientX;
228
- y = touches[0].clientY;
229
- delta_x = (x - state.x);
230
- delta_y = (y - state.y);
275
+ var x = touches[0].clientX;
276
+ var y = touches[0].clientY;
277
+ var delta_x = (x - state.x);
278
+ var delta_y = (y - state.y);
231
279
 
232
280
  /* Apply acceleration */
233
- sign_x = (delta_x < 0 ? -1 : 1);
234
- sign_y = (delta_y < 0 ? -1 : 1);
235
- delta_x = Math.ceil(Math.pow(Math.abs(delta_x), 1.5) * sign_x);
236
- delta_y = Math.ceil(Math.pow(Math.abs(delta_y), 1.5) * sign_y);
281
+ var sign_x = (delta_x < 0 ? -1 : 1);
282
+ var sign_y = (delta_y < 0 ? -1 : 1);
237
283
 
284
+ /* jQuery Mobile or HTML 'range' inputs don't support floating point.
285
+ * Hack around it by using larger numbers and compensating. */
286
+ var accel = config("fingerpoken/mouse/acceleration", null, 150) / 100.0;
287
+ output += "Accel: " + accel + "\n";
238
288
 
289
+ var delta_x = Math.ceil(Math.pow(Math.abs(delta_x), accel) * sign_x);
290
+ var delta_y = Math.ceil(Math.pow(Math.abs(delta_y), accel) * sign_y);
239
291
  output += "Delta: " + delta_x + ", " + delta_y + "\n";
240
- status.html(output);
241
292
 
242
293
  state.x = x;
243
294
  state.y = y;
244
295
 
296
+ /* TODO(sissel): Make this a config option */
245
297
  if (e.rotation < -10 || e.rotation > 10) {
246
298
  /* Skip rotations that are probably not mouse-cursor-wanting movements */
247
299
  return;
248
300
  }
301
+ /* TODO(sissel): Make this a config option */
249
302
  if (e.scale < 0.9 || e.scale > 1.1) {
250
303
  /* Skip scales that are probably not mouse-cursor-wanting movements */
251
304
  return;
@@ -253,22 +306,63 @@
253
306
 
254
307
  if (touches.length > 1 && !state.dragging) {
255
308
  /* Multifinger movement, probably should scroll? */
256
- if (delta_y < 0 || delta_y > 0) {
309
+ if (Math.abs(delta_y) > 0) {
257
310
  /* Scroll */
258
- state.websocket.send(JSON.stringify({
259
- action: "click",
260
- button: (delta_y < 0) ? 4 : 5,
261
- }))
262
- }
263
-
311
+ state.scroll.y += delta_y;
312
+
313
+ /* Don't scroll every time we move, wait until we move enough
314
+ * that it is more than 10 pixels. */
315
+ /* TODO(sissel): Make this a config option */
316
+ if (Math.abs(state.scroll.y) > 10) {
317
+ state.scrolling = true;
318
+ state.moving = false;
319
+ state.scroll.y = 0;
320
+ state.websocket.send(JSON.stringify({
321
+ action: "click",
322
+ button: (delta_y < 0) ? 4 : 5,
323
+ }))
324
+ }
325
+ } /* if (Math.abs(delta_y) > 0) */
264
326
  } else {
265
- state.websocket.send(JSON.stringify({
266
- action: "mousemove_relative",
267
- rel_x: delta_x,
268
- rel_y: delta_y
269
- }));
270
- }
271
- }); /* $("#area").bind( ... )*/
327
+ /* Only 1 finger, and we aren't dragging. So let's move! */
328
+ /* TODO(sissel): Refactor these in to fumctions */
329
+ var movement = config("fingerpoken/mouse/movement");
330
+ if (movement == "relative") {
331
+ status.html(output);
332
+ state.websocket.send(JSON.stringify({
333
+ action: "mousemove_relative",
334
+ rel_x: delta_x,
335
+ rel_y: delta_y
336
+ }));
337
+ } else if (movement == "vector") {
338
+ if (!state.mouse.vectorTimer) {
339
+ state.mouse.vectorTimer = setInterval(function() {
340
+ var rx = state.x - state.start_x;
341
+ var ry = state.y - state.start_y;
342
+ if (rx == 0 || ry == 0) {
343
+ return;
344
+ }
345
+
346
+ var sign_rx = (rx < 0 ? -1 : 1);
347
+ var sign_ry = (ry < 0 ? -1 : 1);
348
+ var vector_accel = accel / 1.7 /* feels like the right ratio */
349
+
350
+ output = "rx,ry = " + rx + ", " + ry + "\n";
351
+ rx = Math.ceil(Math.pow(Math.abs(rx), vector_accel) * sign_rx);
352
+ ry = Math.ceil(Math.pow(Math.abs(ry), vector_accel) * sign_ry);
353
+ output += "rx2,ry2 = " + rx + ", " + ry + "\n";
354
+ status.html(output)
355
+
356
+ state.websocket.send(JSON.stringify({
357
+ action: "mousemove_relative",
358
+ rel_x: rx,
359
+ rel_y: ry
360
+ }));
361
+ }, 15);
362
+ } /* if (!state.mouse.vectorTimer) */
363
+ } /* mouse vector movement */
364
+ } /* finger movement */
365
+ }); /* $("#touchpadsurface").bind( ... )*/
272
366
 
273
367
 
274
368
  /* Take commands like this:
@@ -280,22 +374,21 @@
280
374
  * <a class="command" data-action="click" data-button="button to click">
281
375
  */
282
376
  $("a.command").bind("touchstart", function(event) {
283
- //event.preventDefault();
284
377
  state.touchelement = this;
285
- }).bind("touchmove", function(event) {
378
+ }).bind("mousedown", function(event) {
379
+ state.touchelement = this;
380
+ event.preventDefault();
381
+ }).bind("touchmove mousemove", function(event) {
286
382
  event.preventDefault();
287
- }).bind("touchend", function(event) {
288
- //event.preventDefault();
289
- console.log(this)
383
+ }).bind("touchend mouseup", function(event) {
290
384
  if (state.touchelement == this) {
291
- console.log(this)
292
385
  state.websocket.send(JSON.stringify({
293
386
  action: $(this).attr("data-action"),
294
387
  key: $(this).attr("data-key"),
295
- button: $(this).attr("data-button"),
388
+ button: parseInt($(this).attr("data-button")),
296
389
  }));
297
390
  }
298
391
  });
299
-
392
+
300
393
  }); /* $(document).ready */
301
394
  })();
data/views/index.haml CHANGED
@@ -16,10 +16,11 @@
16
16
  :type => "text/javascript" }
17
17
 
18
18
  %body
19
+ / touchpad
19
20
  %div{"data-role" => "page", "data-theme" => "a", "id" => "touchpad"}
20
21
  %div.header{"data-role" => "header"}
21
22
  %h1 fingerpoken
22
- %a{:href => "config", "data-role" => "button", "data-inline" => true} Config
23
+ %a{:href => "#config", "data-role" => "button", "data-rel" => "dialog", "data-transition" => "pop"} Config
23
24
  %a{:href => "javascript:window.location.reload()", "data-role" => "button", "data-inline" => true} Reload
24
25
  %div.content{"data-role" => "content"}
25
26
  #area
@@ -27,7 +28,7 @@
27
28
 
28
29
  %div.footer{"data-role" => "footer"}
29
30
  %span.left
30
- %a#extras{:href => "#commands", "data-role" => "button", "data-rel" => "dialog", "data-transition" => "pop"} Commands
31
+ %a{:href => "#commands", "data-role" => "button", "data-rel" => "dialog", "data-transition" => "pop"} Commands
31
32
  %span.right
32
33
  %a.command{:href => "#", "data-role" => "button", "data-action" => "click", "data-button" => "1"} Left
33
34
  %a.command{:href => "#", "data-role" => "button", "data-action" => "click", "data-button" => "3"} Right
@@ -35,6 +36,7 @@
35
36
  %div{"data-role" => "page", "data-theme" => "a", "id" => "commands"}
36
37
  %div{"data-role" => "header"}
37
38
  %h1 Commands
39
+ %a{:href => "#touchpad", "data-role" => "button"} Touchpad
38
40
  %div{"data-role" => "content"}
39
41
  %a.command{:href => "#", "data-role" => "button", "data-action" => "keypress", "data-key" => "Right"} Next Slide
40
42
  %a.command{:href => "#", "data-role" => "button", "data-action" => "keypress", "data-key" => "Left"} Prev Slide
@@ -42,7 +44,30 @@
42
44
  %a.command{:href => "#", "data-role" => "button", "data-action" => "keypress", "data-key" => "ctrl+plus"} Zoom In
43
45
  %a.command{:href => "#", "data-role" => "button", "data-action" => "keypress", "data-key" => "ctrl+minus"} Zoom Out
44
46
  %a.command{:href => "#", "data-role" => "button", "data-action" => "keypress", "data-key" => "ctrl+0"} Zoom Zero
45
- %div{"data-role" => "footer"}
47
+ %hr
48
+ %a.command{:href => "#", "data-role" => "button", "data-action" => "keypress", "data-key" => "alt+Return"} Full Screen
49
+ %a.command{:href => "#", "data-role" => "button", "data-action" => "keypress", "data-key" => "End"} End
50
+ %a.command{:href => "#", "data-role" => "button", "data-action" => "keypress", "data-key" => "Home"} Home
51
+ %a.command{:href => "#", "data-role" => "button", "data-action" => "keypress", "data-key" => "Return"} Return
52
+
53
+ %div{"data-role" => "page", "data-theme" => "a", "id" => "config"}
54
+ %div{"data-role" => "header"}
46
55
  %a{:href => "#touchpad", "data-role" => "button"} Touchpad
56
+ %h1 Configuration
57
+ %div{"data-role" => "content"}
58
+ Mouse movement
59
+
60
+ / Mouse movement type
61
+ %fieldset{"data-role" => "controlgroup"}
62
+ %input{:type => :radio, :name => "mouse-config", :id => "mouse-relative", :value => "relative"}
63
+ %label{:for => "mouse-relative"} relative
64
+ %input{:type => :radio, :name => "mouse-config", :id => "mouse-absolute", :value => "absolute"}
65
+ %label{:for => "mouse-absolute"} absolute
66
+ %input{:type => :radio, :name => "mouse-config", :id => "mouse-vector", :value => "vector"}
67
+ %label{:for => "mouse-vector"} vector
68
+
69
+ / Mouse acceleration
70
+ %label{:for => "mouse-acceleration"} Acceleration
71
+ %input{:type => "range", :name => "mouse-acceleration", :id => "mouse-acceleration", :min => 1, :max => 300, :step => "any"}
47
72
 
48
73
  %script{ :src => "/js/fingerpoken.js" }
data/views/style.sass CHANGED
@@ -19,34 +19,14 @@ html, body
19
19
  h1
20
20
  color: orange
21
21
 
22
- #menu
23
- width: 100%
24
- color: white
25
- font-family: sans-serif
26
- font-weight: bold
27
- text-align: center
28
- vertical-align: middle
29
- padding: 0
30
- padding-bottom: 5px
31
- margin: 0
32
-
33
- .item:last-child
34
- border-right: 2px solid lightgreen
35
- .item
36
- font-size: 250%
37
- border: 2px solid lightgreen
38
- border-right: 0px
39
- height: 40px
40
- padding: 10px
41
- margin: 0
42
- text-align: center
43
- vertical-align: middle
44
22
  .content
45
23
  .header
46
24
  .footer
47
25
  font-size: 120%
48
26
  .right
49
27
  float: right
28
+ //.content > #area
29
+ //padding: 0px !important
50
30
  #area
51
31
  width: 100%
52
32
  height: 100%
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: fingerpoken
3
3
  version: !ruby/object:Gem::Version
4
- hash: 40202418343269
4
+ hash: 40202432048205
5
5
  prerelease: false
6
6
  segments:
7
7
  - 0
8
8
  - 2
9
- - 20101209171641
10
- version: 0.2.20101209171641
9
+ - 20101216024109
10
+ version: 0.2.20101216024109
11
11
  platform: ruby
12
12
  authors:
13
13
  - Jordan Sissel
@@ -15,7 +15,7 @@ autorequire:
15
15
  bindir: bin
16
16
  cert_chain: []
17
17
 
18
- date: 2010-12-09 00:00:00 -08:00
18
+ date: 2010-12-16 00:00:00 -08:00
19
19
  default_executable:
20
20
  dependencies:
21
21
  - !ruby/object:Gem::Dependency
@@ -71,11 +71,22 @@ extra_rdoc_files: []
71
71
  files:
72
72
  - lib/fingerpoken/xdo.rb
73
73
  - lib/fingerpoken/target.rb
74
+ - lib/fingerpoken/tivo.rb
74
75
  - lib/fingerpoken/vnc.rb
75
76
  - public/reset.css
76
77
  - public/js/fingerpoken.js
77
78
  - public/js/jquery.min.js
78
79
  - public/js/jquery.mobile-1.0a2.min.js
80
+ - public/images/form-radio-on.png
81
+ - public/images/form-check-on.png
82
+ - public/images/icons-36-white.png
83
+ - public/images/icons-36-black.png
84
+ - public/images/icon-search-black.png
85
+ - public/images/icons-18-white.png
86
+ - public/images/ajax-loader.png
87
+ - public/images/form-radio-off.png
88
+ - public/images/icons-18-black.png
89
+ - public/images/form-check-off.png
79
90
  - public/jquery.mobile-1.0a2.min.css
80
91
  - views/style.sass
81
92
  - views/index.haml