fingerpoken 0.2.20101208032306
Sign up to get free protection for your applications and to get access to all the features.
- data/bin/fingerpoken.rb +51 -0
- data/lib/fingerpoken/target.rb +59 -0
- data/lib/fingerpoken/vnc.rb +69 -0
- data/lib/fingerpoken/xdo.rb +78 -0
- metadata +112 -0
data/bin/fingerpoken.rb
ADDED
@@ -0,0 +1,51 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require "rubygems"
|
4
|
+
require "em-websocket"
|
5
|
+
require "json"
|
6
|
+
require "rack"
|
7
|
+
require "sinatra/async"
|
8
|
+
|
9
|
+
class FingerPoken < Sinatra::Base
|
10
|
+
register Sinatra::Async
|
11
|
+
set :haml, :format => :html5
|
12
|
+
set :logging, true
|
13
|
+
set :public, "#{File.dirname(__FILE__)}/../public"
|
14
|
+
set :views, "#{File.dirname(__FILE__)}/../views"
|
15
|
+
|
16
|
+
aget '/' do
|
17
|
+
headers "Content-Type" => "text/html"
|
18
|
+
body haml :index
|
19
|
+
end # GET /
|
20
|
+
|
21
|
+
aget '/style.css' do
|
22
|
+
headers "Content-Type" => "text/css; charset=utf8"
|
23
|
+
body sass :style
|
24
|
+
end # GET /style.css
|
25
|
+
end
|
26
|
+
|
27
|
+
EventMachine::run do
|
28
|
+
$:.unshift(File.dirname(__FILE__) + "/lib")
|
29
|
+
channel = EventMachine::Channel.new
|
30
|
+
|
31
|
+
# TODO(sissel): Pick up here and make command flags to choose the
|
32
|
+
# target (vnc, xdo, etc)
|
33
|
+
require "fingerpoken/xdo"
|
34
|
+
target = FingerPoken::Target::Xdo.new :channel => channel
|
35
|
+
|
36
|
+
#require "fingerpoken/vnc"
|
37
|
+
#target = FingerPoken::Target::VNC.new :channel => channel
|
38
|
+
|
39
|
+
EventMachine::WebSocket.start(:host => "0.0.0.0", :port => 5001) do |ws|
|
40
|
+
ws.onmessage do |message|
|
41
|
+
request = JSON.parse(message)
|
42
|
+
p request
|
43
|
+
channel.push(request)
|
44
|
+
end # ws.onmessage
|
45
|
+
end # WebSocket
|
46
|
+
|
47
|
+
Rack::Handler::Thin.run(
|
48
|
+
Rack::CommonLogger.new( \
|
49
|
+
Rack::ShowExceptions.new( \
|
50
|
+
FingerPoken.new)), :Port => 5000)
|
51
|
+
end # EventMachine::run
|
@@ -0,0 +1,59 @@
|
|
1
|
+
require "logger"
|
2
|
+
|
3
|
+
class FingerPoken::Target
|
4
|
+
def initialize(config)
|
5
|
+
@channel = config[:channel]
|
6
|
+
@logger = Logger.new(STDERR)
|
7
|
+
end
|
8
|
+
|
9
|
+
def register
|
10
|
+
@channel.subscribe do |request|
|
11
|
+
case request["action"]
|
12
|
+
when "mousemove_relative"
|
13
|
+
mousemove_relative(request["rel_x"], request["rel_y"])
|
14
|
+
when "click"
|
15
|
+
click(request["button"])
|
16
|
+
when "mousedown"
|
17
|
+
mousedown(request["button"])
|
18
|
+
when "mouseup"
|
19
|
+
mouseup(request["button"])
|
20
|
+
when "type"
|
21
|
+
type(request["string"])
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
# Subclasses should implement this.
|
27
|
+
def mousemove_relative(x, y)
|
28
|
+
@logger.info("mousemove not supported")
|
29
|
+
end
|
30
|
+
|
31
|
+
def mousedown(button)
|
32
|
+
@logger.info("mousedown not supported")
|
33
|
+
end
|
34
|
+
|
35
|
+
def mouseup(button)
|
36
|
+
@logger.info("mouseup not supported")
|
37
|
+
end
|
38
|
+
|
39
|
+
def click(button)
|
40
|
+
mousedown(button)
|
41
|
+
mouseup(button)
|
42
|
+
end
|
43
|
+
|
44
|
+
def type(string)
|
45
|
+
@logger.info("typing not supported")
|
46
|
+
end
|
47
|
+
|
48
|
+
def keypress(key)
|
49
|
+
@logger.info("keypress not supported")
|
50
|
+
end
|
51
|
+
|
52
|
+
def keydown(key)
|
53
|
+
@logger.info("keydown not supported")
|
54
|
+
end
|
55
|
+
|
56
|
+
def keyup(key)
|
57
|
+
@logger.info("keyup not supported")
|
58
|
+
end
|
59
|
+
end # class FingerPoken::Target
|
@@ -0,0 +1,69 @@
|
|
1
|
+
require "rubygems"
|
2
|
+
require "eventmachine-vnc"
|
3
|
+
require "fingerpoken/target"
|
4
|
+
|
5
|
+
class FingerPoken::Target::VNC < FingerPoken::Target
|
6
|
+
attr_accessor :x
|
7
|
+
attr_accessor :y
|
8
|
+
attr_accessor :buttonmask
|
9
|
+
|
10
|
+
def initialize(config)
|
11
|
+
super(config)
|
12
|
+
# TODO(sissel): Make this configurable
|
13
|
+
@password = ENV["VNCPASS"]
|
14
|
+
@host = "sadness"
|
15
|
+
@port = 5900
|
16
|
+
|
17
|
+
@vnc = EventMachine::connect(@host, @port, VNCClient, self)
|
18
|
+
@x = 0
|
19
|
+
@y = 0
|
20
|
+
@buttonmask = 0
|
21
|
+
end
|
22
|
+
|
23
|
+
def update
|
24
|
+
p [@x, @y, @buttonmask]
|
25
|
+
@vnc.pointerevent(@x, @y, @buttonmask)
|
26
|
+
|
27
|
+
# TODO(sissel): Hack to make it work in TF2.
|
28
|
+
# Mouse movement is always "from center"
|
29
|
+
# So after each move, center the cursor.
|
30
|
+
#@x = (@vnc.screen_width / 2).to_i
|
31
|
+
#@y = (@vnc.screen_height / 2).to_i
|
32
|
+
end
|
33
|
+
|
34
|
+
|
35
|
+
def mousemove_relative(x, y)
|
36
|
+
@x += x
|
37
|
+
@y += y
|
38
|
+
update
|
39
|
+
end
|
40
|
+
|
41
|
+
def mousedown(button)
|
42
|
+
button = (1 << (button - 1))
|
43
|
+
return if @buttonmask & button != 0
|
44
|
+
@buttonmask |= button
|
45
|
+
update
|
46
|
+
end
|
47
|
+
|
48
|
+
def mouseup(button)
|
49
|
+
button = (1 << (button - 1))
|
50
|
+
return if @buttonmask & button == 0
|
51
|
+
@buttonmask &= (~button)
|
52
|
+
update
|
53
|
+
end
|
54
|
+
|
55
|
+
class VNCClient < EventMachine::Connection
|
56
|
+
include EventMachine::Protocols::VNC::Client
|
57
|
+
|
58
|
+
def initialize(target)
|
59
|
+
@target = target
|
60
|
+
end
|
61
|
+
|
62
|
+
def ready
|
63
|
+
@target.register
|
64
|
+
@target.x = (@screen_width / 2).to_i
|
65
|
+
@target.y = (@screen_height / 2).to_i
|
66
|
+
@target.buttonmask = 0
|
67
|
+
end
|
68
|
+
end # class VNCClient
|
69
|
+
end
|
@@ -0,0 +1,78 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require "rubygems"
|
4
|
+
require "ffi"
|
5
|
+
require "fingerpoken/target"
|
6
|
+
|
7
|
+
class FingerPoken::Target::Xdo < FingerPoken::Target
|
8
|
+
module LibXdo
|
9
|
+
extend FFI::Library
|
10
|
+
ffi_lib "libxdo.so"
|
11
|
+
|
12
|
+
attach_function :xdo_new, [:string], :pointer
|
13
|
+
attach_function :xdo_mousemove, [:pointer, :int, :int, :int], :int
|
14
|
+
attach_function :xdo_mousemove_relative, [:pointer, :int, :int], :int
|
15
|
+
attach_function :xdo_click, [:pointer, :long, :int], :int
|
16
|
+
attach_function :xdo_mousedown, [:pointer, :long, :int], :int
|
17
|
+
attach_function :xdo_mouseup, [:pointer, :long, :int], :int
|
18
|
+
attach_function :xdo_type, [:pointer, :long, :string, :long], :int
|
19
|
+
attach_function :xdo_keysequence, [:pointer, :long, :string, :long], :int
|
20
|
+
end
|
21
|
+
|
22
|
+
def initialize(config)
|
23
|
+
super(config)
|
24
|
+
@xdo = LibXdo::xdo_new(nil)
|
25
|
+
if @xdo.null?
|
26
|
+
raise "xdo_new failed"
|
27
|
+
end
|
28
|
+
register
|
29
|
+
end
|
30
|
+
|
31
|
+
def mousemove_relative(x, y)
|
32
|
+
@logger.info("move #{x},#{y}")
|
33
|
+
return LibXdo::xdo_mousemove_relative(@xdo, x, y)
|
34
|
+
end
|
35
|
+
|
36
|
+
def click(button)
|
37
|
+
LibXdo::xdo_click(@xdo, 0, button)
|
38
|
+
end
|
39
|
+
|
40
|
+
def mousedown(button)
|
41
|
+
LibXdo::xdo_mousedown(@xdo, 0, button)
|
42
|
+
end
|
43
|
+
|
44
|
+
def mouseup(button)
|
45
|
+
LibXdo::xdo_mouseup(@xdo, 0, button)
|
46
|
+
end
|
47
|
+
|
48
|
+
def type(string)
|
49
|
+
LibXdo::xdo_type(@xdo, 0, string, 12000)
|
50
|
+
end
|
51
|
+
|
52
|
+
def keypress(key)
|
53
|
+
key = request["key"]
|
54
|
+
if key.is_a?(String)
|
55
|
+
if key.length == 1
|
56
|
+
# Assume letter
|
57
|
+
LibXdo::xdo_type(@xdo, 0, key, 12000)
|
58
|
+
else
|
59
|
+
# Assume keysym
|
60
|
+
LibXdo::xdo_keysequence(@xdo, 0, key, 12000)
|
61
|
+
end
|
62
|
+
else
|
63
|
+
# type printables, key others.
|
64
|
+
if 32.upto(127).include?(key)
|
65
|
+
LibXdo::xdo_type(@xdo, 0, request["key"].chr, 12000)
|
66
|
+
else
|
67
|
+
case key
|
68
|
+
when 8
|
69
|
+
LibXdo::xdo_keysequence(@xdo, 0, "BackSpace", 12000)
|
70
|
+
when 13
|
71
|
+
LibXdo::xdo_keysequence(@xdo, 0, "Return", 12000)
|
72
|
+
else
|
73
|
+
puts "I don't know how to type web keycode '#{key}'"
|
74
|
+
end # case key
|
75
|
+
end # if 32.upto(127).include?(key)
|
76
|
+
end # if key.is_a?String
|
77
|
+
end # def keypress
|
78
|
+
end # class FingerPoken::Target::Xdo
|
metadata
ADDED
@@ -0,0 +1,112 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: fingerpoken
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
hash: 40202416064627
|
5
|
+
prerelease: false
|
6
|
+
segments:
|
7
|
+
- 0
|
8
|
+
- 2
|
9
|
+
- 20101208032306
|
10
|
+
version: 0.2.20101208032306
|
11
|
+
platform: ruby
|
12
|
+
authors:
|
13
|
+
- Jordan Sissel
|
14
|
+
autorequire:
|
15
|
+
bindir: bin
|
16
|
+
cert_chain: []
|
17
|
+
|
18
|
+
date: 2010-12-08 00:00:00 -08:00
|
19
|
+
default_executable:
|
20
|
+
dependencies:
|
21
|
+
- !ruby/object:Gem::Dependency
|
22
|
+
name: eventmachine-vnc
|
23
|
+
prerelease: false
|
24
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ">="
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
hash: 3
|
30
|
+
segments:
|
31
|
+
- 0
|
32
|
+
version: "0"
|
33
|
+
type: :runtime
|
34
|
+
version_requirements: *id001
|
35
|
+
- !ruby/object:Gem::Dependency
|
36
|
+
name: ffi
|
37
|
+
prerelease: false
|
38
|
+
requirement: &id002 !ruby/object:Gem::Requirement
|
39
|
+
none: false
|
40
|
+
requirements:
|
41
|
+
- - ">="
|
42
|
+
- !ruby/object:Gem::Version
|
43
|
+
hash: 3
|
44
|
+
segments:
|
45
|
+
- 0
|
46
|
+
version: "0"
|
47
|
+
type: :runtime
|
48
|
+
version_requirements: *id002
|
49
|
+
- !ruby/object:Gem::Dependency
|
50
|
+
name: eventmachine
|
51
|
+
prerelease: false
|
52
|
+
requirement: &id003 !ruby/object:Gem::Requirement
|
53
|
+
none: false
|
54
|
+
requirements:
|
55
|
+
- - ">="
|
56
|
+
- !ruby/object:Gem::Version
|
57
|
+
hash: 3
|
58
|
+
segments:
|
59
|
+
- 0
|
60
|
+
version: "0"
|
61
|
+
type: :runtime
|
62
|
+
version_requirements: *id003
|
63
|
+
description: fingerpoken - turns your ipad/itouch/iphone into a remote touchpad, keyboard, etc
|
64
|
+
email: jls@semicomplete.com
|
65
|
+
executables:
|
66
|
+
- fingerpoken.rb
|
67
|
+
extensions: []
|
68
|
+
|
69
|
+
extra_rdoc_files: []
|
70
|
+
|
71
|
+
files:
|
72
|
+
- lib/fingerpoken/xdo.rb
|
73
|
+
- lib/fingerpoken/target.rb
|
74
|
+
- lib/fingerpoken/vnc.rb
|
75
|
+
- bin/fingerpoken.rb
|
76
|
+
has_rdoc: true
|
77
|
+
homepage: https://github.com/jordansissel/eventmachine-vnc
|
78
|
+
licenses: []
|
79
|
+
|
80
|
+
post_install_message:
|
81
|
+
rdoc_options: []
|
82
|
+
|
83
|
+
require_paths:
|
84
|
+
- lib
|
85
|
+
- lib
|
86
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
87
|
+
none: false
|
88
|
+
requirements:
|
89
|
+
- - ">="
|
90
|
+
- !ruby/object:Gem::Version
|
91
|
+
hash: 3
|
92
|
+
segments:
|
93
|
+
- 0
|
94
|
+
version: "0"
|
95
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
96
|
+
none: false
|
97
|
+
requirements:
|
98
|
+
- - ">="
|
99
|
+
- !ruby/object:Gem::Version
|
100
|
+
hash: 3
|
101
|
+
segments:
|
102
|
+
- 0
|
103
|
+
version: "0"
|
104
|
+
requirements: []
|
105
|
+
|
106
|
+
rubyforge_project:
|
107
|
+
rubygems_version: 1.3.7
|
108
|
+
signing_key:
|
109
|
+
specification_version: 3
|
110
|
+
summary: fingerpoken - turns your ipad/itouch/iphone into a remote touchpad, keyboard, etc
|
111
|
+
test_files: []
|
112
|
+
|