| line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
|
1
|
|
|
|
|
|
|
=head1 NAME |
|
2
|
|
|
|
|
|
|
|
|
3
|
|
|
|
|
|
|
Term::Graille::IO |
|
4
|
|
|
|
|
|
|
|
|
5
|
|
|
|
|
|
|
Allows user interaction in Graille Applications (or perhaps on any |
|
6
|
|
|
|
|
|
|
pterminal application). Depends on Term::ReadKey and Time::HiRes; |
|
7
|
|
|
|
|
|
|
When integrated with Term::Graille::Menu allows a modal drop down menu |
|
8
|
|
|
|
|
|
|
that |
|
9
|
|
|
|
|
|
|
|
|
10
|
|
|
|
|
|
|
=head1 SYNOPSIS |
|
11
|
|
|
|
|
|
|
|
|
12
|
|
|
|
|
|
|
my $io=Term::Graille::IO->new(); |
|
13
|
|
|
|
|
|
|
$io->addAction( # add action for key press |
|
14
|
|
|
|
|
|
|
"Am", # Am is returned for up arrow |
|
15
|
|
|
|
|
|
|
{note=>"up arrow:cursor up ", # For drawing a menu |
|
16
|
|
|
|
|
|
|
proc=>sub{my $self.@args)=@_ ...} # the action |
|
17
|
|
|
|
|
|
|
} ); |
|
18
|
|
|
|
|
|
|
$io->run($io,@args); # start trapping keypresses |
|
19
|
|
|
|
|
|
|
... |
|
20
|
|
|
|
|
|
|
$io->stop(); # stop |
|
21
|
|
|
|
|
|
|
|
|
22
|
|
|
|
|
|
|
=cut |
|
23
|
|
|
|
|
|
|
|
|
24
|
|
|
|
|
|
|
package Term::Graille::IO; |
|
25
|
|
|
|
|
|
|
|
|
26
|
|
|
|
|
|
|
our $VERSION=0.09; |
|
27
|
|
|
|
|
|
|
|
|
28
|
1
|
|
|
1
|
|
821
|
use strict; use warnings; |
|
|
1
|
|
|
1
|
|
2
|
|
|
|
1
|
|
|
|
|
24
|
|
|
|
1
|
|
|
|
|
4
|
|
|
|
1
|
|
|
|
|
2
|
|
|
|
1
|
|
|
|
|
25
|
|
|
29
|
1
|
|
|
1
|
|
4
|
use Time::HiRes ("sleep"); # allow fractional sleeps |
|
|
1
|
|
|
|
|
2
|
|
|
|
1
|
|
|
|
|
4
|
|
|
30
|
1
|
|
|
1
|
|
71
|
use utf8; # allow utf characters in print |
|
|
1
|
|
|
|
|
2
|
|
|
|
1
|
|
|
|
|
3
|
|
|
31
|
|
|
|
|
|
|
binmode STDOUT, ":utf8"; |
|
32
|
1
|
|
|
1
|
|
427
|
use Term::ReadKey; # allow reading from keyboard |
|
|
1
|
|
|
|
|
2007
|
|
|
|
1
|
|
|
|
|
61
|
|
|
33
|
1
|
|
|
1
|
|
6
|
use Term::Graille qw/colour paint printAt cursorAt clearScreen border/; |
|
|
1
|
|
|
|
|
2
|
|
|
|
1
|
|
|
|
|
627
|
|
|
34
|
|
|
|
|
|
|
|
|
35
|
|
|
|
|
|
|
=head1 FUNCTIONS |
|
36
|
|
|
|
|
|
|
|
|
37
|
|
|
|
|
|
|
=cut |
|
38
|
|
|
|
|
|
|
|
|
39
|
|
|
|
|
|
|
=head3 Cnew(%params)> |
|
40
|
|
|
|
|
|
|
|
|
41
|
|
|
|
|
|
|
Creates a new IO object for user interaction. |
|
42
|
|
|
|
|
|
|
Three modes are available; C, means the key presses are captured |
|
43
|
|
|
|
|
|
|
and not echoed, C |
|
44
|
|
|
|
|
|
|
using C<$io-EaddMenu($menu), and C when the key presses are |
|
45
|
|
|
|
|
|
|
read normally |
|
46
|
|
|
|
|
|
|
|
|
47
|
|
|
|
|
|
|
=cut |
|
48
|
|
|
|
|
|
|
|
|
49
|
|
|
|
|
|
|
sub new{ |
|
50
|
0
|
|
|
0
|
1
|
|
my $class = shift; # |
|
51
|
0
|
|
|
|
|
|
my $self={}; |
|
52
|
0
|
|
|
|
|
|
$self->{actions}={}; |
|
53
|
0
|
|
|
|
|
|
$self->{refreshRate}=20; |
|
54
|
0
|
|
|
|
|
|
$self->{key}=""; |
|
55
|
0
|
|
|
|
|
|
$self->{mode}="free";# one of qw/free menu normal/ |
|
56
|
0
|
|
|
|
|
|
($self->{terminalWidth},$self->{terminalHeight},$self->{terminalXPixels},$self->{terminalYPixels})=GetTerminalSize; |
|
57
|
0
|
|
|
|
|
|
bless $self,$class; |
|
58
|
0
|
|
|
|
|
|
return $self; |
|
59
|
|
|
|
|
|
|
} |
|
60
|
|
|
|
|
|
|
|
|
61
|
|
|
|
|
|
|
=head3 CaddMenu($menu,$trigger)> |
|
62
|
|
|
|
|
|
|
|
|
63
|
|
|
|
|
|
|
Uses a topbar dropdown menu of class Term::Graille::Menu. If C<$trigger> is specified |
|
64
|
|
|
|
|
|
|
that activates or deactivates the menu; if not specified the 'm' key activates the menu. |
|
65
|
|
|
|
|
|
|
|
|
66
|
|
|
|
|
|
|
=cut |
|
67
|
|
|
|
|
|
|
|
|
68
|
|
|
|
|
|
|
sub addMenu{ |
|
69
|
0
|
|
|
0
|
1
|
|
my ($self,$menu,$trigger)=@_; |
|
70
|
0
|
|
0
|
|
|
|
$self->{menuTrigger}=$trigger//"m"; |
|
71
|
0
|
|
|
|
|
|
$self->{menu}=$menu; |
|
72
|
|
|
|
|
|
|
} |
|
73
|
|
|
|
|
|
|
|
|
74
|
|
|
|
|
|
|
|
|
75
|
|
|
|
|
|
|
=head3 CaddAction($menu,$key,$actionData)> |
|
76
|
|
|
|
|
|
|
|
|
77
|
|
|
|
|
|
|
Determines what happens when a key is pressed in C mode. Functions in the |
|
78
|
|
|
|
|
|
|
users scripts have to be "fully qualified" e.g. C<&main::function()> |
|
79
|
|
|
|
|
|
|
|
|
80
|
|
|
|
|
|
|
$io->addAction("s",{note=>"s key saves sprite",proc=>sub{ |
|
81
|
|
|
|
|
|
|
my ($self,$canvas,$sprite,$cursor)=@_; # these are the objects passed as parameters |
|
82
|
|
|
|
|
|
|
&main::saveSprite($sprite); |
|
83
|
|
|
|
|
|
|
&main::flashCursor($sprite,$cursor); |
|
84
|
|
|
|
|
|
|
&main::restoreIO();},} ); |
|
85
|
|
|
|
|
|
|
|
|
86
|
|
|
|
|
|
|
|
|
87
|
|
|
|
|
|
|
=cut |
|
88
|
|
|
|
|
|
|
|
|
89
|
|
|
|
|
|
|
sub addAction{ |
|
90
|
0
|
|
|
0
|
1
|
|
my ($self,$key, $actionData)=@_; |
|
91
|
0
|
|
|
|
|
|
my %args=%$actionData; |
|
92
|
0
|
|
|
|
|
|
foreach my $k (keys %args){ |
|
93
|
0
|
|
|
|
|
|
$self->{actions}->{$key}->{$k}=$args{$k}; |
|
94
|
|
|
|
|
|
|
} |
|
95
|
|
|
|
|
|
|
} |
|
96
|
|
|
|
|
|
|
|
|
97
|
|
|
|
|
|
|
=head3 Crun($io,@objects)> |
|
98
|
|
|
|
|
|
|
|
|
99
|
|
|
|
|
|
|
Iniiating the capture of the key presses may trigger actions. These |
|
100
|
|
|
|
|
|
|
actions may need parameters including the $io object itself, it is useful |
|
101
|
|
|
|
|
|
|
to select all possible objects that may need to be passed to the anonymous |
|
102
|
|
|
|
|
|
|
subroutines added by C above. |
|
103
|
|
|
|
|
|
|
|
|
104
|
|
|
|
|
|
|
=cut |
|
105
|
|
|
|
|
|
|
|
|
106
|
|
|
|
|
|
|
sub run{ |
|
107
|
0
|
|
|
0
|
1
|
|
my ($self,@objects)=@_; |
|
108
|
0
|
|
|
|
|
|
ReadMode 'cbreak'; |
|
109
|
0
|
|
|
|
|
|
my $n=0; my @modifiers=(); |
|
|
0
|
|
|
|
|
|
|
|
110
|
0
|
|
|
|
|
|
while(1){ |
|
111
|
0
|
|
|
|
|
|
sleep 1/$self->{refreshRate}; |
|
112
|
0
|
|
|
|
|
|
$self->{key} = ReadKey(-1); # -1 means non-blocking read |
|
113
|
0
|
0
|
|
|
|
|
if ($self->{key}){ |
|
114
|
0
|
|
|
|
|
|
my $OrdKey = ord($self->{key}); |
|
115
|
0
|
0
|
|
|
|
|
if ($OrdKey ==27){push @modifiers, $OrdKey;} |
|
|
0
|
|
|
|
|
|
|
|
116
|
|
|
|
|
|
|
else{ |
|
117
|
0
|
0
|
|
|
|
|
my $pressed=chr($OrdKey).(@modifiers?"m":""); |
|
118
|
0
|
0
|
|
|
|
|
$pressed="enter" if ($OrdKey==10); |
|
119
|
0
|
|
|
|
|
|
printAt (20,60,"key pressed=$OrdKey $pressed "); |
|
120
|
0
|
0
|
|
|
|
|
if ($self->{mode} eq "free"){ |
|
|
|
0
|
|
|
|
|
|
|
121
|
0
|
0
|
0
|
|
|
|
if (defined $self->{actions}->{$pressed}->{proc}){ |
|
|
|
0
|
|
|
|
|
|
|
122
|
0
|
|
|
|
|
|
$self->{actions}->{$pressed}->{proc}->(@objects) |
|
123
|
|
|
|
|
|
|
} |
|
124
|
|
|
|
|
|
|
elsif((exists $self->{menuTrigger})&&($pressed eq $self->{menuTrigger})){ |
|
125
|
0
|
|
|
|
|
|
$self->startMenu(); |
|
126
|
|
|
|
|
|
|
} |
|
127
|
|
|
|
|
|
|
} |
|
128
|
|
|
|
|
|
|
elsif ($self->{mode} eq "menu"){ |
|
129
|
0
|
0
|
|
|
|
|
if ($pressed eq"Am"){ #up arrow |
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
130
|
|
|
|
|
|
|
$self->{menu}->upArrow() |
|
131
|
0
|
|
|
|
|
|
} |
|
132
|
|
|
|
|
|
|
elsif ($pressed eq"Bm"){ #down arrow |
|
133
|
|
|
|
|
|
|
$self->{menu}->downArrow() |
|
134
|
0
|
|
|
|
|
|
} |
|
135
|
|
|
|
|
|
|
elsif ($pressed eq"Cm"){ #left arrow |
|
136
|
|
|
|
|
|
|
$self->{menu}->leftArrow() |
|
137
|
0
|
|
|
|
|
|
} |
|
138
|
|
|
|
|
|
|
elsif ($pressed eq"Dm"){ #right arrow |
|
139
|
|
|
|
|
|
|
$self->{menu}->rightArrow() |
|
140
|
0
|
|
|
|
|
|
} |
|
141
|
|
|
|
|
|
|
elsif ($pressed eq"enter"){ #enter key |
|
142
|
|
|
|
|
|
|
$self->{menu}->openItem() |
|
143
|
0
|
|
|
|
|
|
} |
|
144
|
|
|
|
|
|
|
elsif ($pressed eq $self->{menuTrigger}){ #right arrow |
|
145
|
|
|
|
|
|
|
$self->{menu}->closeMenu() |
|
146
|
0
|
|
|
|
|
|
} |
|
147
|
|
|
|
|
|
|
} |
|
148
|
|
|
|
|
|
|
} |
|
149
|
|
|
|
|
|
|
} |
|
150
|
|
|
|
|
|
|
else { |
|
151
|
0
|
|
|
|
|
|
@modifiers=(); |
|
152
|
|
|
|
|
|
|
} |
|
153
|
0
|
0
|
|
|
|
|
$self->{actions}->{update}->(@objects) if exists $self->{actions}->{update}; |
|
154
|
0
|
|
|
|
|
|
$n++; |
|
155
|
|
|
|
|
|
|
} |
|
156
|
0
|
|
|
|
|
|
ReadMode 'normal'; |
|
157
|
|
|
|
|
|
|
} |
|
158
|
|
|
|
|
|
|
|
|
159
|
|
|
|
|
|
|
|
|
160
|
|
|
|
|
|
|
=head3 CstartMenu()> |
|
161
|
|
|
|
|
|
|
|
|
162
|
|
|
|
|
|
|
Starts a menu as described in Term::Graille::Menu. The $io object enters a "menu" mode |
|
163
|
|
|
|
|
|
|
when Arrow, Enter and the Trigger key (see above) are passed to the Menu object |
|
164
|
|
|
|
|
|
|
|
|
165
|
|
|
|
|
|
|
=cut |
|
166
|
|
|
|
|
|
|
|
|
167
|
|
|
|
|
|
|
sub startMenu{ |
|
168
|
0
|
|
|
0
|
1
|
|
my $self=shift; |
|
169
|
0
|
0
|
|
|
|
|
if (exists $self->{menu}){ |
|
170
|
0
|
|
|
|
|
|
$self->{mode}="menu"; |
|
171
|
0
|
|
|
|
|
|
$self->{menu}->drawMenu(); |
|
172
|
|
|
|
|
|
|
} |
|
173
|
|
|
|
|
|
|
} |
|
174
|
|
|
|
|
|
|
|
|
175
|
|
|
|
|
|
|
=head3 CstopMenu()> |
|
176
|
|
|
|
|
|
|
|
|
177
|
|
|
|
|
|
|
Stops menu and returns to C mode |
|
178
|
|
|
|
|
|
|
|
|
179
|
|
|
|
|
|
|
=cut |
|
180
|
|
|
|
|
|
|
|
|
181
|
|
|
|
|
|
|
sub stopMenu{ |
|
182
|
0
|
|
|
0
|
1
|
|
my $self=shift; |
|
183
|
0
|
|
|
|
|
|
$self->{mode}="free"; |
|
184
|
|
|
|
|
|
|
} |
|
185
|
|
|
|
|
|
|
|
|
186
|
|
|
|
|
|
|
=head3 Cstop()> |
|
187
|
|
|
|
|
|
|
|
|
188
|
|
|
|
|
|
|
stops capturing key presses and enters normal mode. Useful for exeample, when the |
|
189
|
|
|
|
|
|
|
user needs to enter data |
|
190
|
|
|
|
|
|
|
|
|
191
|
|
|
|
|
|
|
=cut |
|
192
|
|
|
|
|
|
|
|
|
193
|
|
|
|
|
|
|
|
|
194
|
|
|
|
|
|
|
sub stop{ |
|
195
|
0
|
|
|
0
|
1
|
|
my $self=shift; |
|
196
|
0
|
|
|
|
|
|
ReadMode 'normal'; |
|
197
|
|
|
|
|
|
|
} |