-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathgrace.pl
More file actions
309 lines (252 loc) · 6.4 KB
/
grace.pl
File metadata and controls
309 lines (252 loc) · 6.4 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
#!/usr/bin/perl
=pod
=head1 NAME
grace.pl - A program for a two year old
=head1 SYNOPSIS
grace.pl [seq]
=head1 DESCRIPTION
The I<grace.pl> has two modes of operation. In normal
mode, pressing a key will display a given image and
pay a sound.
In sequential mode the system displays a sequence
of images and sounds.
To get out of the program type "exit" in order.
=head1 INPUT FILES
In sequential mode, the file I<seq_key.txt> contains a list
of sounds to play in sequence. Actually each line of this file
is a system command to play a sound (or multiple sounds).
The file I<seq_image.txt> contains a line of images (one per line)
to display in order.
In normal mode the file I<key.txt> contains a key to sound playing
command mapping. The key is the first item on the line, the command
taking up the rest of the line.
The I<image.txt> file contains a set of key to image mappings. Again,
the key is the first field, the image the second.
=head1 AUTHOR
Steve Oualline, E<lt>oualline@www.oualline.comE<gt>.
=head1 COPYRIGHT
Copyright 2005 Steve Oualline.
This program is distributed under the GPL.
=cut
#
# Display a big window and let Grace type on it.
#
# When a key is pressed, display a picture and play
# a sound.
#
# The file cmd.txt contains the sound playing
# command.
#
# The format of this file is:
#
# key <tab> command
#
#
use strict;
use warnings;
use POSIX qw(:sys_wait_h);
use Tk;
use Tk::JPEG;
my %sound_list = (); # Key -> Command mapping
my %image_list = (); # List of images to display
# List of sound commands in sequential mode
my @seq_sound_list;
# List of images in sequential mode
my @seq_image_list;
my $bg_pid = 0; # Pid of the background process
my $canvas; # Canvas for drawing
my $canvas_image; # Image on the canvas
my $mw; # Main window
my $mode = "???"; # The mode (seq, key, debug)
#
# Called when a child dies.
# Tell the system that nothing
# is running in background
#
sub child_handler()
{
my $wait_pid = waitpid(-1, WNOHANG);
if ($wait_pid == $bg_pid) {
$bg_pid = 0;
}
}
# What we have to type to get out of here
my @exit = qw(e x i t);
my $stage = 0; # How many letters of "exit" typed
my $image_count = -1; # Current image in seq mode
my $sound_count = -1; # Current sound in seq mode
####################################################
# get_image($key) -- Get the image to display
#
# Make sure it's the right one for the mode
####################################################
sub get_image($)
{
my $key = shift; # Key that was just pressed
if ($mode eq "seq") {
++$image_count;
if ($image_count > $#seq_image_list) {
$image_count = 0;
}
return ($seq_image_list[$image_count]);
}
return ($image_list{$key});
}
####################################################
# get_sound($key) -- Get the next sound to play
####################################################
sub get_sound($)
{
my $key = shift; # Key that was just pressed
if ($mode eq "seq") {
++$sound_count;
if ($sound_count > $#seq_sound_list) {
$sound_count = 0;
}
return ($seq_sound_list[$sound_count]);
}
return ($image_list{$key});
}
####################################################
# Handle keypresses
####################################################
sub key_handler($) {
# Widget generating the event
my ($widget) = @_;
# The event causing the problem
my $event = $widget->XEvent;
# The key causing the event
my $key = $event->K();
if ($exit[$stage] eq $key) {
$stage++;
}
if ($stage > $#exit) {
exit (0);
}
# Lock system until bg sound finishes
if ($bg_pid != 0) {
return;
}
my $image_name = get_image($key);
my $sound = get_sound($key);
#
# Display Image
#
if (defined($image_name)) {
# Define an image
my $image =
$mw->Photo(-file => $image_name);
if (defined($canvas_image)) {
$canvas->delete($canvas_image);
}
$canvas_image = $canvas->createImage(0, 0,
-anchor => "nw",
-image => $image);
}
else
{
print NO_KEY "$key -- no image\n";
}
#
# Execute command
#
if (defined($sound)) {
if ($bg_pid == 0) {
$bg_pid = fork();
if ($bg_pid == 0) {
exec($sound);
}
}
} else {
print NO_KEY "$key -- no sound\n";
}
}
###################################################
# read_list(file)
#
# Read a list from a file and return the
# hash containing the key value pairs.
####################################################
sub read_list($)
{
my $file = shift; # File we are reading
my %result; # Result of the read
open (IN_FILE, "<$file") or
die("Could not open $file");
while (<IN_FILE>) {
chomp($_);
my ($key, $value) = split /\t/, $_;
$result{$key} = $value;
}
close (IN_FILE);
return (%result);
}
#####################################################
# read_seq_list($file) -- Read a sequential list
####################################################
sub read_seq_list($)
{
my $file = shift; # File to read
my @list; # Result
open IN_FILE, "<$file" or
die("Could not open $file");
@list = <IN_FILE>;
chomp(@list);
close(IN_FILE);
return (@list);
}
#===================================================
$mode = "key";
if ($#ARGV > -1) {
if ($ARGV[0] eq "seq") {
$mode = "seq";
} else {
$mode = "debug";
}
}
$SIG{CHLD} = \&child_handler;
if ($mode eq "seq") {
# The list of commands
@seq_sound_list = read_seq_list("seq_key.txt");
@seq_image_list =
read_seq_list("seq_image.txt");
} else {
# The list of commands
%sound_list = read_list("key.txt");
%image_list = read_list("image.txt");
}
# Open the key error file
open NO_KEY, ">no_key.txt" or
die("Could not open no_key.txt");
$mw = MainWindow->new(-title => "Graces Program");
# Big main window
my $big = $mw->Toplevel();
#
# Don't display borders
# (And don't work if commented in)
#
#if ($#ARGV == -1) {
# $big->overrideredirect(1);
#}
$mw->bind("<KeyPress>" => \&key_handler);
$big->bind("<KeyPress>" => \&key_handler);
# Width and height of the screen
my $width = $mw->screenwidth();
my $height = $mw->screenheight();
if ($mode eq "debug") {
$width = 800;
$height = 600;
}
$canvas = $big->Canvas(-background => "Yellow",
-width => $width,
-height => $height
)->pack(
-expand => 1,
-fill => "both"
);
$mw->iconify();
if ($mode ne "debug") {
$big->bind("<Map>" =>
sub {$big->grabGlobal();});
}
MainLoop();