shank 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- 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
|
+
|