tea 0.6.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/COPYING +674 -0
- data/COPYING.LESSER +165 -0
- data/README.rdoc +93 -0
- data/doc/example/bitmap_draw.rb +21 -0
- data/doc/example/bitmap_load.rb +14 -0
- data/doc/example/bitmap_new.rb +19 -0
- data/doc/example/circle.rb +24 -0
- data/doc/example/circle_alpha.rb +45 -0
- data/doc/example/circle_alpha_bitmap.rb +51 -0
- data/doc/example/circle_bitmap.rb +18 -0
- data/doc/example/clip.rb +46 -0
- data/doc/example/event_app.rb +45 -0
- data/doc/example/event_keyboard.rb +43 -0
- data/doc/example/event_mouse.rb +85 -0
- data/doc/example/font_hello.rb +22 -0
- data/doc/example/font_word_wrap.rb +44 -0
- data/doc/example/grab.rb +28 -0
- data/doc/example/init.rb +10 -0
- data/doc/example/lines.rb +49 -0
- data/doc/example/lines_aa.rb +44 -0
- data/doc/example/lines_alpha.rb +33 -0
- data/doc/example/point.rb +26 -0
- data/doc/example/rect.rb +15 -0
- data/doc/example/rect_alpha.rb +75 -0
- data/doc/example/screen_set_mode.rb +18 -0
- data/doc/example/screen_update.rb +14 -0
- data/doc/example/sfont_hello.rb +22 -0
- data/doc/example/smile.png +0 -0
- data/doc/example/smile_bounce.rb +44 -0
- data/doc/example/smile_move.rb +58 -0
- data/doc/example/smile_move_2.rb +78 -0
- data/doc/example/sound.rb +101 -0
- data/doc/example/state_app.rb +33 -0
- data/doc/example/state_keyboard.rb +23 -0
- data/doc/example/state_mouse.rb +60 -0
- data/doc/key_constants.textile +129 -0
- data/doc/key_modifiers.textile +19 -0
- data/doc/reference.textile +421 -0
- data/lib/tea.rb +34 -0
- data/lib/tea/c_bitmap.rb +122 -0
- data/lib/tea/c_error.rb +11 -0
- data/lib/tea/c_font.rb +302 -0
- data/lib/tea/c_sound.rb +144 -0
- data/lib/tea/m_color.rb +50 -0
- data/lib/tea/m_event.rb +65 -0
- data/lib/tea/m_event_app.rb +96 -0
- data/lib/tea/m_event_dispatch.rb +54 -0
- data/lib/tea/m_event_keyboard.rb +311 -0
- data/lib/tea/m_event_mouse.rb +189 -0
- data/lib/tea/mix_blitting.rb +31 -0
- data/lib/tea/mix_clipping.rb +71 -0
- data/lib/tea/mix_grabbing.rb +86 -0
- data/lib/tea/mix_image_saving.rb +70 -0
- data/lib/tea/mix_primitive.rb +613 -0
- data/lib/tea/o_screen.rb +98 -0
- metadata +137 -0
data/lib/tea/c_sound.rb
ADDED
@@ -0,0 +1,144 @@
|
|
1
|
+
# This file contains the Sound class.
|
2
|
+
|
3
|
+
require 'sdl'
|
4
|
+
|
5
|
+
require 'tea/c_error'
|
6
|
+
|
7
|
+
#
|
8
|
+
module Tea
|
9
|
+
|
10
|
+
# The Sound class allows loading and playing of audio files.
|
11
|
+
#
|
12
|
+
# Currently supported formats: OGG, WAV, AIFF, RIFF, VOC.
|
13
|
+
class Sound
|
14
|
+
|
15
|
+
# Sound states returned by Tea::Sound#state.
|
16
|
+
STOPPED = :STOPPED
|
17
|
+
PLAYING = :PLAYING
|
18
|
+
PAUSED = :PAUSED
|
19
|
+
|
20
|
+
# As per Ruby/SDL's mixer API.
|
21
|
+
VOLUME_MAX = 128
|
22
|
+
|
23
|
+
# Tracked because Ruby/SDL's mixer API can't get the channel volumes.
|
24
|
+
@@volume = VOLUME_MAX
|
25
|
+
|
26
|
+
# Tracks which Sound objects are playing in which channels, to report
|
27
|
+
# accurate playing state info.
|
28
|
+
@@channel_sound_ids = []
|
29
|
+
|
30
|
+
# Get the master volume. Volume ranges from 0..128 inclusive.
|
31
|
+
def Sound.volume
|
32
|
+
@@volume
|
33
|
+
end
|
34
|
+
|
35
|
+
# Set the master volume. new_volume should be between 0..128 inclusive.
|
36
|
+
def Sound.volume=(new_volume)
|
37
|
+
v = (new_volume >= 0) ? (new_volume <= VOLUME_MAX ? new_volume : VOLUME_MAX) : 0
|
38
|
+
SDL::Mixer.set_volume -1, new_volume
|
39
|
+
@@volume = v
|
40
|
+
end
|
41
|
+
|
42
|
+
# Pause all sound.
|
43
|
+
def Sound.pause_all
|
44
|
+
SDL::Mixer.pause -1
|
45
|
+
end
|
46
|
+
|
47
|
+
# Resume playing all paused sound.
|
48
|
+
def Sound.resume_all
|
49
|
+
SDL::Mixer.resume -1
|
50
|
+
end
|
51
|
+
|
52
|
+
# Stop all sounds, playing or paused.
|
53
|
+
def Sound.stop_all
|
54
|
+
SDL::Mixer.halt -1
|
55
|
+
end
|
56
|
+
|
57
|
+
|
58
|
+
# Load a sound file.
|
59
|
+
#
|
60
|
+
# May raise Tea::Error on failure.
|
61
|
+
def initialize(path)
|
62
|
+
@wave = SDL::Mixer::Wave.load(path)
|
63
|
+
@channel = -1
|
64
|
+
|
65
|
+
# Tracked because Ruby/SDL's mixer API can't get sound volumes.
|
66
|
+
@volume = VOLUME_MAX
|
67
|
+
rescue SDL::Error => e
|
68
|
+
raise Tea::Error, e.message, e.backtrace
|
69
|
+
end
|
70
|
+
|
71
|
+
# Get the sound's volume. Volume ranges from 0..128 inclusive.
|
72
|
+
def volume
|
73
|
+
@volume
|
74
|
+
end
|
75
|
+
|
76
|
+
# Set the sound's volume. new_volume should be between 0..128 inclusive.
|
77
|
+
def volume=(new_volume)
|
78
|
+
v = (new_volume >= 0) ? (new_volume <= VOLUME_MAX ? new_volume : VOLUME_MAX) : 0
|
79
|
+
@wave.set_volume v
|
80
|
+
@volume = v
|
81
|
+
end
|
82
|
+
|
83
|
+
# Play the sound. If this sound is still playing, cut it off and start
|
84
|
+
# playing it from the start.
|
85
|
+
#
|
86
|
+
# loops should be the number of times to repeat playing the sound. Use -1
|
87
|
+
# to loop the sound forever.
|
88
|
+
def play(loops=0)
|
89
|
+
SDL::Mixer.halt(@channel) if channel_valid?
|
90
|
+
|
91
|
+
@channel = SDL::Mixer.play_channel(-1, @wave, loops)
|
92
|
+
@@channel_sound_ids[@channel] = object_id
|
93
|
+
end
|
94
|
+
|
95
|
+
# Pause the sound if it's playing, otherwise do nothing.
|
96
|
+
def pause
|
97
|
+
SDL::Mixer.pause(@channel) if channel_valid?
|
98
|
+
end
|
99
|
+
|
100
|
+
# Resume the sound if it's paused, otherwise do nothing.
|
101
|
+
def resume
|
102
|
+
SDL::Mixer.resume(@channel) if channel_valid?
|
103
|
+
end
|
104
|
+
|
105
|
+
# Stop the sound if it's playing or paused, otherwise do nothing.
|
106
|
+
def stop
|
107
|
+
SDL::Mixer.halt(@channel) if channel_valid?
|
108
|
+
end
|
109
|
+
|
110
|
+
# Check if the sound is stopped, playing or paused. Returns one of
|
111
|
+
# Tea::Sound::STOPPED, Tea::Sound::PLAYING or Tea::Sound::PAUSED. A sound
|
112
|
+
# that isn't playing or paused is considered stopped.
|
113
|
+
def state
|
114
|
+
if channel_valid?
|
115
|
+
if SDL::Mixer.play?(@channel)
|
116
|
+
# For some reason, pause? returns 0 and 1 instead of true and false.
|
117
|
+
if SDL::Mixer.pause?(@channel) != 0
|
118
|
+
PAUSED
|
119
|
+
else
|
120
|
+
PLAYING
|
121
|
+
end
|
122
|
+
else
|
123
|
+
STOPPED
|
124
|
+
end
|
125
|
+
else
|
126
|
+
STOPPED
|
127
|
+
end
|
128
|
+
end
|
129
|
+
|
130
|
+
private
|
131
|
+
|
132
|
+
# Check if @channel really maps to this sound. Returns the channel number
|
133
|
+
# if so, otherwise nil.
|
134
|
+
def channel_valid?
|
135
|
+
if @channel >= 0 && @@channel_sound_ids[@channel] == object_id
|
136
|
+
@channel
|
137
|
+
else
|
138
|
+
nil
|
139
|
+
end
|
140
|
+
end
|
141
|
+
|
142
|
+
end
|
143
|
+
|
144
|
+
end
|
data/lib/tea/m_color.rb
ADDED
@@ -0,0 +1,50 @@
|
|
1
|
+
# This file holds the Color module.
|
2
|
+
|
3
|
+
#
|
4
|
+
module Tea
|
5
|
+
|
6
|
+
# The Color module holds utility methods that can mix and split colors.
|
7
|
+
module Color
|
8
|
+
|
9
|
+
# Create a color from red, green, blue and optionally alpha parts.
|
10
|
+
# All values passed in should be within 0..255 inclusive.
|
11
|
+
def Color.mix(red, green, blue, alpha=255)
|
12
|
+
((red & 0xff) << 24) |
|
13
|
+
((green & 0xff) << 16) |
|
14
|
+
((blue & 0xff) << 8) |
|
15
|
+
(alpha & 0xff)
|
16
|
+
end
|
17
|
+
|
18
|
+
# Break a colour up into its red, green, blue and alpha parts.
|
19
|
+
# Returns a 4-element array of the form [red, green, blue, alpha], where
|
20
|
+
# each element is within 0..255 inclusive.
|
21
|
+
def Color.split(color)
|
22
|
+
[(color & 0xff000000) >> 24,
|
23
|
+
(color & 0x00ff0000) >> 16,
|
24
|
+
(color & 0x0000ff00) >> 8,
|
25
|
+
(color & 0x000000ff)]
|
26
|
+
end
|
27
|
+
|
28
|
+
CLEAR = Color.mix( 0, 0, 0, 0)
|
29
|
+
|
30
|
+
BLACK = Color.mix( 0, 0, 0)
|
31
|
+
DARK_RED = Color.mix(128, 0, 0)
|
32
|
+
DARK_GREEN = Color.mix( 0, 128, 0)
|
33
|
+
DARK_YELLOW = Color.mix(128, 128, 0)
|
34
|
+
DARK_BLUE = Color.mix( 0, 0, 128)
|
35
|
+
DARK_MAGENTA = Color.mix(128, 0, 128)
|
36
|
+
DARK_CYAN = Color.mix( 0, 128, 128)
|
37
|
+
DARK_GRAY = Color.mix(128, 128, 128)
|
38
|
+
|
39
|
+
GRAY = Color.mix(192, 192, 192)
|
40
|
+
RED = Color.mix(255, 0, 0)
|
41
|
+
GREEN = Color.mix( 0, 255, 0)
|
42
|
+
YELLOW = Color.mix(255, 255, 0)
|
43
|
+
BLUE = Color.mix( 0, 0, 255)
|
44
|
+
MAGENTA = Color.mix(255, 0, 255)
|
45
|
+
CYAN = Color.mix( 0, 255, 255)
|
46
|
+
WHITE = Color.mix(255, 255, 255)
|
47
|
+
|
48
|
+
end
|
49
|
+
|
50
|
+
end
|
data/lib/tea/m_event.rb
ADDED
@@ -0,0 +1,65 @@
|
|
1
|
+
# This file holds the core Event module.
|
2
|
+
|
3
|
+
require 'sdl'
|
4
|
+
|
5
|
+
require 'tea/c_error'
|
6
|
+
require 'tea/m_event_app'
|
7
|
+
require 'tea/m_event_dispatch'
|
8
|
+
require 'tea/m_event_keyboard'
|
9
|
+
require 'tea/m_event_mouse'
|
10
|
+
|
11
|
+
#
|
12
|
+
module Tea
|
13
|
+
|
14
|
+
# The Event module allows access to the event queue, and the classes of
|
15
|
+
# events that come out.
|
16
|
+
module Event
|
17
|
+
|
18
|
+
# Tea's generated event queue. Add to the back, get from the front.
|
19
|
+
@@event_queue = []
|
20
|
+
|
21
|
+
# Get the next event in the event queue. If wait is true and there are no
|
22
|
+
# events to return, this method will wait until there is one and return it.
|
23
|
+
# Otherwise, an empty event queue will return nil.
|
24
|
+
#
|
25
|
+
# May raise Tea::Error if getting an event fails.
|
26
|
+
def Event.get(wait=false)
|
27
|
+
if @@event_queue.length == 0
|
28
|
+
if wait
|
29
|
+
begin
|
30
|
+
sdl_event = SDL::Event.wait
|
31
|
+
if (out_events = translate_event(sdl_event))
|
32
|
+
@@event_queue.push *out_events
|
33
|
+
end
|
34
|
+
end until @@event_queue.length > 0
|
35
|
+
else
|
36
|
+
if (out_events = translate_event(SDL::Event.poll))
|
37
|
+
@@event_queue.push *out_events
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
tea_event = @@event_queue.shift
|
43
|
+
[App, Mouse, Kbd].each { |state_holder| state_holder.update_state tea_event }
|
44
|
+
tea_event
|
45
|
+
rescue SDL::Error => e
|
46
|
+
raise Tea::Error, e.message, e.backtrace
|
47
|
+
end
|
48
|
+
|
49
|
+
# Convert an SDL::Event into one or more Tea events. May return nil, a
|
50
|
+
# single event object or multiple events in an array.
|
51
|
+
def Event.translate_event(sdl_event)
|
52
|
+
case sdl_event
|
53
|
+
when SDL::Event::Active, SDL::Event::Quit
|
54
|
+
translate_app_event sdl_event
|
55
|
+
when SDL::Event::MouseMotion, SDL::Event::MouseButtonDown, SDL::Event::MouseButtonUp
|
56
|
+
translate_mouse_event sdl_event
|
57
|
+
when SDL::Event::KeyDown, SDL::Event::KeyUp
|
58
|
+
translate_keyboard_event sdl_event
|
59
|
+
end
|
60
|
+
end
|
61
|
+
private_class_method :translate_event
|
62
|
+
|
63
|
+
end
|
64
|
+
|
65
|
+
end
|
@@ -0,0 +1,96 @@
|
|
1
|
+
# This file holds app-related event handling.
|
2
|
+
|
3
|
+
require 'sdl'
|
4
|
+
|
5
|
+
#
|
6
|
+
module Tea
|
7
|
+
|
8
|
+
module Mouse
|
9
|
+
# Event generated when mouse focus is gained.
|
10
|
+
class Gained
|
11
|
+
end
|
12
|
+
|
13
|
+
# Event generated when mouse focus is lost.
|
14
|
+
class Lost
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
module Kbd
|
19
|
+
# Event generated when keyboard input focus is gained.
|
20
|
+
class Gained
|
21
|
+
end
|
22
|
+
|
23
|
+
# Event generated when keyboard input focus is lost.
|
24
|
+
class Lost
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
module App
|
29
|
+
# Event generated when the player acts to close the screen window.
|
30
|
+
class Exit
|
31
|
+
end
|
32
|
+
|
33
|
+
# Event generated when the screen window is minimised.
|
34
|
+
class Minimized
|
35
|
+
end
|
36
|
+
|
37
|
+
# Event generated when the screen window is restored from being minimised.
|
38
|
+
class Restored
|
39
|
+
end
|
40
|
+
|
41
|
+
# Default for App.visible?.
|
42
|
+
@visible = true
|
43
|
+
|
44
|
+
# Returns true if the screen window has not been minimised, otherwise
|
45
|
+
# false.
|
46
|
+
def App.visible?
|
47
|
+
@visible
|
48
|
+
end
|
49
|
+
|
50
|
+
# Update the reported app state when a Tea event is retrieved, so
|
51
|
+
# App.visible? returns the right status. Called automatically by
|
52
|
+
# Event.get.
|
53
|
+
def App.update_state(tea_event)
|
54
|
+
case tea_event
|
55
|
+
when Minimized then @visible = false
|
56
|
+
when Restored then @visible = true
|
57
|
+
end
|
58
|
+
@visible
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
module Event
|
63
|
+
|
64
|
+
# APP constants rubysdl is missing. For internal use only.
|
65
|
+
APPMOUSEFOCUS_ = 0x01
|
66
|
+
APPINPUTFOCUS_ = 0x02
|
67
|
+
APPACTIVE_ = 0x04
|
68
|
+
|
69
|
+
# Translates an app-related SDL::Event into an array of Tea::Event
|
70
|
+
# objects. For internal use only.
|
71
|
+
def Event.translate_app_event(sdl_event)
|
72
|
+
out_events = []
|
73
|
+
|
74
|
+
case sdl_event
|
75
|
+
when SDL::Event::Quit
|
76
|
+
out_events.push App::Exit.new
|
77
|
+
|
78
|
+
when SDL::Event::Active
|
79
|
+
if (sdl_event.state & APPACTIVE_) != 0
|
80
|
+
out_events.push sdl_event.gain ? App::Restored.new : App::Minimized.new
|
81
|
+
end
|
82
|
+
if (sdl_event.state & APPINPUTFOCUS_) != 0
|
83
|
+
out_events.push sdl_event.gain ? Kbd::Gained.new : Kbd::Lost.new
|
84
|
+
end
|
85
|
+
if (sdl_event.state & APPMOUSEFOCUS_) != 0
|
86
|
+
out_events.push sdl_event.gain ? Mouse::Gained.new : Mouse::Lost.new
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
out_events
|
91
|
+
end
|
92
|
+
private_class_method :translate_app_event
|
93
|
+
|
94
|
+
end
|
95
|
+
|
96
|
+
end
|
@@ -0,0 +1,54 @@
|
|
1
|
+
# This file contains the event dispatch mixin.
|
2
|
+
|
3
|
+
require 'tea/c_error'
|
4
|
+
|
5
|
+
#
|
6
|
+
module Tea
|
7
|
+
|
8
|
+
module Event
|
9
|
+
|
10
|
+
# The Dispatch mixin gives any object the ability to handle Tea events with
|
11
|
+
# method calls. To use it, include the mixin in your class
|
12
|
+
#
|
13
|
+
# include Tea::Event::Dispatch
|
14
|
+
#
|
15
|
+
# define the handling methods (all optional)
|
16
|
+
#
|
17
|
+
# def app_exit; end
|
18
|
+
# def app_restored; end
|
19
|
+
# def app_minimized; end
|
20
|
+
# def kbd_down; end
|
21
|
+
# def kbd_up; end
|
22
|
+
# def mouse_move; end
|
23
|
+
# def mouse_down; end
|
24
|
+
# def mouse_up; end
|
25
|
+
# def mouse_scroll; end
|
26
|
+
#
|
27
|
+
# and when you need events handled, call your instance's dispatch_event
|
28
|
+
# method
|
29
|
+
#
|
30
|
+
# handler = MyEventHandler.new
|
31
|
+
# ...
|
32
|
+
# loop do
|
33
|
+
# event = Tea::Event.get
|
34
|
+
# handler.dispatch_event event if event
|
35
|
+
# ...
|
36
|
+
# end
|
37
|
+
#
|
38
|
+
# Tea will then call the method matching the event received.
|
39
|
+
module Dispatch
|
40
|
+
|
41
|
+
def dispatch_event(tea_event)
|
42
|
+
class_string = tea_event.class.to_s
|
43
|
+
unless class_string =~ /^Tea::(?:App|Kbd|Mouse)::[A-Za-z]+$/
|
44
|
+
raise Tea::Error, "Can't dispatch on class #{class_string}", caller
|
45
|
+
end
|
46
|
+
msg = class_string.split('::', 2)[1].sub('::', '_').downcase.intern
|
47
|
+
send msg, tea_event if respond_to?(msg)
|
48
|
+
end
|
49
|
+
|
50
|
+
end
|
51
|
+
|
52
|
+
end
|
53
|
+
|
54
|
+
end
|
@@ -0,0 +1,311 @@
|
|
1
|
+
# This file holds the key press and modifier events.
|
2
|
+
|
3
|
+
require 'sdl'
|
4
|
+
|
5
|
+
#
|
6
|
+
module Tea
|
7
|
+
|
8
|
+
module Kbd
|
9
|
+
|
10
|
+
# Superclass for all Kbd events.
|
11
|
+
class Event
|
12
|
+
@@sdl_key_table = {
|
13
|
+
SDL::Key::BACKSPACE => :BACKSPACE,
|
14
|
+
SDL::Key::TAB => :TAB,
|
15
|
+
#SDL::Key::CLEAR => clear, # ???
|
16
|
+
SDL::Key::RETURN => :ENTER,
|
17
|
+
SDL::Key::PAUSE => :PAUSE,
|
18
|
+
SDL::Key::ESCAPE => :ESCAPE,
|
19
|
+
SDL::Key::SPACE => :SPACE,
|
20
|
+
SDL::Key::EXCLAIM => :EXCLAMATION_MARK,
|
21
|
+
SDL::Key::QUOTEDBL => :DOUBLE_QUOTE,
|
22
|
+
SDL::Key::HASH => :HASH,
|
23
|
+
SDL::Key::DOLLAR => :DOLLAR,
|
24
|
+
SDL::Key::AMPERSAND => :AMPERSAND,
|
25
|
+
SDL::Key::QUOTE => :QUOTE,
|
26
|
+
SDL::Key::LEFTPAREN => :OPEN_PAREN,
|
27
|
+
SDL::Key::RIGHTPAREN => :CLOSE_PAREN,
|
28
|
+
SDL::Key::ASTERISK => :ASTERISK,
|
29
|
+
SDL::Key::PLUS => :PLUS,
|
30
|
+
SDL::Key::COMMA => :COMMA,
|
31
|
+
SDL::Key::MINUS => :MINUS,
|
32
|
+
SDL::Key::PERIOD => :PERIOD,
|
33
|
+
SDL::Key::SLASH => :SLASH,
|
34
|
+
SDL::Key::K0 => :K0,
|
35
|
+
SDL::Key::K1 => :K1,
|
36
|
+
SDL::Key::K2 => :K2,
|
37
|
+
SDL::Key::K3 => :K3,
|
38
|
+
SDL::Key::K4 => :K4,
|
39
|
+
SDL::Key::K5 => :K5,
|
40
|
+
SDL::Key::K6 => :K6,
|
41
|
+
SDL::Key::K7 => :K7,
|
42
|
+
SDL::Key::K8 => :K8,
|
43
|
+
SDL::Key::K9 => :K9,
|
44
|
+
SDL::Key::COLON => :COLON,
|
45
|
+
SDL::Key::SEMICOLON => :SEMICOLON,
|
46
|
+
SDL::Key::LESS => :LESS_THAN,
|
47
|
+
SDL::Key::EQUALS => :EQUALS,
|
48
|
+
SDL::Key::GREATER => :GREATER_THAN,
|
49
|
+
SDL::Key::QUESTION => :QUESTION_MARK,
|
50
|
+
SDL::Key::AT => :AT,
|
51
|
+
SDL::Key::LEFTBRACKET => :OPEN_SQUARE_BRACKET,
|
52
|
+
SDL::Key::BACKSLASH => :BACKSLASH,
|
53
|
+
SDL::Key::RIGHTBRACKET => :CLOSE_SQUARE_BRACKET,
|
54
|
+
SDL::Key::CARET => :CARET,
|
55
|
+
SDL::Key::UNDERSCORE => :UNDERSCORE,
|
56
|
+
SDL::Key::BACKQUOTE => :BACKTICK,
|
57
|
+
SDL::Key::A => :A,
|
58
|
+
SDL::Key::B => :B,
|
59
|
+
SDL::Key::C => :C,
|
60
|
+
SDL::Key::D => :D,
|
61
|
+
SDL::Key::E => :E,
|
62
|
+
SDL::Key::F => :F,
|
63
|
+
SDL::Key::G => :G,
|
64
|
+
SDL::Key::H => :H,
|
65
|
+
SDL::Key::I => :I,
|
66
|
+
SDL::Key::J => :J,
|
67
|
+
SDL::Key::K => :K,
|
68
|
+
SDL::Key::L => :L,
|
69
|
+
SDL::Key::M => :M,
|
70
|
+
SDL::Key::N => :N,
|
71
|
+
SDL::Key::O => :O,
|
72
|
+
SDL::Key::P => :P,
|
73
|
+
SDL::Key::Q => :Q,
|
74
|
+
SDL::Key::R => :R,
|
75
|
+
SDL::Key::S => :S,
|
76
|
+
SDL::Key::T => :T,
|
77
|
+
SDL::Key::U => :U,
|
78
|
+
SDL::Key::V => :V,
|
79
|
+
SDL::Key::W => :W,
|
80
|
+
SDL::Key::X => :X,
|
81
|
+
SDL::Key::Y => :Y,
|
82
|
+
SDL::Key::Z => :Z,
|
83
|
+
SDL::Key::DELETE => :DELETE,
|
84
|
+
SDL::Key::KP0 => :NP0,
|
85
|
+
SDL::Key::KP1 => :NP1,
|
86
|
+
SDL::Key::KP2 => :NP2,
|
87
|
+
SDL::Key::KP3 => :NP3,
|
88
|
+
SDL::Key::KP4 => :NP4,
|
89
|
+
SDL::Key::KP5 => :NP5,
|
90
|
+
SDL::Key::KP6 => :NP6,
|
91
|
+
SDL::Key::KP7 => :NP7,
|
92
|
+
SDL::Key::KP8 => :NP8,
|
93
|
+
SDL::Key::KP9 => :NP9,
|
94
|
+
SDL::Key::KP_PERIOD => :NP_PERIOD,
|
95
|
+
SDL::Key::KP_DIVIDE => :NP_DIVIDE,
|
96
|
+
SDL::Key::KP_MULTIPLY => :NP_MULTIPLY,
|
97
|
+
SDL::Key::KP_MINUS => :NP_MINUS,
|
98
|
+
SDL::Key::KP_PLUS => :NP_PLUS,
|
99
|
+
SDL::Key::KP_ENTER => :NP_ENTER,
|
100
|
+
SDL::Key::KP_EQUALS => :NP_EQUALS,
|
101
|
+
SDL::Key::UP => :UP,
|
102
|
+
SDL::Key::DOWN => :DOWN,
|
103
|
+
SDL::Key::RIGHT => :RIGHT,
|
104
|
+
SDL::Key::LEFT => :LEFT,
|
105
|
+
SDL::Key::INSERT => :INSERT,
|
106
|
+
SDL::Key::HOME => :HOME,
|
107
|
+
SDL::Key::END => :END,
|
108
|
+
SDL::Key::PAGEUP => :PAGE_UP,
|
109
|
+
SDL::Key::PAGEDOWN => :PAGE_DOWN,
|
110
|
+
SDL::Key::F1 => :F1,
|
111
|
+
SDL::Key::F2 => :F2,
|
112
|
+
SDL::Key::F3 => :F3,
|
113
|
+
SDL::Key::F4 => :F4,
|
114
|
+
SDL::Key::F5 => :F5,
|
115
|
+
SDL::Key::F6 => :F6,
|
116
|
+
SDL::Key::F7 => :F7,
|
117
|
+
SDL::Key::F8 => :F8,
|
118
|
+
SDL::Key::F9 => :F9,
|
119
|
+
SDL::Key::F10 => :F10,
|
120
|
+
SDL::Key::F11 => :F11,
|
121
|
+
SDL::Key::F12 => :F12,
|
122
|
+
#SDL::Key::F13 => F13, # Who
|
123
|
+
#SDL::Key::F14 => F14, # has
|
124
|
+
#SDL::Key::F15 => F15, # these?
|
125
|
+
SDL::Key::NUMLOCK => :NUM_LOCK,
|
126
|
+
SDL::Key::CAPSLOCK => :CAPS_LOCK,
|
127
|
+
SDL::Key::SCROLLOCK => :SCROLL_LOCK,
|
128
|
+
SDL::Key::RSHIFT => :R_SHIFT,
|
129
|
+
SDL::Key::LSHIFT => :L_SHIFT,
|
130
|
+
SDL::Key::RCTRL => :R_CTRL,
|
131
|
+
SDL::Key::LCTRL => :L_CTRL,
|
132
|
+
SDL::Key::RALT => :R_ALT,
|
133
|
+
SDL::Key::LALT => :L_ALT,
|
134
|
+
#SDL::Key::RMETA => right meta, # 'meta' should
|
135
|
+
#SDL::Key::LMETA => left meta, # be 'alt'?
|
136
|
+
SDL::Key::LSUPER => :L_SUPER,
|
137
|
+
SDL::Key::RSUPER => :R_SUPER,
|
138
|
+
SDL::Key::MODE => :ALT_GR,
|
139
|
+
#SDL::Key::HELP => help, # Rare enough to cause problems.
|
140
|
+
SDL::Key::PRINT => :PRINT_SCREEN,
|
141
|
+
SDL::Key::SYSREQ => :SYS_REQ,
|
142
|
+
SDL::Key::BREAK => :BREAK,
|
143
|
+
SDL::Key::MENU => :MENU,
|
144
|
+
#SDL::Key::POWER => power, # "Power Macintosh" power key
|
145
|
+
SDL::Key::EURO => :EURO, # Some European keyboards need this.
|
146
|
+
}
|
147
|
+
|
148
|
+
# Call a block for each defined Tea key constant.
|
149
|
+
def Event.each_key
|
150
|
+
@@sdl_key_table.each_value { |key_const| yield key_const }
|
151
|
+
end
|
152
|
+
|
153
|
+
protected
|
154
|
+
|
155
|
+
# Convert an SDL keysym to a Tea key constant
|
156
|
+
def sdl_keysym_to_key(sdl_keysym)
|
157
|
+
@@sdl_key_table[sdl_keysym]
|
158
|
+
end
|
159
|
+
|
160
|
+
# Convert SDL key modifier info into an array of active key modifiers.
|
161
|
+
def sdl_keymod_to_mods(sdl_keymod)
|
162
|
+
mods = {}
|
163
|
+
|
164
|
+
mods[:L_SHIFT] = (sdl_keymod & SDL::Key::MOD_LSHIFT) != 0
|
165
|
+
mods[:R_SHIFT] = (sdl_keymod & SDL::Key::MOD_RSHIFT) != 0
|
166
|
+
mods[:SHIFT] = mods[:L_SHIFT] || mods[:R_SHIFT]
|
167
|
+
|
168
|
+
mods[:L_CTRL] = (sdl_keymod & SDL::Key::MOD_LCTRL) != 0
|
169
|
+
mods[:R_CTRL] = (sdl_keymod & SDL::Key::MOD_RCTRL) != 0
|
170
|
+
mods[:CTRL] = mods[:L_CTRL] || mods[:R_CTRL]
|
171
|
+
|
172
|
+
mods[:L_ALT] = (sdl_keymod & SDL::Key::MOD_LALT) != 0
|
173
|
+
mods[:R_ALT] = (sdl_keymod & SDL::Key::MOD_RALT) != 0
|
174
|
+
mods[:ALT] = mods[:L_ALT] || mods[:R_ALT]
|
175
|
+
|
176
|
+
mods[:NUM_LOCK] = (sdl_keymod & SDL::Key::MOD_NUM) != 0
|
177
|
+
mods[:CAPS_LOCK] = (sdl_keymod & SDL::Key::MOD_CAPS) != 0
|
178
|
+
mods[:ALT_GR] = (sdl_keymod & SDL::Key::MOD_MODE) != 0
|
179
|
+
|
180
|
+
mods
|
181
|
+
end
|
182
|
+
end
|
183
|
+
|
184
|
+
# Event generated when a key is pressed down.
|
185
|
+
#
|
186
|
+
# +key+:: Physical key that was pressed, as a symbol (see key reference).
|
187
|
+
# +mods+:: Hash of the active key modifiers. Values are +true+ or
|
188
|
+
# +false+, and the keys can be: +:L_SHIFT+, +:R_SHIFT+,
|
189
|
+
# +:L_CTRL+, +:R_CTRL+, +:L_ALT+, +:R_ALT+, +:NUM_LOCK+,
|
190
|
+
# +:CAPS_LOCK+, +:ALT_GR+. Also, +:SHIFT+, +:CTRL+ and +:ALT+
|
191
|
+
# are provided for convenience, and Tea key constants with the
|
192
|
+
# same names can be used instead.
|
193
|
+
# +char+:: String character generated by that key and those modifiers.
|
194
|
+
# With Ruby >= 1.9, the encoding of this character is UTF-8,
|
195
|
+
# otherwise it varies with the running environment.
|
196
|
+
class Down < Event
|
197
|
+
attr_reader :key, :mods, :char
|
198
|
+
def initialize(sdl_event)
|
199
|
+
@key = sdl_keysym_to_key(sdl_event.sym)
|
200
|
+
@mods = sdl_keymod_to_mods(sdl_event.mod)
|
201
|
+
|
202
|
+
if sdl_event.unicode != 0
|
203
|
+
unicode_field = "%c"
|
204
|
+
# Ruby 1.9 uses UTF-8 Unicode encoding. Otherwise, who knows how
|
205
|
+
# Unicode code points are interpreted?
|
206
|
+
unicode_field = unicode_field.encode('utf-8') if RUBY_1_9
|
207
|
+
@char = unicode_field % sdl_event.unicode
|
208
|
+
else
|
209
|
+
@char = ''
|
210
|
+
end
|
211
|
+
end
|
212
|
+
end
|
213
|
+
|
214
|
+
# Event generated when a held-down key is released. +key+ and +mods+ are
|
215
|
+
# the same as in KeyDown.
|
216
|
+
#
|
217
|
+
# +key+:: Physical key that was pressed, as a symbol (see key reference).
|
218
|
+
# +mods+:: Hash of the active key modifiers. Values are +true+ or
|
219
|
+
# +false+, and the keys can be: +:L_SHIFT+, +:R_SHIFT+,
|
220
|
+
# +:L_CTRL+, +:R_CTRL+, +:L_ALT+, +:R_ALT+, +:NUM_LOCK+,
|
221
|
+
# +:CAPS_LOCK+, +:ALT_GR+. Also, +:SHIFT+, +:CTRL+ and +:ALT+
|
222
|
+
# are provided for convenience, and Tea key constants with the
|
223
|
+
# same names can be used instead.
|
224
|
+
class Up < Event
|
225
|
+
attr_reader :key, :mods
|
226
|
+
def initialize(sdl_event)
|
227
|
+
@key = sdl_keysym_to_key(sdl_event.sym)
|
228
|
+
@mods = sdl_keymod_to_mods(sdl_event.mod)
|
229
|
+
end
|
230
|
+
end
|
231
|
+
|
232
|
+
# Defaults for Kbd.key_down?, Kbd.mod_active? and Kbd.in_app?.
|
233
|
+
@key_states = {}
|
234
|
+
Event.each_key { |key| @key_states[key] = false }
|
235
|
+
|
236
|
+
@mod_states = { :L_SHIFT => false, :R_SHIFT => false, :SHIFT => false,
|
237
|
+
:L_CTRL => false, :R_CTRL => false, :CTRL => false,
|
238
|
+
:L_ALT => false, :R_ALT => false, :ALT => false,
|
239
|
+
:NUM_LOCK => false,
|
240
|
+
:CAPS_LOCK => false,
|
241
|
+
:ALT_GR => false }
|
242
|
+
|
243
|
+
@in_app = true
|
244
|
+
|
245
|
+
# Returns +true+ if +key+ is being pressed down.
|
246
|
+
def Kbd.key_down?(key)
|
247
|
+
if (down = @key_states[key]) == nil
|
248
|
+
raise Tea::Error, "Can't find key #{key} to check", caller
|
249
|
+
end
|
250
|
+
down
|
251
|
+
end
|
252
|
+
|
253
|
+
# Returns true if the modifier is 'active'. For +:L_SHIFT+, +:R_SHIFT+,
|
254
|
+
# +:L_CTRL+, +:R_CTRL+, +:L_ALT+, and +:ALT_GR+ (and convenience modifier
|
255
|
+
# constants +:SHIFT+, +:CTRL+ and +:ALT+), this means they're being held
|
256
|
+
# down. For +:NUM_LOCK+ and +:CAPS_LOCK+, this means their toggle is on.
|
257
|
+
def Kbd.mod_active?(mod)
|
258
|
+
if (active = @mod_states[mod]) == nil
|
259
|
+
raise Tea::Error, "Can't find modifier #{mod} to check", caller
|
260
|
+
end
|
261
|
+
active
|
262
|
+
end
|
263
|
+
|
264
|
+
# Returns true if the keyboard is focused in the screen window.
|
265
|
+
def Kbd.in_app?
|
266
|
+
@in_app
|
267
|
+
end
|
268
|
+
|
269
|
+
# Update the keyboard state, so that Kbd.key_down? and Kbd.mod_active?
|
270
|
+
# provide fresh data. Called automatically by Event.get.
|
271
|
+
def Kbd.update_state(tea_event)
|
272
|
+
case tea_event
|
273
|
+
when Down, Up
|
274
|
+
@key_states[tea_event.key] = (tea_event.class == Down)
|
275
|
+
@mod_states.merge! tea_event.mods
|
276
|
+
when Lost then @in_app = false
|
277
|
+
when Gained then @in_app = true
|
278
|
+
end
|
279
|
+
end
|
280
|
+
|
281
|
+
# Define Tea key symbols as constants to avoid typo errors.
|
282
|
+
Event.each_key { |key| const_set(key, key) }
|
283
|
+
|
284
|
+
# Extra modifier constants for making modifier detection more consistent.
|
285
|
+
SHIFT = :SHIFT
|
286
|
+
CTRL = :CTRL
|
287
|
+
ALT = :ALT
|
288
|
+
|
289
|
+
end
|
290
|
+
|
291
|
+
module Event
|
292
|
+
|
293
|
+
# Convert a keyboard-related SDL::Event into a Tea event. For internal use
|
294
|
+
# only.
|
295
|
+
def Event.translate_keyboard_event(sdl_event)
|
296
|
+
out_events = []
|
297
|
+
|
298
|
+
case sdl_event
|
299
|
+
when SDL::Event::KeyDown
|
300
|
+
out_events.push Kbd::Down.new(sdl_event)
|
301
|
+
when SDL::Event::KeyUp
|
302
|
+
out_events.push Kbd::Up.new(sdl_event)
|
303
|
+
end
|
304
|
+
|
305
|
+
out_events
|
306
|
+
end
|
307
|
+
private_class_method :translate_keyboard_event
|
308
|
+
|
309
|
+
end
|
310
|
+
|
311
|
+
end
|