shank 0.0.1
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/.gitignore +22 -0
- data/Gemfile +3 -0
- data/LICENSE +22 -0
- data/README.md +0 -0
- data/Rakefile +2 -0
- data/lib/assets/javascripts/engine.gamepads.coffee +46 -0
- data/lib/assets/javascripts/engine_stats.coffee +10 -0
- data/lib/assets/javascripts/error_handler.coffee +11 -0
- data/lib/assets/javascripts/game_keys.coffee +6 -0
- data/lib/assets/javascripts/gamepads.coffee +21 -0
- data/lib/assets/javascripts/gamepads.controller.coffee +138 -0
- data/lib/assets/javascripts/init.coffee +6 -0
- data/lib/assets/javascripts/joysticks.coffee +238 -0
- data/lib/assets/javascripts/jquery.hotkeys.coffee +161 -0
- data/lib/assets/javascripts/jquery.reverse_merge.coffee +21 -0
- data/lib/assets/javascripts/keydown.coffee +73 -0
- data/lib/assets/javascripts/mouse.coffee +66 -0
- data/lib/assets/javascripts/music.coffee +78 -0
- data/lib/assets/javascripts/pixie_canvas.coffee +739 -0
- data/lib/assets/javascripts/request_animation_frame.coffee +22 -0
- data/lib/assets/javascripts/shank.coffee +18 -0
- data/lib/assets/javascripts/sound.coffee +131 -0
- data/lib/assets/javascripts/storage.coffee +88 -0
- data/lib/shank/version.rb +3 -0
- data/lib/shank.rb +10 -0
- data/shank.gemspec +17 -0
- data/test/jquery.reverse_merge.coffee +43 -0
- data/test/keydown.coffee +19 -0
- data/test/pixie_canvas.coffee +18 -0
- data/test/request_animation_frame.coffee +7 -0
- data/test/sound.coffee +7 -0
- data/test/storage.coffee +47 -0
- data/test/xstats.coffee +7 -0
- data/vendor/assets/javascripts/xstats.js +767 -0
- metadata +113 -0
data/.gitignore
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
*.gem
|
2
|
+
*.rbc
|
3
|
+
.DS_STORE
|
4
|
+
.bundle
|
5
|
+
.config
|
6
|
+
.sass-cache/
|
7
|
+
.yardoc
|
8
|
+
Gemfile.lock
|
9
|
+
InstalledFiles
|
10
|
+
_yardoc
|
11
|
+
coverage
|
12
|
+
doc/
|
13
|
+
docs/
|
14
|
+
lib/bundler/man
|
15
|
+
lib/assets/test.html
|
16
|
+
lib/assets/javascripts/cornerstone_tests.js
|
17
|
+
pkg
|
18
|
+
rdoc
|
19
|
+
spec/reports
|
20
|
+
test/tmp
|
21
|
+
test/version_tmp
|
22
|
+
tmp
|
data/Gemfile
ADDED
data/LICENSE
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2012 Daniel X. Moore
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
File without changes
|
data/Rakefile
ADDED
@@ -0,0 +1,46 @@
|
|
1
|
+
###*
|
2
|
+
The <code>Gamepads</code> module gives the engine access to gamepads.
|
3
|
+
|
4
|
+
# First you need to add the `Gamepads` module to the engine
|
5
|
+
Engine.defaultModules.push "Gamepads"
|
6
|
+
|
7
|
+
window.engine = Engine
|
8
|
+
...
|
9
|
+
|
10
|
+
# Then you need to get a controller reference
|
11
|
+
# id = 0 for player 1, etc.
|
12
|
+
controller = engine.controller(id)
|
13
|
+
|
14
|
+
# Point indicating direction primary axis is held
|
15
|
+
direction = controller.position()
|
16
|
+
|
17
|
+
# Check if buttons are held
|
18
|
+
controller.actionDown("A")
|
19
|
+
controller.actionDown("B")
|
20
|
+
controller.actionDown("X")
|
21
|
+
controller.actionDown("Y")
|
22
|
+
|
23
|
+
@name Gamepads
|
24
|
+
@fieldOf Engine
|
25
|
+
@module
|
26
|
+
|
27
|
+
@param {Object} I Instance variables
|
28
|
+
@param {Object} self Reference to the engine
|
29
|
+
###
|
30
|
+
Engine.Gamepads = (I, self) ->
|
31
|
+
gamepads = Gamepads()
|
32
|
+
|
33
|
+
self.bind "beforeUpdate", ->
|
34
|
+
# Update the gamepads
|
35
|
+
gamepads.update()
|
36
|
+
|
37
|
+
###*
|
38
|
+
Get a controller for a given id.
|
39
|
+
|
40
|
+
@name controller
|
41
|
+
@methodOf Engine.Gamepads#
|
42
|
+
|
43
|
+
@param {Number} index The index to get a controller for.
|
44
|
+
###
|
45
|
+
controller: (index) ->
|
46
|
+
gamepads.controller(index)
|
@@ -0,0 +1,11 @@
|
|
1
|
+
###*
|
2
|
+
This error handler captures any runtime errors and reports them to the IDE
|
3
|
+
if present.
|
4
|
+
###
|
5
|
+
window.onerror = (message, url, lineNumber) ->
|
6
|
+
errorContext = $('script').last().text().split('\n')[(lineNumber-5)..(lineNumber+4)]
|
7
|
+
|
8
|
+
errorContext[4] = "<b style='font-weight: bold; text-decoration: underline;'>" + errorContext[4] + "</b>"
|
9
|
+
|
10
|
+
displayRuntimeError?("<code>#{message}</code> <br /><br />(Sometimes this context may be wrong.)<br /><code><pre>#{errorContext.join('\n')}</pre></code>")
|
11
|
+
|
@@ -0,0 +1,21 @@
|
|
1
|
+
Gamepads = (I={}) ->
|
2
|
+
state = {} # holds current and previous states
|
3
|
+
controllers = [] # controller cache
|
4
|
+
|
5
|
+
# Capture the current gamepad state
|
6
|
+
snapshot = ->
|
7
|
+
Array::map.call navigator.webkitGamepads || navigator.webkitGetGamepads(), (x) ->
|
8
|
+
axes: x.axes
|
9
|
+
buttons: x.buttons
|
10
|
+
|
11
|
+
controller: (index=0) ->
|
12
|
+
controllers[index] ||= Gamepads.Controller
|
13
|
+
index: index
|
14
|
+
state: state
|
15
|
+
|
16
|
+
update: ->
|
17
|
+
state.previous = state.current
|
18
|
+
state.current = snapshot()
|
19
|
+
|
20
|
+
controllers.each (controller) ->
|
21
|
+
controller?.update()
|
@@ -0,0 +1,138 @@
|
|
1
|
+
Gamepads.Controller = (I={}) ->
|
2
|
+
Object.reverseMerge I,
|
3
|
+
debugColor: "#000"
|
4
|
+
|
5
|
+
MAX_BUFFER = 0.03
|
6
|
+
AXIS_MAX = 1 - MAX_BUFFER
|
7
|
+
DEAD_ZONE = AXIS_MAX * 0.2
|
8
|
+
TRIP_HIGH = AXIS_MAX * 0.75
|
9
|
+
TRIP_LOW = AXIS_MAX * 0.5
|
10
|
+
|
11
|
+
BUTTON_THRESHOLD = 0.5
|
12
|
+
|
13
|
+
buttonMapping =
|
14
|
+
"A": 0
|
15
|
+
"B": 1
|
16
|
+
|
17
|
+
# X/C, Y/D are interchangeable
|
18
|
+
"C": 2
|
19
|
+
"D": 3
|
20
|
+
"X": 2
|
21
|
+
"Y": 3
|
22
|
+
|
23
|
+
"L": 4
|
24
|
+
"LB": 4
|
25
|
+
"L1": 4
|
26
|
+
|
27
|
+
"R": 5
|
28
|
+
"RB": 5
|
29
|
+
"R1": 5
|
30
|
+
|
31
|
+
"SELECT": 6
|
32
|
+
"BACK": 6
|
33
|
+
|
34
|
+
"START": 7
|
35
|
+
|
36
|
+
"HOME": 8
|
37
|
+
"GUIDE": 8
|
38
|
+
|
39
|
+
"TL": 9
|
40
|
+
"TR": 10
|
41
|
+
|
42
|
+
currentState = ->
|
43
|
+
I.state.current?[I.index]
|
44
|
+
|
45
|
+
previousState = ->
|
46
|
+
I.state.previous?[I.index]
|
47
|
+
|
48
|
+
axisTrips = []
|
49
|
+
tap = Point(0, 0)
|
50
|
+
|
51
|
+
processTaps = ->
|
52
|
+
[x, y] = [0, 1].map (n) ->
|
53
|
+
if !axisTrips[n] && self.axis(n).abs() > TRIP_HIGH
|
54
|
+
axisTrips[n] = true
|
55
|
+
|
56
|
+
return self.axis(n).sign()
|
57
|
+
|
58
|
+
if axisTrips[n] && self.axis(n).abs() < TRIP_LOW
|
59
|
+
axisTrips[n] = false
|
60
|
+
|
61
|
+
return 0
|
62
|
+
|
63
|
+
tap = Point(x, y)
|
64
|
+
|
65
|
+
self = Core().include(Bindable).extend
|
66
|
+
actionDown: (buttons...) ->
|
67
|
+
if state = currentState()
|
68
|
+
buttons.inject false, (down, button) ->
|
69
|
+
down || if button is "ANY"
|
70
|
+
state.buttons.inject false, (down, button) ->
|
71
|
+
down || (button > BUTTON_THRESHOLD)
|
72
|
+
else
|
73
|
+
state.buttons[buttonMapping[button]] > BUTTON_THRESHOLD
|
74
|
+
else
|
75
|
+
false
|
76
|
+
|
77
|
+
# true if button was just pressed
|
78
|
+
buttonPressed: (button) ->
|
79
|
+
buttonId = buttonMapping[button]
|
80
|
+
|
81
|
+
return (self.buttons()[buttonId] > BUTTON_THRESHOLD) && !(previousState()?.buttons[buttonId] > BUTTON_THRESHOLD)
|
82
|
+
|
83
|
+
position: (stick=0) ->
|
84
|
+
if state = currentState()
|
85
|
+
p = Point(self.axis(2*stick), self.axis(2*stick+1))
|
86
|
+
|
87
|
+
magnitude = p.magnitude()
|
88
|
+
|
89
|
+
if magnitude > AXIS_MAX
|
90
|
+
p.norm()
|
91
|
+
else if magnitude < DEAD_ZONE
|
92
|
+
Point(0, 0)
|
93
|
+
else
|
94
|
+
ratio = magnitude / AXIS_MAX
|
95
|
+
|
96
|
+
p.scale(ratio / AXIS_MAX)
|
97
|
+
|
98
|
+
else
|
99
|
+
Point(0, 0)
|
100
|
+
|
101
|
+
axis: (n) ->
|
102
|
+
self.axes()[n] || 0
|
103
|
+
|
104
|
+
axes: ->
|
105
|
+
if state = currentState()
|
106
|
+
state.axes
|
107
|
+
else
|
108
|
+
[]
|
109
|
+
|
110
|
+
buttons: ->
|
111
|
+
if state = currentState()
|
112
|
+
state.buttons
|
113
|
+
else
|
114
|
+
[]
|
115
|
+
|
116
|
+
tap: ->
|
117
|
+
tap
|
118
|
+
|
119
|
+
update: ->
|
120
|
+
processTaps()
|
121
|
+
|
122
|
+
drawDebug: (canvas) ->
|
123
|
+
lineHeight = 18
|
124
|
+
|
125
|
+
self.axes().each (axis, i) ->
|
126
|
+
canvas.drawText
|
127
|
+
color: I.debugColor
|
128
|
+
text: axis
|
129
|
+
x: 0
|
130
|
+
y: i * lineHeight
|
131
|
+
|
132
|
+
self.buttons().each (button, i) ->
|
133
|
+
canvas.drawText
|
134
|
+
color: I.debugColor
|
135
|
+
text: button
|
136
|
+
x: 250
|
137
|
+
y: i * lineHeight
|
138
|
+
|
@@ -0,0 +1,238 @@
|
|
1
|
+
Joysticks = ( ->
|
2
|
+
type = "application/x-boomstickjavascriptjoysticksupport"
|
3
|
+
plugin = null
|
4
|
+
MAX_BUFFER = 2000
|
5
|
+
AXIS_MAX = 32767 - MAX_BUFFER
|
6
|
+
DEAD_ZONE = AXIS_MAX * 0.2
|
7
|
+
TRIP_HIGH = AXIS_MAX * 0.75
|
8
|
+
TRIP_LOW = AXIS_MAX * 0.5
|
9
|
+
|
10
|
+
# Raw Joysticks data
|
11
|
+
previousJoysticks = []
|
12
|
+
joysticks = []
|
13
|
+
|
14
|
+
controllers = []
|
15
|
+
|
16
|
+
buttonMappingDefault =
|
17
|
+
"A": 1
|
18
|
+
"B": 2
|
19
|
+
|
20
|
+
# X/C, Y/D are interchangeable
|
21
|
+
"C": 4
|
22
|
+
"D": 8
|
23
|
+
"X": 4
|
24
|
+
"Y": 8
|
25
|
+
|
26
|
+
"R": 32
|
27
|
+
"RB": 32
|
28
|
+
"R1": 32
|
29
|
+
|
30
|
+
"L": 16
|
31
|
+
"LB": 16
|
32
|
+
"L1": 16
|
33
|
+
|
34
|
+
"SELECT": 64
|
35
|
+
"BACK": 64
|
36
|
+
|
37
|
+
"START": 128
|
38
|
+
|
39
|
+
"HOME": 256
|
40
|
+
"GUIDE": 256
|
41
|
+
|
42
|
+
"TL": 512
|
43
|
+
"TR": 1024
|
44
|
+
|
45
|
+
"ANY": 0xFFFFFF
|
46
|
+
|
47
|
+
buttonMappingOSX =
|
48
|
+
"A": 2048
|
49
|
+
"B": 4096
|
50
|
+
|
51
|
+
"C": 8192
|
52
|
+
"D": 16384
|
53
|
+
"X": 8192
|
54
|
+
"Y": 16384
|
55
|
+
|
56
|
+
"R": 512
|
57
|
+
|
58
|
+
"L": 256
|
59
|
+
|
60
|
+
"SELECT": 32
|
61
|
+
"BACK": 32
|
62
|
+
|
63
|
+
"START": 16
|
64
|
+
|
65
|
+
"HOME": 1024
|
66
|
+
|
67
|
+
"LT": 64
|
68
|
+
"TR": 128
|
69
|
+
|
70
|
+
"ANY": 0xFFFFFF0
|
71
|
+
|
72
|
+
axisMappingDefault =
|
73
|
+
0: 0
|
74
|
+
1: 1
|
75
|
+
2: 2
|
76
|
+
3: 3
|
77
|
+
4: 4
|
78
|
+
5: 5
|
79
|
+
|
80
|
+
axisMappingOSX =
|
81
|
+
0: 2
|
82
|
+
1: 3
|
83
|
+
2: 4
|
84
|
+
3: 5
|
85
|
+
4: 0
|
86
|
+
5: 1
|
87
|
+
|
88
|
+
displayInstallPrompt = (text, url) ->
|
89
|
+
$ "<a />",
|
90
|
+
css:
|
91
|
+
backgroundColor: "yellow"
|
92
|
+
boxSizing: "border-box"
|
93
|
+
color: "#000"
|
94
|
+
display: "block"
|
95
|
+
fontWeight: "bold"
|
96
|
+
left: 0
|
97
|
+
padding: "1em"
|
98
|
+
position: "absolute"
|
99
|
+
textDecoration: "none"
|
100
|
+
top: 0
|
101
|
+
width: "100%"
|
102
|
+
zIndex: 2000
|
103
|
+
href: url
|
104
|
+
target: "_blank"
|
105
|
+
text: text
|
106
|
+
.appendTo("body")
|
107
|
+
|
108
|
+
Controller = (i, remapOSX) ->
|
109
|
+
if remapOSX == undefined
|
110
|
+
remapOSX = navigator.platform.match(/^Mac/)
|
111
|
+
|
112
|
+
if remapOSX
|
113
|
+
buttonMapping = buttonMappingOSX
|
114
|
+
axisMapping = axisMappingOSX
|
115
|
+
else
|
116
|
+
buttonMapping = buttonMappingDefault
|
117
|
+
axisMapping = axisMappingDefault
|
118
|
+
|
119
|
+
currentState = ->
|
120
|
+
joysticks[i]
|
121
|
+
|
122
|
+
previousState = ->
|
123
|
+
previousJoysticks[i]
|
124
|
+
|
125
|
+
axisTrips = []
|
126
|
+
|
127
|
+
self = Core().include(Bindable).extend
|
128
|
+
actionDown: (buttons...) ->
|
129
|
+
if state = currentState()
|
130
|
+
buttons.inject false, (down, button) ->
|
131
|
+
down || state.buttons & buttonMapping[button]
|
132
|
+
else
|
133
|
+
false
|
134
|
+
|
135
|
+
# true if button was just pressed
|
136
|
+
buttonPressed: (button) ->
|
137
|
+
buttonId = buttonMapping[button]
|
138
|
+
|
139
|
+
return (self.buttons() & buttonId) && !(previousState().buttons & buttonId)
|
140
|
+
|
141
|
+
position: (stick=0) ->
|
142
|
+
if state = currentState()
|
143
|
+
p = Point(self.axis(2*stick), self.axis(2*stick+1))
|
144
|
+
|
145
|
+
magnitude = p.magnitude()
|
146
|
+
|
147
|
+
if magnitude > AXIS_MAX
|
148
|
+
p.norm()
|
149
|
+
else if magnitude < DEAD_ZONE
|
150
|
+
Point(0, 0)
|
151
|
+
else
|
152
|
+
ratio = magnitude / AXIS_MAX
|
153
|
+
|
154
|
+
p.scale(ratio / AXIS_MAX)
|
155
|
+
|
156
|
+
else
|
157
|
+
Point(0, 0)
|
158
|
+
|
159
|
+
axis: (n) ->
|
160
|
+
n = axisMapping[n]
|
161
|
+
|
162
|
+
self.axes()[n] || 0
|
163
|
+
|
164
|
+
axes: ->
|
165
|
+
if state = currentState()
|
166
|
+
state.axes
|
167
|
+
else
|
168
|
+
[]
|
169
|
+
|
170
|
+
buttons: ->
|
171
|
+
if state = currentState()
|
172
|
+
state.buttons
|
173
|
+
|
174
|
+
processEvents: ->
|
175
|
+
[x, y] = [0, 1].map (n) ->
|
176
|
+
if !axisTrips[n] && self.axis(n).abs() > TRIP_HIGH
|
177
|
+
axisTrips[n] = true
|
178
|
+
|
179
|
+
return self.axis(n).sign()
|
180
|
+
|
181
|
+
if axisTrips[n] && self.axis(n).abs() < TRIP_LOW
|
182
|
+
axisTrips[n] = false
|
183
|
+
|
184
|
+
return 0
|
185
|
+
|
186
|
+
self.trigger("tap", Point(x, y)) if !x || !y
|
187
|
+
|
188
|
+
drawDebug: (canvas) ->
|
189
|
+
lineHeight = 18
|
190
|
+
canvas.fillColor("#FFF")
|
191
|
+
|
192
|
+
for axis, i in self.axes()
|
193
|
+
canvas.fillText(axis, 0, i * lineHeight)
|
194
|
+
|
195
|
+
canvas.fillText(self.buttons(), 0, i * lineHeight)
|
196
|
+
|
197
|
+
getController: (i) ->
|
198
|
+
controllers[i] ||= Controller(i)
|
199
|
+
|
200
|
+
init: ->
|
201
|
+
unless plugin
|
202
|
+
plugin = document.createElement("object")
|
203
|
+
plugin.type = type
|
204
|
+
plugin.width = 0
|
205
|
+
plugin.height = 0
|
206
|
+
|
207
|
+
$("body").append(plugin)
|
208
|
+
|
209
|
+
plugin.maxAxes = 6
|
210
|
+
|
211
|
+
unless plugin.status
|
212
|
+
promptElement = displayInstallPrompt("Your browser does not yet handle joysticks, please click here to install the Boomstick plugin!", "https://github.com/STRd6/Boomstick/wiki")
|
213
|
+
|
214
|
+
# The periodic check will remove the prompt if the player
|
215
|
+
# needs to accept or run the plugin manually
|
216
|
+
periodicCheck = ->
|
217
|
+
if plugin.status
|
218
|
+
promptElement.remove()
|
219
|
+
else
|
220
|
+
setTimeout periodicCheck, 500
|
221
|
+
|
222
|
+
periodicCheck()
|
223
|
+
|
224
|
+
status: ->
|
225
|
+
plugin?.status
|
226
|
+
|
227
|
+
update: ->
|
228
|
+
if plugin.joysticksJSON
|
229
|
+
previousJoysticks = joysticks
|
230
|
+
joysticks = JSON.parse(plugin.joysticksJSON())
|
231
|
+
|
232
|
+
for controller in controllers
|
233
|
+
controller?.processEvents()
|
234
|
+
|
235
|
+
joysticks: ->
|
236
|
+
joysticks
|
237
|
+
)()
|
238
|
+
|
@@ -0,0 +1,161 @@
|
|
1
|
+
###*
|
2
|
+
jQuery Hotkeys Plugin
|
3
|
+
Copyright 2010, John Resig
|
4
|
+
Dual licensed under the MIT or GPL Version 2 licenses.
|
5
|
+
|
6
|
+
Based upon the plugin by Tzury Bar Yochay:
|
7
|
+
http://github.com/tzuryby/hotkeys
|
8
|
+
|
9
|
+
Original idea by:
|
10
|
+
Binny V A, http://www.openjs.com/scripts/events/keyboard_shortcuts/
|
11
|
+
###
|
12
|
+
|
13
|
+
((jQuery) ->
|
14
|
+
isTextAcceptingInput = (element) ->
|
15
|
+
/textarea|select/i.test(element.nodeName) || element.type == "text" || element.type == "password"
|
16
|
+
|
17
|
+
isFunctionKey = (event) ->
|
18
|
+
(event.type != "keypress") && (112 <= event.which <= 123)
|
19
|
+
|
20
|
+
jQuery.hotkeys =
|
21
|
+
version: "0.8"
|
22
|
+
|
23
|
+
specialKeys:
|
24
|
+
8: "backspace"
|
25
|
+
9: "tab"
|
26
|
+
13: "return"
|
27
|
+
16: "shift"
|
28
|
+
17: "ctrl"
|
29
|
+
18: "alt"
|
30
|
+
19: "pause"
|
31
|
+
20: "capslock"
|
32
|
+
27: "esc"
|
33
|
+
32: "space"
|
34
|
+
33: "pageup"
|
35
|
+
34: "pagedown"
|
36
|
+
35: "end"
|
37
|
+
36: "home"
|
38
|
+
37: "left"
|
39
|
+
38: "up"
|
40
|
+
39: "right"
|
41
|
+
40: "down"
|
42
|
+
45: "insert"
|
43
|
+
46: "del"
|
44
|
+
96: "0"
|
45
|
+
97: "1"
|
46
|
+
98: "2"
|
47
|
+
99: "3"
|
48
|
+
100: "4"
|
49
|
+
101: "5"
|
50
|
+
102: "6"
|
51
|
+
103: "7"
|
52
|
+
104: "8"
|
53
|
+
105: "9"
|
54
|
+
106: "*"
|
55
|
+
107: "+"
|
56
|
+
109: "-"
|
57
|
+
110: "."
|
58
|
+
111 : "/"
|
59
|
+
112: "f1"
|
60
|
+
113: "f2"
|
61
|
+
114: "f3"
|
62
|
+
115: "f4"
|
63
|
+
116: "f5"
|
64
|
+
117: "f6"
|
65
|
+
118: "f7"
|
66
|
+
119: "f8"
|
67
|
+
120: "f9"
|
68
|
+
121: "f10"
|
69
|
+
122: "f11"
|
70
|
+
123: "f12"
|
71
|
+
144: "numlock"
|
72
|
+
145: "scroll"
|
73
|
+
186: ";"
|
74
|
+
187: "="
|
75
|
+
188: ","
|
76
|
+
189: "-"
|
77
|
+
190: "."
|
78
|
+
191: "/"
|
79
|
+
219: "["
|
80
|
+
220: "\\"
|
81
|
+
221: "]"
|
82
|
+
222: "'"
|
83
|
+
224: "meta"
|
84
|
+
|
85
|
+
shiftNums:
|
86
|
+
"`": "~"
|
87
|
+
"1": "!"
|
88
|
+
"2": "@"
|
89
|
+
"3": "#"
|
90
|
+
"4": "$"
|
91
|
+
"5": "%"
|
92
|
+
"6": "^"
|
93
|
+
"7": "&"
|
94
|
+
"8": "*"
|
95
|
+
"9": "("
|
96
|
+
"0": ")"
|
97
|
+
"-": "_"
|
98
|
+
"=": "+"
|
99
|
+
";": ":"
|
100
|
+
"'": "\""
|
101
|
+
",": "<"
|
102
|
+
".": ">"
|
103
|
+
"/": "?"
|
104
|
+
"\\": "|"
|
105
|
+
|
106
|
+
keyHandler = (handleObj) ->
|
107
|
+
# Only care when a possible input has been specified
|
108
|
+
if typeof handleObj.data != "string"
|
109
|
+
return
|
110
|
+
|
111
|
+
origHandler = handleObj.handler
|
112
|
+
keys = handleObj.data.toLowerCase().split(" ")
|
113
|
+
|
114
|
+
handleObj.handler = (event) ->
|
115
|
+
# Keypress represents characters, not special keys
|
116
|
+
special = event.type != "keypress" && jQuery.hotkeys.specialKeys[ event.which ]
|
117
|
+
character = String.fromCharCode( event.which ).toLowerCase()
|
118
|
+
modif = ""
|
119
|
+
possible = {}
|
120
|
+
target = event.target
|
121
|
+
|
122
|
+
# check combinations (alt|ctrl|shift+anything)
|
123
|
+
if event.altKey && special != "alt"
|
124
|
+
modif += "alt+"
|
125
|
+
|
126
|
+
if event.ctrlKey && special != "ctrl"
|
127
|
+
modif += "ctrl+"
|
128
|
+
|
129
|
+
# TODO: Need to make sure this works consistently across platforms
|
130
|
+
if event.metaKey && !event.ctrlKey && special != "meta"
|
131
|
+
modif += "meta+"
|
132
|
+
|
133
|
+
# Don't fire in text-accepting inputs that we didn't directly bind to
|
134
|
+
# unless a non-shift modifier key or function key is pressed
|
135
|
+
unless this == target
|
136
|
+
if isTextAcceptingInput(target) && !modif && !isFunctionKey(event)
|
137
|
+
return
|
138
|
+
|
139
|
+
if event.shiftKey && special != "shift"
|
140
|
+
modif += "shift+"
|
141
|
+
|
142
|
+
if special
|
143
|
+
possible[ modif + special ] = true
|
144
|
+
else
|
145
|
+
possible[ modif + character ] = true
|
146
|
+
possible[ modif + jQuery.hotkeys.shiftNums[ character ] ] = true
|
147
|
+
|
148
|
+
# "$" can be triggered as "Shift+4" or "Shift+$" or just "$"
|
149
|
+
if modif == "shift+"
|
150
|
+
possible[ jQuery.hotkeys.shiftNums[ character ] ] = true
|
151
|
+
|
152
|
+
for key in keys
|
153
|
+
if possible[key]
|
154
|
+
return origHandler.apply( this, arguments )
|
155
|
+
|
156
|
+
|
157
|
+
jQuery.each [ "keydown", "keyup", "keypress" ], ->
|
158
|
+
jQuery.event.special[ this ] = { add: keyHandler }
|
159
|
+
|
160
|
+
)(jQuery)
|
161
|
+
|