allegro4r 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/History.txt +4 -0
- data/Manifest.txt +58 -0
- data/README.txt +94 -0
- data/examples/exdbuf.rb +58 -0
- data/examples/exfixed.rb +46 -0
- data/examples/exflame.rb +200 -0
- data/examples/exflip.rb +87 -0
- data/examples/exfont.rb +70 -0
- data/examples/exhello.rb +46 -0
- data/examples/exjoy.rb +206 -0
- data/examples/exkeys.rb +216 -0
- data/examples/exmem.rb +50 -0
- data/examples/exmidi.rb +97 -0
- data/examples/exmouse.rb +149 -0
- data/examples/expal.rb +70 -0
- data/examples/expat.rb +62 -0
- data/examples/exsample.rb +89 -0
- data/examples/extimer.rb +84 -0
- data/examples/unifont.dat +0 -0
- data/ext/a4r_API_BITMAP.c +27 -0
- data/ext/a4r_API_DIGI_DRIVER.c +14 -0
- data/ext/a4r_API_GFX_DRIVER.c +14 -0
- data/ext/a4r_API_JOYSTICK_AXIS_INFO.c +53 -0
- data/ext/a4r_API_JOYSTICK_BUTTON_INFO.c +27 -0
- data/ext/a4r_API_JOYSTICK_DRIVER.c +14 -0
- data/ext/a4r_API_JOYSTICK_INFO.c +84 -0
- data/ext/a4r_API_JOYSTICK_STICK_INFO.c +62 -0
- data/ext/a4r_API_KEYBOARD_DRIVER.c +14 -0
- data/ext/a4r_API_MIDI_DRIVER.c +14 -0
- data/ext/a4r_API_MOUSE_DRIVER.c +14 -0
- data/ext/a4r_API_PALETTE.c +63 -0
- data/ext/a4r_API_RGB.c +118 -0
- data/ext/a4r_API_TIMER_DRIVER.c +14 -0
- data/ext/a4r_API_bitmap_objects.c +310 -0
- data/ext/a4r_API_blitting_and_sprites.c +86 -0
- data/ext/a4r_API_digital_sample_routines.c +83 -0
- data/ext/a4r_API_direct_access_to_video_memory.c +102 -0
- data/ext/a4r_API_drawing_primitives.c +114 -0
- data/ext/a4r_API_file_and_compression_routines.c +27 -0
- data/ext/a4r_API_fixed_point_math_routines.c +98 -0
- data/ext/a4r_API_fonts.c +147 -0
- data/ext/a4r_API_graphics_modes.c +155 -0
- data/ext/a4r_API_joystick_routines.c +213 -0
- data/ext/a4r_API_keyboard_routines.c +420 -0
- data/ext/a4r_API_misc.c +133 -0
- data/ext/a4r_API_mouse_routines.c +220 -0
- data/ext/a4r_API_music_routines_midi.c +147 -0
- data/ext/a4r_API_palette_routines.c +112 -0
- data/ext/a4r_API_sound_init_routines.c +29 -0
- data/ext/a4r_API_text_output.c +178 -0
- data/ext/a4r_API_timer_routines.c +250 -0
- data/ext/a4r_API_transparency_and_patterned_drawing.c +87 -0
- data/ext/a4r_API_truecolor_pixel_formats.c +44 -0
- data/ext/a4r_API_unicode_routines.c +53 -0
- data/ext/a4r_API_using_allegro.c +98 -0
- data/ext/allegro4r.c +866 -0
- data/ext/allegro4r.h +311 -0
- data/ext/extconf.rb +11 -0
- metadata +112 -0
@@ -0,0 +1,155 @@
|
|
1
|
+
#include "allegro4r.h"
|
2
|
+
|
3
|
+
/*
|
4
|
+
* call-seq:
|
5
|
+
* set_gfx_mode(card, w, h, v_w, v_h) -> int
|
6
|
+
*
|
7
|
+
* Switches into graphics mode. The card parameter should usually be one of the
|
8
|
+
* Allegro magic drivers (read introduction of chapter "Graphics modes") or see
|
9
|
+
* the platform specific documentation for a list of the available drivers. The
|
10
|
+
* w and h parameters specify what screen resolution you want. The color depth
|
11
|
+
* of the graphic mode has to be specified before calling this function with
|
12
|
+
* set_color_depth.
|
13
|
+
*
|
14
|
+
* The v_w and v_h parameters specify the minimum virtual screen size, in case
|
15
|
+
* you need a large virtual screen for hardware scrolling or page flipping. You
|
16
|
+
* should set them to zero if you don't care about the virtual screen size.
|
17
|
+
*
|
18
|
+
* When you call set_gfx_mode, the v_w and v_h parameters represent the minimum
|
19
|
+
* size of virtual screen that is acceptable for your program. The range of
|
20
|
+
* possible sizes is usually very restricted, and Allegro may end up creating a
|
21
|
+
* virtual screen much larger than the one you request. Allowed sizes are driver
|
22
|
+
* dependent and some drivers do not allow virtual screens that are larger than
|
23
|
+
* the visible screen at all: don't assume that whatever you pass will always
|
24
|
+
* work.
|
25
|
+
*
|
26
|
+
* In mode-X the virtual width can be any multiple of eight greater than or
|
27
|
+
* equal to the physical screen width, and the virtual height will be set
|
28
|
+
* accordingly (the VGA has 256k of vram, so the virtual height will be
|
29
|
+
* 256*1024/virtual_width).
|
30
|
+
*
|
31
|
+
* Currently, using a big virtual screen for page flipping is considered bad
|
32
|
+
* practice. There are platforms which don't support virtual screens bigger than
|
33
|
+
* the physical screen but can create different video pages to flip back and
|
34
|
+
* forth. This means that, if you want page flipping and aren't going to use
|
35
|
+
* hardware scrolling, you should call set_gfx_mode with (0,0) as the virtual
|
36
|
+
* screen size and later create the different video pages with
|
37
|
+
* create_video_bitmap. Otherwise your program will be limited to the platforms
|
38
|
+
* supporting hardware scrolling.
|
39
|
+
*
|
40
|
+
* After you select a graphics mode, the physical and virtual screen sizes can
|
41
|
+
* be checked with the macros SCREEN_W, SCREEN_H, VIRTUAL_W, and VIRTUAL_H.
|
42
|
+
*
|
43
|
+
* Return value: Returns zero on success. On failure returns a negative number
|
44
|
+
* and stores a description of the problem in allegro_error.
|
45
|
+
*/
|
46
|
+
VALUE a4r_API_set_gfx_mode(VALUE self, VALUE card, VALUE w, VALUE h, VALUE v_w, VALUE v_h)
|
47
|
+
{
|
48
|
+
return INT2FIX(set_gfx_mode(NUM2INT(card), FIX2INT(w), FIX2INT(h), FIX2INT(v_w), FIX2INT(v_h)));
|
49
|
+
}
|
50
|
+
|
51
|
+
/*
|
52
|
+
* call-seq:
|
53
|
+
* set_display_switch_mode(mode) -> int
|
54
|
+
*
|
55
|
+
* Sets how the program should handle being switched into the background, if the
|
56
|
+
* user tabs away from it. Not all of the possible modes will be supported by
|
57
|
+
* every graphics driver on every platform. The available modes are:
|
58
|
+
* SWITCH_NONE::
|
59
|
+
* Disables switching. This is the default in single-tasking systems like DOS.
|
60
|
+
* It may be supported on other platforms, but you should use it with caution,
|
61
|
+
* because your users won't be impressed if they want to switch away from your
|
62
|
+
* program, but you don't let them!
|
63
|
+
* SWITCH_PAUSE::
|
64
|
+
* Pauses the program whenever it is in the background. Execution will be
|
65
|
+
* resumed as soon as the user switches back to it. This is the default in
|
66
|
+
* most fullscreen multitasking environments, for example the Linux console,
|
67
|
+
* but not under Windows.
|
68
|
+
* SWITCH_AMNESIA::
|
69
|
+
* Like SWITCH_PAUSE, but this mode doesn't bother to remember the contents of
|
70
|
+
* video memory, so the screen, and any video bitmaps that you have created,
|
71
|
+
* will be erased after the user switches away and then back to your program.
|
72
|
+
* This is not a terribly useful mode to have, but it is the default for the
|
73
|
+
* fullscreen drivers under Windows because DirectDraw is too dumb to
|
74
|
+
* implement anything better.
|
75
|
+
* SWITCH_BACKGROUND::
|
76
|
+
* The program will carry on running in the background, with the screen bitmap
|
77
|
+
* temporarily being pointed at a memory buffer for the fullscreen drivers.
|
78
|
+
* You must take special care when using this mode, because bad things will
|
79
|
+
* happen if the screen bitmap gets changed around when your program isn't
|
80
|
+
* expecting it (see below).
|
81
|
+
* SWITCH_BACKAMNESIA::
|
82
|
+
* Like SWITCH_BACKGROUND, but this mode doesn't bother to remember the
|
83
|
+
* contents of video memory (see SWITCH_AMNESIA). It is again the only mode
|
84
|
+
* supported by the fullscreen drivers under Windows that lets the program
|
85
|
+
* keep running in the background.
|
86
|
+
*
|
87
|
+
* Note that you should be very careful when you are using graphics routines in
|
88
|
+
* the switching context: you must always call acquire_screen before the start
|
89
|
+
* of any drawing code onto the screen and not release it until you are
|
90
|
+
* completely finished, because the automatic locking mechanism may not be good
|
91
|
+
* enough to work when the program runs in the background or has just been
|
92
|
+
* raised in the foreground.
|
93
|
+
*
|
94
|
+
* Return value: Returns zero on success, invalidating at the same time all
|
95
|
+
* callbacks previously registered with set_display_switch_callback. Returns -1
|
96
|
+
* if the requested mode is not currently possible.
|
97
|
+
*/
|
98
|
+
VALUE a4r_API_set_display_switch_mode(VALUE self, VALUE mode)
|
99
|
+
{
|
100
|
+
return INT2FIX(set_display_switch_mode(FIX2INT(mode)));
|
101
|
+
}
|
102
|
+
|
103
|
+
/*
|
104
|
+
* call-seq:
|
105
|
+
* show_video_bitmap(bitmap) -> int
|
106
|
+
*
|
107
|
+
* Attempts to page flip the hardware screen to display the specified video
|
108
|
+
* bitmap object, which must be the same size as the physical screen, and should
|
109
|
+
* have been obtained by calling the create_video_bitmap function.
|
110
|
+
*
|
111
|
+
* Allegro will handle any necessary vertical retrace synchronisation when page
|
112
|
+
* flipping, so you don't need to call vsync before it. This means that
|
113
|
+
* show_video_bitmap has the same time delay effects as vsync by default. This
|
114
|
+
* can be adjusted with the "disable_vsync" config key in the [graphics] section
|
115
|
+
* of allegro.cfg. Example:
|
116
|
+
* video_page = Array.new
|
117
|
+
* ...
|
118
|
+
* # Create pages for page flipping
|
119
|
+
* video_page[0] = create_video_bitmap(SCREEN_W, SCREEN_H)
|
120
|
+
* video_page[1] = create_video_bitmap(SCREEN_W, SCREEN_H)
|
121
|
+
* current_page = 0
|
122
|
+
* ...
|
123
|
+
* # draw the screen and flip pages
|
124
|
+
* draw_screen(video_page[current_page])
|
125
|
+
* show_video_bitmap(video_page[current_page])
|
126
|
+
* current_page = (current_page + 1) % 2
|
127
|
+
* ...
|
128
|
+
*
|
129
|
+
* Return value: Returns zero on success and non-zero on failure.
|
130
|
+
*/
|
131
|
+
VALUE a4r_API_show_video_bitmap(VALUE self, VALUE bitmap)
|
132
|
+
{
|
133
|
+
BITMAP *bmp;
|
134
|
+
Data_Get_Struct(bitmap, BITMAP, bmp);
|
135
|
+
return INT2FIX(show_video_bitmap(bmp));
|
136
|
+
}
|
137
|
+
|
138
|
+
/*
|
139
|
+
* call-seq:
|
140
|
+
* vsync -> nil
|
141
|
+
*
|
142
|
+
* Waits for a vertical retrace to begin. The retrace happens when the electron
|
143
|
+
* beam in your monitor has reached the bottom of the screen and is moving back
|
144
|
+
* to the top ready for another scan. During this short period the graphics card
|
145
|
+
* isn't sending any data to the monitor, so you can do things to it that aren't
|
146
|
+
* possible at other times, such as altering the palette without causing
|
147
|
+
* flickering (snow). Allegro will automatically wait for a retrace before
|
148
|
+
* altering the palette or doing any hardware scrolling, though, so you don't
|
149
|
+
* normally need to bother with this function.
|
150
|
+
*/
|
151
|
+
VALUE a4r_API_vsync(VALUE self)
|
152
|
+
{
|
153
|
+
vsync();
|
154
|
+
return Qnil;
|
155
|
+
}
|
@@ -0,0 +1,213 @@
|
|
1
|
+
#include "allegro4r.h"
|
2
|
+
|
3
|
+
/*
|
4
|
+
* call-seq:
|
5
|
+
* install_joystick(type) -> int
|
6
|
+
*
|
7
|
+
* Installs Allegro's joystick handler, and calibrates the centre position
|
8
|
+
* values. The type parameter should usually be JOY_TYPE_AUTODETECT, or see the
|
9
|
+
* platform specific documentation for a list of the available drivers. You must
|
10
|
+
* call this routine before using any other joystick functions, and you should
|
11
|
+
* make sure that all joysticks are in the middle position at the time. Example:
|
12
|
+
* textout_centre_ex(screen, font,
|
13
|
+
* "Center the joystick and press a key",
|
14
|
+
* SCREEN_W()/2, SCREEN_H()/2, red_color, -1)
|
15
|
+
* readkey
|
16
|
+
* if install_joystick(JOY_TYPE_AUTODETECT) != 0
|
17
|
+
* abort_on_error("Error initialising joystick!")
|
18
|
+
* end
|
19
|
+
*
|
20
|
+
* Return value: Returns zero on success. As soon as you have installed the
|
21
|
+
* joystick module, you will be able to read the button state and digital
|
22
|
+
* (on/off toggle) direction information, which may be enough for some games. If
|
23
|
+
* you want to get full analogue input, though, you need to use the
|
24
|
+
* calibrate_joystick functions to measure the exact range of the inputs: see
|
25
|
+
* below.
|
26
|
+
*/
|
27
|
+
VALUE a4r_API_install_joystick(VALUE self, VALUE type)
|
28
|
+
{
|
29
|
+
return INT2FIX(install_joystick(FIX2INT(type)));
|
30
|
+
}
|
31
|
+
|
32
|
+
/*
|
33
|
+
* call-seq:
|
34
|
+
* poll_joystick -> int
|
35
|
+
*
|
36
|
+
* The joystick handler is not interrupt driven, so you need to call this
|
37
|
+
* function every now and again to update the global position values. Example:
|
38
|
+
* loop do
|
39
|
+
* # Get joystick input
|
40
|
+
* poll_joystick
|
41
|
+
*
|
42
|
+
* # Process input for the first joystick
|
43
|
+
* if joy[0].button[0].b
|
44
|
+
* first_button_pressed
|
45
|
+
* end
|
46
|
+
*
|
47
|
+
* if joy[0].button[1].b
|
48
|
+
* second_button_pressed
|
49
|
+
* end
|
50
|
+
* ...
|
51
|
+
* break if done
|
52
|
+
* end
|
53
|
+
*
|
54
|
+
* Return value: Returns zero on success or a negative number on failure
|
55
|
+
* (usually because no joystick driver was installed).
|
56
|
+
*/
|
57
|
+
VALUE a4r_API_poll_joystick(VALUE self)
|
58
|
+
{
|
59
|
+
return INT2FIX(poll_joystick());
|
60
|
+
}
|
61
|
+
|
62
|
+
/*
|
63
|
+
* call-seq:
|
64
|
+
* num_joysticks -> int
|
65
|
+
*
|
66
|
+
* Global variable containing the number of active joystick devices. The current
|
67
|
+
* drivers support a maximum of eight controllers.
|
68
|
+
*/
|
69
|
+
VALUE a4r_API_num_joysticks(VALUE self)
|
70
|
+
{
|
71
|
+
// TODO: Convert to data struct or cached or hooked variable?
|
72
|
+
return INT2FIX(num_joysticks);
|
73
|
+
}
|
74
|
+
|
75
|
+
/*
|
76
|
+
* call-seq:
|
77
|
+
* joy -> ary
|
78
|
+
*
|
79
|
+
* Global array of joystick state information, which is updated by the
|
80
|
+
* poll_joystick function. Only the first num_joysticks elements will contain
|
81
|
+
* meaningful information. Joystick info is described by the JOYSTICK_INFO
|
82
|
+
* class.
|
83
|
+
*
|
84
|
+
* The button status is stored in the JOYSTICK_BUTTON_INFO class.
|
85
|
+
*
|
86
|
+
* You may wish to display the button names as part of an input configuration
|
87
|
+
* screen to let the user choose what game function will be performed by each
|
88
|
+
* button, but in simpler situations you can safely assume that the first two
|
89
|
+
* elements in the button array will always be the main trigger controls.
|
90
|
+
*
|
91
|
+
* Each joystick will provide one or more stick inputs, of varying types. These
|
92
|
+
* can be digital controls which snap to specific positions (eg. a gamepad
|
93
|
+
* controller, the coolie hat on a Flightstick Pro or Wingman Extreme, or a
|
94
|
+
* normal joystick which hasn't yet been calibrated), or they can be full
|
95
|
+
* analogue inputs with a smooth range of motion. Sticks may also have different
|
96
|
+
* numbers of axes, for example a normal directional control has two, but the
|
97
|
+
* Flightstick Pro throttle is only a single axis, and it is possible that the
|
98
|
+
* system could be extended in the future to support full 3d controllers. A
|
99
|
+
* stick input is described by the JOYSTICK_STICK_INFO class.
|
100
|
+
*
|
101
|
+
* A single joystick may provide several different stick inputs, but you can
|
102
|
+
* safely assume that the first element in the stick array will always be the
|
103
|
+
* main directional controller.
|
104
|
+
*
|
105
|
+
* Information about each of the stick axis is stored in the subclass
|
106
|
+
* JOYSTICK_AXIS_INFO.
|
107
|
+
*
|
108
|
+
* This provides both analogue input in the pos field (ranging from -128 to 128
|
109
|
+
* or from 0 to 255, depending on the type of the control), and digital values
|
110
|
+
* in the d1 and d2 fields. For example, when describing the X-axis position,
|
111
|
+
* the pos field will hold the horizontal position of the joystick, d1 will be
|
112
|
+
* set if it is moved left, and d2 will be set if it is moved right. Allegro
|
113
|
+
* will fill in all these values regardless of whether it is using a digital or
|
114
|
+
* analogue joystick, emulating the pos field for digital inputs by snapping it
|
115
|
+
* to the min, middle, and maximum positions, and emulating the d1 and d2 values
|
116
|
+
* for an analogue stick by comparing the current position with the centre
|
117
|
+
* point.
|
118
|
+
*
|
119
|
+
* The joystick flags field may contain any combination of the bit flags:
|
120
|
+
*
|
121
|
+
* JOYFLAG_DIGITAL
|
122
|
+
* This control is currently providing digital input.
|
123
|
+
*
|
124
|
+
* JOYFLAG_ANALOGUE
|
125
|
+
* This control is currently providing analogue input.
|
126
|
+
*
|
127
|
+
* JOYFLAG_CALIB_DIGITAL
|
128
|
+
* This control will be capable of providing digital input once it has been
|
129
|
+
* calibrated, but is not doing this at the moment.
|
130
|
+
*
|
131
|
+
* JOYFLAG_CALIB_ANALOGUE
|
132
|
+
* This control will be capable of providing analogue input once it has been
|
133
|
+
* calibrated, but is not doing this at the moment.
|
134
|
+
*
|
135
|
+
* JOYFLAG_CALIBRATE
|
136
|
+
* Indicates that this control needs to be calibrated. Many devices require
|
137
|
+
* multiple calibration steps, so you should call the calibrate_joystick
|
138
|
+
* function from a loop until this flag is cleared.
|
139
|
+
*
|
140
|
+
* JOYFLAG_SIGNED
|
141
|
+
* Indicates that the analogue axis position is in signed format, ranging from
|
142
|
+
* -128 to 128. This is the case for all 2d directional controls.
|
143
|
+
*
|
144
|
+
* JOYFLAG_UNSIGNED
|
145
|
+
* Indicates that the analogue axis position is in unsigned format, ranging from
|
146
|
+
* 0 to 255. This is the case for all 1d throttle controls.
|
147
|
+
*
|
148
|
+
* Note for people who spell funny: in case you don't like having to type
|
149
|
+
* "analogue", there are some aliases h that will allow you to write "analog"
|
150
|
+
* instead.
|
151
|
+
*/
|
152
|
+
VALUE a4r_API_joy(VALUE self)
|
153
|
+
{
|
154
|
+
VALUE ret = rb_ary_new2(num_joysticks);
|
155
|
+
long x;
|
156
|
+
for (x = 0; x < num_joysticks; x++)
|
157
|
+
{
|
158
|
+
VALUE obj = Data_Wrap_Struct(cAPI_JOYSTICK_INFO, 0, 0, &(joy[x]));
|
159
|
+
rb_ary_store(ret, x, obj);
|
160
|
+
}
|
161
|
+
|
162
|
+
return ret;
|
163
|
+
}
|
164
|
+
|
165
|
+
/*
|
166
|
+
* call-seq:
|
167
|
+
* calibrate_joystick_name(n) -> str
|
168
|
+
*
|
169
|
+
* Pass the number of the joystick you want to calibrate as the parameter.
|
170
|
+
*
|
171
|
+
* Return value: Returns a text description for the next type of calibration
|
172
|
+
* that will be done on the specified joystick, or nil if no more calibration is
|
173
|
+
* required.
|
174
|
+
*/
|
175
|
+
VALUE a4r_API_calibrate_joystick_name(VALUE self, VALUE n)
|
176
|
+
{
|
177
|
+
const char *s = calibrate_joystick_name(FIX2INT(n));
|
178
|
+
if (s == NULL)
|
179
|
+
return Qnil;
|
180
|
+
else
|
181
|
+
return rb_str_new2(s);
|
182
|
+
}
|
183
|
+
|
184
|
+
/*
|
185
|
+
* call-seq:
|
186
|
+
* calibrate_joystick(n) -> int
|
187
|
+
*
|
188
|
+
* Most joysticks need to be calibrated before they can provide full analogue
|
189
|
+
* input. This function performs the next operation in the calibration series
|
190
|
+
* for the specified stick, assuming that the joystick has been positioned in
|
191
|
+
* the manner described by a previous call to calibrate_joystick_name, returning
|
192
|
+
* zero on success. For example, a simple routine to fully calibrate all the
|
193
|
+
* joysticks might look like:
|
194
|
+
* (0...num_joysticks).each do |i|
|
195
|
+
* while joy[i].flags & JOYFLAG_CALIBRATE != 0
|
196
|
+
* msg = calibrate_joystick_name(i)
|
197
|
+
* textprintf_ex(..., "%s, and press a key\n" % msg)
|
198
|
+
* readkey
|
199
|
+
* if calibrate_joystick(i) != 0
|
200
|
+
* textprintf_ex(..., "oops!\n")
|
201
|
+
* readkey
|
202
|
+
* exit 1
|
203
|
+
* end
|
204
|
+
* end
|
205
|
+
* end
|
206
|
+
*
|
207
|
+
* Return value: Returns zero on success, non-zero if the calibration could not
|
208
|
+
* be performed successfully.
|
209
|
+
*/
|
210
|
+
VALUE a4r_API_calibrate_joystick(VALUE self, VALUE n)
|
211
|
+
{
|
212
|
+
return INT2FIX(calibrate_joystick(FIX2INT(n)));
|
213
|
+
}
|
@@ -0,0 +1,420 @@
|
|
1
|
+
#include "allegro4r.h"
|
2
|
+
|
3
|
+
/*
|
4
|
+
* call-seq:
|
5
|
+
* install_keyboard -> int
|
6
|
+
*
|
7
|
+
* Installs the Allegro keyboard interrupt handler. You must call this before
|
8
|
+
* using any of the keyboard input routines. Once you have set up the Allegro
|
9
|
+
* handler, you can no longer use operating system calls or C library functions
|
10
|
+
* to access the keyboard.
|
11
|
+
*
|
12
|
+
* Note that on some platforms the keyboard won't work unless you have set a
|
13
|
+
* graphics mode, even if this function returns a success value before calling
|
14
|
+
* set_gfx_mode. This can happen in environments with graphic windowed modes,
|
15
|
+
* since Allegro usually reads the keyboard through the graphical window (which
|
16
|
+
* appears after the set_gfx_mode call). Example:
|
17
|
+
* allegro_init
|
18
|
+
* install_timer
|
19
|
+
* install_keyboard
|
20
|
+
* # We are not 100% sure we can read the keyboard yet!
|
21
|
+
* if set_gfx_mode(GFX_AUTODETECT, 640, 480, 0, 0) != 0
|
22
|
+
* abort_on_error("Couldn't set graphic mode!")
|
23
|
+
* end
|
24
|
+
*
|
25
|
+
* # Now we are guaranteed to be able to read the keyboard.
|
26
|
+
* readkey
|
27
|
+
*
|
28
|
+
* Return value: Returns zero on success, or a negative number on failure (but
|
29
|
+
* you may decide not to check the return value as this function is very
|
30
|
+
* unlikely to fail).
|
31
|
+
*/
|
32
|
+
VALUE a4r_API_install_keyboard(VALUE self)
|
33
|
+
{
|
34
|
+
return INT2FIX(install_keyboard());
|
35
|
+
}
|
36
|
+
|
37
|
+
/*
|
38
|
+
* call-seq:
|
39
|
+
* poll_keyboard -> int
|
40
|
+
*
|
41
|
+
* Wherever possible, Allegro will read the keyboard input asynchronously (ie.
|
42
|
+
* from inside an interrupt handler), but on some platforms that may not be
|
43
|
+
* possible, in which case you must call this routine at regular intervals to
|
44
|
+
* update the keyboard state variables.
|
45
|
+
*
|
46
|
+
* To help you test your keyboard polling code even if you are programming on a
|
47
|
+
* platform that doesn't require it, after the first time that you call this
|
48
|
+
* function Allegro will switch into polling mode, so from that point onwards
|
49
|
+
* you will have to call this routine in order to get any keyboard input at all,
|
50
|
+
* regardless of whether the current driver actually needs to be polled or not.
|
51
|
+
*
|
52
|
+
* The keypressed, readkey, and ureadkey functions call poll_keyboard
|
53
|
+
* automatically, so you only need to use this function when accessing the
|
54
|
+
* key array and key_shifts variable.
|
55
|
+
*
|
56
|
+
* Return value: Returns zero on success, or a negative number on failure (ie.
|
57
|
+
* no keyboard driver installed).
|
58
|
+
*/
|
59
|
+
VALUE a4r_API_poll_keyboard(VALUE self)
|
60
|
+
{
|
61
|
+
return INT2FIX(poll_keyboard());
|
62
|
+
}
|
63
|
+
|
64
|
+
/*
|
65
|
+
* call-seq:
|
66
|
+
* key -> ary
|
67
|
+
*
|
68
|
+
* Array of flags indicating the state of each key, ordered by scancode.
|
69
|
+
* Wherever possible these values will be updated asynchronously, but if
|
70
|
+
* keyboard_needs_poll returns true, you must manually call poll_keyboard to
|
71
|
+
* update them with the current input state. The scancodes are defined as a
|
72
|
+
* series of KEY_* constants (and are also listed below). For example, you could
|
73
|
+
* write:
|
74
|
+
* printf("Space is pressed\n") if key[KEY_SPACE]
|
75
|
+
*
|
76
|
+
* Note that the array is supposed to represent which keys are physically held
|
77
|
+
* down and which keys are not, so it is semantically read-only.
|
78
|
+
*
|
79
|
+
* These are the keyboard scancodes:
|
80
|
+
* KEY_A ... KEY_Z,
|
81
|
+
* KEY_0 ... KEY_9,
|
82
|
+
* KEY_0_PAD ... KEY_9_PAD,
|
83
|
+
* KEY_F1 ... KEY_F12,
|
84
|
+
*
|
85
|
+
* KEY_ESC, KEY_TILDE, KEY_MINUS, KEY_EQUALS,
|
86
|
+
* KEY_BACKSPACE, KEY_TAB, KEY_OPENBRACE, KEY_CLOSEBRACE,
|
87
|
+
* KEY_ENTER, KEY_COLON, KEY_QUOTE, KEY_BACKSLASH,
|
88
|
+
* KEY_BACKSLASH2, KEY_COMMA, KEY_STOP, KEY_SLASH,
|
89
|
+
* KEY_SPACE,
|
90
|
+
*
|
91
|
+
* KEY_INSERT, KEY_DEL, KEY_HOME, KEY_END, KEY_PGUP,
|
92
|
+
* KEY_PGDN, KEY_LEFT, KEY_RIGHT, KEY_UP, KEY_DOWN,
|
93
|
+
*
|
94
|
+
* KEY_SLASH_PAD, KEY_ASTERISK, KEY_MINUS_PAD,
|
95
|
+
* KEY_PLUS_PAD, KEY_DEL_PAD, KEY_ENTER_PAD,
|
96
|
+
*
|
97
|
+
* KEY_PRTSCR, KEY_PAUSE,
|
98
|
+
*
|
99
|
+
* KEY_ABNT_C1, KEY_YEN, KEY_KANA, KEY_CONVERT, KEY_NOCONVERT,
|
100
|
+
* KEY_AT, KEY_CIRCUMFLEX, KEY_COLON2, KEY_KANJI,
|
101
|
+
*
|
102
|
+
* KEY_LSHIFT, KEY_RSHIFT,
|
103
|
+
* KEY_LCONTROL, KEY_RCONTROL,
|
104
|
+
* KEY_ALT, KEY_ALTGR,
|
105
|
+
* KEY_LWIN, KEY_RWIN, KEY_MENU,
|
106
|
+
* KEY_SCRLOCK, KEY_NUMLOCK, KEY_CAPSLOCK
|
107
|
+
*
|
108
|
+
* KEY_EQUALS_PAD, KEY_BACKQUOTE, KEY_SEMICOLON, KEY_COMMAND
|
109
|
+
*
|
110
|
+
* Finally, you may notice an 'odd' behaviour of the KEY_PAUSE key. This key
|
111
|
+
* only generates an interrupt when it is pressed, not when it is released. For
|
112
|
+
* this reason, Allegro pretends the pause key is a 'state' key, which is the
|
113
|
+
* only way to make it usable.
|
114
|
+
*/
|
115
|
+
VALUE a4r_API_key(VALUE self)
|
116
|
+
{
|
117
|
+
// TODO: Convert to data struct or cached or hooked variable?
|
118
|
+
// make [] access directly without array conversion?
|
119
|
+
VALUE ret = rb_ary_new2(KEY_MAX);
|
120
|
+
long x;
|
121
|
+
for (x = KEY_A; x <= KEY_MAX; x++)
|
122
|
+
rb_ary_store(ret, x, key[x] == 0 ? Qfalse : Qtrue);
|
123
|
+
return ret;
|
124
|
+
}
|
125
|
+
|
126
|
+
/*
|
127
|
+
* call-seq:
|
128
|
+
* key_shifts -> int
|
129
|
+
*
|
130
|
+
* Bitmask containing the current state of shift/ctrl/alt, the special Windows
|
131
|
+
* keys, and the accent escape characters. Wherever possible this value will be
|
132
|
+
* updated asynchronously, but if keyboard_needs_poll returns true, you must
|
133
|
+
* manually call poll_keyboard to update it with the current input state. This
|
134
|
+
* can contain any of the flags:
|
135
|
+
* KB_SHIFT_FLAG
|
136
|
+
* KB_CTRL_FLAG
|
137
|
+
* KB_ALT_FLAG
|
138
|
+
* KB_LWIN_FLAG
|
139
|
+
* KB_RWIN_FLAG
|
140
|
+
* KB_MENU_FLAG
|
141
|
+
* KB_COMMAND_FLAG
|
142
|
+
* KB_SCROLOCK_FLAG
|
143
|
+
* KB_NUMLOCK_FLAG
|
144
|
+
* KB_CAPSLOCK_FLAG
|
145
|
+
* KB_INALTSEQ_FLAG
|
146
|
+
* KB_ACCENT1_FLAG
|
147
|
+
* KB_ACCENT2_FLAG
|
148
|
+
* KB_ACCENT3_FLAG
|
149
|
+
* KB_ACCENT4_FLAG
|
150
|
+
*
|
151
|
+
* Example:
|
152
|
+
* if key[KEY_W]
|
153
|
+
* if key_shifts & KB_SHIFT_FLAG != 0
|
154
|
+
* # User is pressing shift + W.
|
155
|
+
* else
|
156
|
+
* # Hmmm... lower case W then.
|
157
|
+
* end
|
158
|
+
* end
|
159
|
+
*/
|
160
|
+
VALUE a4r_API_key_shifts(VALUE self)
|
161
|
+
{
|
162
|
+
// TODO: Convert to data struct or cached or hooked variable?
|
163
|
+
return INT2FIX(key_shifts);
|
164
|
+
}
|
165
|
+
|
166
|
+
/*
|
167
|
+
* call-seq:
|
168
|
+
* keypressed -> true or false
|
169
|
+
*
|
170
|
+
* Returns true if there are keypresses waiting in the input buffer. You can use
|
171
|
+
* this to see if the next call to readkey is going to block or to simply wait
|
172
|
+
* for the user to press a key while you still update the screen possibly
|
173
|
+
* drawing some animation. Example:
|
174
|
+
* while !keypressed do
|
175
|
+
* # Show cool animated logo.
|
176
|
+
* end
|
177
|
+
* # So he skipped our title screen.
|
178
|
+
*/
|
179
|
+
VALUE a4r_API_keypressed(VALUE self)
|
180
|
+
{
|
181
|
+
return keypressed() ? Qtrue : Qfalse;
|
182
|
+
}
|
183
|
+
|
184
|
+
/*
|
185
|
+
* call-seq:
|
186
|
+
* readkey -> int
|
187
|
+
*
|
188
|
+
* Returns the next character from the keyboard buffer, in ASCII format. If the
|
189
|
+
* buffer is empty, it waits until a key is pressed. You can see if there are
|
190
|
+
* queued keypresses with keypressed.
|
191
|
+
*
|
192
|
+
* The low byte of the return value contains the ASCII code of the key, and the
|
193
|
+
* high byte the scancode. The scancode remains the same whatever the state of
|
194
|
+
* the shift, ctrl and alt keys, while the ASCII code is affected by shift and
|
195
|
+
* ctrl in the normal way (shift changes case, ctrl+letter gives the position of
|
196
|
+
* that letter in the alphabet, eg. ctrl+A = 1, ctrl+B = 2, etc). Pressing
|
197
|
+
* alt+key returns only the scancode, with a zero ASCII code in the low byte.
|
198
|
+
* For example:
|
199
|
+
* val = readkey
|
200
|
+
* if (val & 0xff) == 'd' # by ASCII code
|
201
|
+
* allegro_message("You pressed 'd'\n")
|
202
|
+
* end
|
203
|
+
*
|
204
|
+
* if (val >> 8) == KEY_SPACE # by scancode
|
205
|
+
* allegro_message("You pressed Space\n");
|
206
|
+
* end
|
207
|
+
*
|
208
|
+
* if (val & 0xff) == 3 # ctrl+letter
|
209
|
+
* allegro_message("You pressed Control+C\n");
|
210
|
+
* end
|
211
|
+
*
|
212
|
+
* if val == (KEY_X << 8) # alt+letter
|
213
|
+
* allegro_message("You pressed Alt+X\n");
|
214
|
+
* end
|
215
|
+
*
|
216
|
+
* This function cannot return character values greater than 255. If you need to
|
217
|
+
* read Unicode input, use ureadkey instead.
|
218
|
+
*/
|
219
|
+
VALUE a4r_API_readkey(VALUE self)
|
220
|
+
{
|
221
|
+
return INT2FIX(readkey());
|
222
|
+
}
|
223
|
+
|
224
|
+
/*
|
225
|
+
* call-seq:
|
226
|
+
* ureadkey(scancode) -> int
|
227
|
+
* ureadkey(scancode) -> [int, int]
|
228
|
+
*
|
229
|
+
* Returns the next character from the keyboard buffer, in Unicode format. If
|
230
|
+
* the buffer is empty, it waits until a key is pressed. You can see if there
|
231
|
+
* are queued keypresses with keypressed. The return value contains the Unicode
|
232
|
+
* value of the key, and if not nil or false, the second return value will be
|
233
|
+
* set to the scancode. Unlike readkey, this function is able to return
|
234
|
+
* character values greater than 255. Example:
|
235
|
+
* val, scancode = ureadkey(true)
|
236
|
+
* if val == 0x00F1
|
237
|
+
* allegro_message("You pressed n with tilde\n")
|
238
|
+
* end
|
239
|
+
*
|
240
|
+
* if val == 0x00DF
|
241
|
+
* allegro_message("You pressed sharp s\n")
|
242
|
+
* end
|
243
|
+
*
|
244
|
+
* You should be able to find Unicode character maps at http://www.unicode.org/.
|
245
|
+
* Remember that on DOS you must specify a custom keyboard map (like those found
|
246
|
+
* in 'keyboard.dat') usually with the help of a configuration file specifying
|
247
|
+
* the language mapping (keyboard variable in system section of 'allegro.cfg'),
|
248
|
+
* or you will get the default US keyboard mapping.
|
249
|
+
*
|
250
|
+
* *** The Ruby method signature differs from the Allegro method signature. The
|
251
|
+
* Allegro signature takes scancode by reference, but the Ruby signature takes a
|
252
|
+
* boolean. If false or nil, the method returns only the read key, otherwise it
|
253
|
+
* returns an array containing the read key and the scancode.
|
254
|
+
*/
|
255
|
+
VALUE a4r_API_ureadkey(VALUE self, VALUE scancode)
|
256
|
+
{
|
257
|
+
int s;
|
258
|
+
int *s_p = NULL;
|
259
|
+
|
260
|
+
if (RTEST(scancode))
|
261
|
+
s_p = &s;
|
262
|
+
int u = ureadkey(s_p);
|
263
|
+
|
264
|
+
VALUE ret;
|
265
|
+
if (s_p)
|
266
|
+
ret = rb_ary_new3(2, INT2FIX(u), INT2FIX(s));
|
267
|
+
else
|
268
|
+
ret = INT2FIX(u);
|
269
|
+
|
270
|
+
return ret;
|
271
|
+
}
|
272
|
+
|
273
|
+
/*
|
274
|
+
* call-seq:
|
275
|
+
* scancode_to_name(scancode) -> str
|
276
|
+
*
|
277
|
+
* This function returns a string containing the name of they key with the given
|
278
|
+
* scancode. This is useful if you e.g. let the user choose a key for some
|
279
|
+
* action, and want to display something more meaningful than just the scancode.
|
280
|
+
* Example:
|
281
|
+
* keyname = scancode_to_name(scancode)
|
282
|
+
* allegro_message("You pressed the %s key." % keyname)
|
283
|
+
*/
|
284
|
+
VALUE a4r_API_scancode_to_name(VALUE self, VALUE scancode)
|
285
|
+
{
|
286
|
+
return rb_str_new2(scancode_to_name(FIX2INT(scancode)));
|
287
|
+
}
|
288
|
+
|
289
|
+
/*
|
290
|
+
* call-seq:
|
291
|
+
* keyboard_callback = proc
|
292
|
+
*
|
293
|
+
* If set, this function is called by the keyboard handler in response to every
|
294
|
+
* keypress. It is passed a copy of the value that is about to be added into the
|
295
|
+
* input buffer, and can either return this value unchanged, return zero to
|
296
|
+
* cause the key to be ignored, or return a modified value to change what
|
297
|
+
* readkey will later return. This routine executes in an interrupt context, so
|
298
|
+
* it must be in locked memory. Example:
|
299
|
+
* def enigma_scrambler(key)
|
300
|
+
* # Add one to both the scancode and ascii values.
|
301
|
+
* return (((key >> 8) + 1) << 8) | ((key & 0xff) + 1)
|
302
|
+
* end
|
303
|
+
*
|
304
|
+
* ...
|
305
|
+
*
|
306
|
+
* install_timer
|
307
|
+
* LOCK_FUNCTION(:enigma_scrambler)
|
308
|
+
* install_keyboard
|
309
|
+
* keyboard_callback = self.method(:enigma_scrambler)
|
310
|
+
*
|
311
|
+
* Note that this callback will be ignored if you also set the unicode keyboard
|
312
|
+
* callback.
|
313
|
+
*/
|
314
|
+
VALUE a4r_API_keyboard_callback_set(VALUE self, VALUE proc)
|
315
|
+
{
|
316
|
+
// TODO: Validate proc and maybe check for 0 in the keyboard_callback_method?
|
317
|
+
// TODO: hooked variable?
|
318
|
+
keyboard_callback_proc = proc;
|
319
|
+
if (proc == Qnil)
|
320
|
+
keyboard_callback = NULL;
|
321
|
+
else
|
322
|
+
keyboard_callback = keyboard_callback_method;
|
323
|
+
return proc;
|
324
|
+
}
|
325
|
+
|
326
|
+
/*
|
327
|
+
* call-seq:
|
328
|
+
* keyboard_lowlevel_callback = proc
|
329
|
+
*
|
330
|
+
* If set, this function is called by the keyboard handler in response to every
|
331
|
+
* keyboard event, both presses (including keyboard repeat rate) and releases.
|
332
|
+
* It will be passed a raw keyboard scancode byte (scancodes are 7 bits long),
|
333
|
+
* with the top bit (8th bit) clear if the key has been pressed or set if it was
|
334
|
+
* released. This routine executes in an interrupt context, so it must be in
|
335
|
+
* locked memory. Example:
|
336
|
+
*
|
337
|
+
* def keypress_watcher(scancode)
|
338
|
+
* if (scancode & 0x80) != 0
|
339
|
+
* key_up = 1
|
340
|
+
* else
|
341
|
+
* key_down = 1
|
342
|
+
* end
|
343
|
+
* end
|
344
|
+
*
|
345
|
+
* ...
|
346
|
+
*
|
347
|
+
* install_timer
|
348
|
+
* LOCK_FUNCTION(silence_g_key)
|
349
|
+
* LOCK_VARIABLE(key_down)
|
350
|
+
* LOCK_VARIABLE(key_up)
|
351
|
+
* install_keyboard
|
352
|
+
* keyboard_lowlevel_callback = self.method(:keypress_watcher)
|
353
|
+
* # Disable keyboard repeat to get typewriter effect.
|
354
|
+
* set_keyboard_rate(0, 0)
|
355
|
+
*
|
356
|
+
* ...
|
357
|
+
*
|
358
|
+
* while (game_loop)
|
359
|
+
* if (key_down == 1)
|
360
|
+
* key_down = 0
|
361
|
+
* # Play sample of typewriter key press.
|
362
|
+
* end
|
363
|
+
* if (key_up == 1)
|
364
|
+
* key_up = 0;
|
365
|
+
* # Play sample of typewriter key release.
|
366
|
+
* end
|
367
|
+
* end
|
368
|
+
*/
|
369
|
+
VALUE a4r_API_keyboard_lowlevel_callback_set(VALUE self, VALUE proc)
|
370
|
+
{
|
371
|
+
// TODO: Validate proc and maybe check for 0 in the keyboard_lowlevel_callback_method?
|
372
|
+
// TODO: hooked variable?
|
373
|
+
keyboard_lowlevel_callback_proc = proc;
|
374
|
+
if (proc == Qnil)
|
375
|
+
keyboard_lowlevel_callback = NULL;
|
376
|
+
else
|
377
|
+
keyboard_lowlevel_callback = keyboard_lowlevel_callback_method;
|
378
|
+
return proc;
|
379
|
+
}
|
380
|
+
|
381
|
+
/*
|
382
|
+
* call-seq:
|
383
|
+
* clear_keybuf -> nil
|
384
|
+
*
|
385
|
+
* Empties the keyboard buffer. Usually you want to use this in your program
|
386
|
+
* before reading keys to avoid previously buffered keys to be returned by calls
|
387
|
+
* to readkey or ureadkey.
|
388
|
+
*/
|
389
|
+
VALUE a4r_API_clear_keybuf(VALUE self)
|
390
|
+
{
|
391
|
+
clear_keybuf();
|
392
|
+
return Qnil;
|
393
|
+
}
|
394
|
+
|
395
|
+
/******************************************************************************/
|
396
|
+
// Predefined keyboard callback routines
|
397
|
+
/*
|
398
|
+
* TODO: The keyboard callback routines are not working as expected. I thought
|
399
|
+
* I might be able to fake things by setting a global variable to a proc, which
|
400
|
+
* then would get called by the below methods. Unfortunately, even with no code
|
401
|
+
* in the proc, it crashes ruby. I'm assuming that since these methods run
|
402
|
+
* in an interrupt context, there is a clash between the Ruby code and the
|
403
|
+
* lowlevel code.
|
404
|
+
*/
|
405
|
+
|
406
|
+
VALUE keyboard_callback_proc;
|
407
|
+
VALUE keyboard_lowlevel_callback_proc;
|
408
|
+
|
409
|
+
int keyboard_callback_method(int key)
|
410
|
+
{
|
411
|
+
return FIX2INT(rb_funcall(keyboard_callback_proc, CALL_ID, 1, INT2FIX(key)));
|
412
|
+
}
|
413
|
+
END_OF_FUNCTION(keyboard_callback_method)
|
414
|
+
|
415
|
+
void keyboard_lowlevel_callback_method(int scancode)
|
416
|
+
{
|
417
|
+
rb_funcall(keyboard_lowlevel_callback_proc, CALL_ID, 1, INT2FIX(scancode));
|
418
|
+
}
|
419
|
+
END_OF_FUNCTION(keyboard_lowlevel_callback_method)
|
420
|
+
|