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.
Files changed (59) hide show
  1. data/History.txt +4 -0
  2. data/Manifest.txt +58 -0
  3. data/README.txt +94 -0
  4. data/examples/exdbuf.rb +58 -0
  5. data/examples/exfixed.rb +46 -0
  6. data/examples/exflame.rb +200 -0
  7. data/examples/exflip.rb +87 -0
  8. data/examples/exfont.rb +70 -0
  9. data/examples/exhello.rb +46 -0
  10. data/examples/exjoy.rb +206 -0
  11. data/examples/exkeys.rb +216 -0
  12. data/examples/exmem.rb +50 -0
  13. data/examples/exmidi.rb +97 -0
  14. data/examples/exmouse.rb +149 -0
  15. data/examples/expal.rb +70 -0
  16. data/examples/expat.rb +62 -0
  17. data/examples/exsample.rb +89 -0
  18. data/examples/extimer.rb +84 -0
  19. data/examples/unifont.dat +0 -0
  20. data/ext/a4r_API_BITMAP.c +27 -0
  21. data/ext/a4r_API_DIGI_DRIVER.c +14 -0
  22. data/ext/a4r_API_GFX_DRIVER.c +14 -0
  23. data/ext/a4r_API_JOYSTICK_AXIS_INFO.c +53 -0
  24. data/ext/a4r_API_JOYSTICK_BUTTON_INFO.c +27 -0
  25. data/ext/a4r_API_JOYSTICK_DRIVER.c +14 -0
  26. data/ext/a4r_API_JOYSTICK_INFO.c +84 -0
  27. data/ext/a4r_API_JOYSTICK_STICK_INFO.c +62 -0
  28. data/ext/a4r_API_KEYBOARD_DRIVER.c +14 -0
  29. data/ext/a4r_API_MIDI_DRIVER.c +14 -0
  30. data/ext/a4r_API_MOUSE_DRIVER.c +14 -0
  31. data/ext/a4r_API_PALETTE.c +63 -0
  32. data/ext/a4r_API_RGB.c +118 -0
  33. data/ext/a4r_API_TIMER_DRIVER.c +14 -0
  34. data/ext/a4r_API_bitmap_objects.c +310 -0
  35. data/ext/a4r_API_blitting_and_sprites.c +86 -0
  36. data/ext/a4r_API_digital_sample_routines.c +83 -0
  37. data/ext/a4r_API_direct_access_to_video_memory.c +102 -0
  38. data/ext/a4r_API_drawing_primitives.c +114 -0
  39. data/ext/a4r_API_file_and_compression_routines.c +27 -0
  40. data/ext/a4r_API_fixed_point_math_routines.c +98 -0
  41. data/ext/a4r_API_fonts.c +147 -0
  42. data/ext/a4r_API_graphics_modes.c +155 -0
  43. data/ext/a4r_API_joystick_routines.c +213 -0
  44. data/ext/a4r_API_keyboard_routines.c +420 -0
  45. data/ext/a4r_API_misc.c +133 -0
  46. data/ext/a4r_API_mouse_routines.c +220 -0
  47. data/ext/a4r_API_music_routines_midi.c +147 -0
  48. data/ext/a4r_API_palette_routines.c +112 -0
  49. data/ext/a4r_API_sound_init_routines.c +29 -0
  50. data/ext/a4r_API_text_output.c +178 -0
  51. data/ext/a4r_API_timer_routines.c +250 -0
  52. data/ext/a4r_API_transparency_and_patterned_drawing.c +87 -0
  53. data/ext/a4r_API_truecolor_pixel_formats.c +44 -0
  54. data/ext/a4r_API_unicode_routines.c +53 -0
  55. data/ext/a4r_API_using_allegro.c +98 -0
  56. data/ext/allegro4r.c +866 -0
  57. data/ext/allegro4r.h +311 -0
  58. data/ext/extconf.rb +11 -0
  59. 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
+