File Coverage

blib/lib/Games/Roguelike/Console/Win32.pm
Criterion Covered Total %
statement 4 6 66.6
branch n/a
condition n/a
subroutine 2 2 100.0
pod n/a
total 6 8 75.0


line stmt bran cond sub pod time code
1 5     5   34 use strict;
  5         7  
  5         248  
2             package Games::Roguelike::Console::Win32;
3            
4             #### refer to Games::Roguelike::Console for docs ###
5            
6 5     5   2180 use Win32::Console;
  0            
  0            
7             use Carp;
8            
9             use base 'Games::Roguelike::Console';
10            
11             our $VERSION = '0.4.' . [qw$Revision: 247 $]->[1];
12            
13             sub new {
14             my $pkg = shift;
15             croak "usage: Games::Roguelike::Console::Win32->new()" unless $pkg;
16            
17             my $self = bless {}, $pkg;
18             $self->init(@_);
19             return $self;
20             }
21            
22             my $CON;
23            
24             #todo: figure out how to free/alloc/resize
25             sub init {
26             my $self = shift;
27             my %opts = @_;
28            
29             $self->SUPER::init(%opts);
30            
31             $self->{conin} = Win32::Console->new(STD_INPUT_HANDLE);
32            
33             # turns off echo
34             $self->{conin}->Mode(ENABLE_PROCESSED_INPUT);
35            
36             $self->{buf} = Win32::Console->new(GENERIC_READ|GENERIC_WRITE);
37             $self->{buf}->Cls();
38             $self->{buf}->Cursor(-1,-1,-1,0);
39            
40             $self->{con} = Win32::Console->new(STD_OUTPUT_HANDLE);
41             $self->{cur} = 0;
42            
43             ($self->{winx},$self->{winy}) = $self->{con}->MaxWindow();
44             $self->{con}->Size($self->{winx}, $self->{winy});
45             $self->{buf}->Size($self->{winx}, $self->{winy});
46            
47             $self->{rx} = 0 if !defined $self->{rx};
48            
49             if (!$opts{noinit}) {
50             $self->{con}->Cursor(-1,-1,-1,0);
51             $self->{con}->Display();
52             $self->{con}->Cls();
53             }
54            
55             $CON = $self->{con} unless $CON;
56            
57             $SIG{INT} = \&sig_int_handler;
58             $SIG{__DIE__} = \&sig_die_handler;
59             }
60            
61             sub DESTROY {
62             $_[0]->{con}->Cls() if $_[0]->{con};
63             }
64            
65             sub sig_int_handler {
66             $CON->Cls();
67             exit;
68             }
69            
70             sub sig_die_handler {
71             die @_ if $^S;
72             $CON->Cls();
73             die @_;
74             }
75            
76             sub nativecolor {
77             my ($self, $fg, $bg, $fgb, $bgb) = @_;
78            
79             # $fg = 'white' if $fg eq '';
80             # $bg = 'black' if $bg eq '';
81            
82             $fg = 'light' . $fg if $fgb;
83            
84             $fg = 'gray' if $fg eq 'lightblack';
85             $bg = 'gray' if $bg eq 'lightblack';
86             $fg = 'brown' if $fg eq 'yellow';
87             $bg = 'brown' if $bg eq 'yellow';
88             $fg = 'yellow' if $fg eq 'lightyellow';
89             $bg = 'yellow' if $bg eq 'lightyellow';
90             $fg = 'lightgray' if $fg eq 'white';
91             $fg = 'white' if $fg eq 'lightwhite';
92             $bg = 'white' if $bg eq 'lightwhite';
93            
94             no strict 'refs';
95             my $color = ${"FG_" . uc($fg)} | ${"BG_" . uc($bg)} ;
96            
97             use strict 'refs';
98            
99             $color = $self->defcolor if !$color;
100             return $color;
101             }
102            
103             sub attron {
104             my $self = shift;
105             my ($attr) = @_;
106             $self->{cattr} = $self->parsecolor($attr);
107             }
108            
109             sub attroff {
110             my $self = shift;
111             $self->{cattr} = $self->defcolor;
112             }
113            
114             sub addstr {
115             my $self = shift;
116             my $str = pop @_;
117            
118             if (@_== 0) {
119             if ($self->{cx}+length($str) > ($self->{winx}+1)) {
120             $str = substr(0, ($self->{cx}+length($str)) - ($self->{winx}));
121             }
122             return if length($str) == 0;
123             $self->{buf}->WriteChar($str, $self->{cx}, $self->{cy});
124             $self->{buf}->WriteAttr(chr($self->{cattr}) x length($str), $self->{cx}, $self->{cy});
125             #$self->invalidate($self->{cx}, $self->{cy}, $self->{cx} + length($str), $self->{cy});
126             $self->{cx} += length($str);
127             } elsif (@_==2) {
128             my ($y, $x) = @_;
129             if ($x+length($str) > ($self->{winx}+1)) {
130             $str = substr(0, ($x+length($str)) - ($self->{winx}));
131             }
132             return if length($str) == 0;
133             $self->{buf}->WriteChar($str, $x, $y);
134             $self->{buf}->WriteAttr(chr($self->{cattr}) x length($str), $x, $y);
135             #$self->invalidate($x, $y, $x+length($str), $y);
136             $self->{cx} = $x + length($str);
137             $self->{cy} = $y;
138             }
139             if ($self->{cursor}) {
140             $self->{con}->Cursor($self->{cx},$self->{cy},-1,1);
141             }
142             }
143            
144             sub tagstr {
145             my $self = shift;
146             my ($y, $x, $str);
147             if (@_ == 1) {
148             ($y, $x, $str) = ($self->{cy}, $self->{cx}, @_);
149             } else {
150             ($y, $x, $str) = @_;
151             }
152             my $attr = chr($self->defcolor);
153             my $r = $x;
154             my $c;
155             for (my $i = 0; $i < length($str); ++$i) {
156             $c = substr($str,$i,1);
157             if ($c eq '<') {
158             substr($str,$i) =~ s/<([^>]*)>//;
159             if ($1 eq 'gt') {
160             $c = '>';
161             --$i;
162             } elsif ($1 eq 'lt') {
163             $c = '<';
164             --$i;
165             } else {
166             $attr = chr($self->parsecolor($1));
167             $c = substr($str,$i,1);
168             }
169             }
170             if ($c eq "\r") {
171             next;
172             }
173             if ($c eq "\n") {
174             $r = $self->{rx};
175             $y++;
176             next;
177             }
178            
179             $self->{buf}->WriteChar($c, $r, $y);
180             $self->{buf}->WriteAttr($attr, $r, $y);
181             ++$r;
182             }
183             #$self->invalidate($x, $y, $x+$r, $y);
184             $self->{cy}=$y;
185             $self->{cx}=$x+$r;
186             }
187            
188             sub refresh {
189             my $self = shift;
190             #my $rect = $self->{buf}->ReadRect($self->{invl}, $self->{invt}, $self->{invr}, $self->{invb});
191             #$self->{con}->WriteRect($rect, $self->{invl}, $self->{invt}, $self->{invr}, $self->{invb});
192             my $rect = $self->{buf}->ReadRect(0, 0, $self->{winx}, $self->{winy});
193             $self->{con}->WriteRect($rect, 0, 0, $self->{winx}, $self->{winy});
194             # $self->{invl} = $self->{winx}+1;
195             # $self->{invt} = $self->{winy}+1;
196             # $self->{invr} = $self->{invb} = -1;
197             }
198            
199             sub move {
200             my $self = shift;
201             my ($y, $x) = @_;
202             $self->{cx}=$x;
203             $self->{cy}=$y;
204             if ($self->{cursor}) {
205             $self->{con}->Cursor($x,$y,-1,1);
206             }
207             }
208            
209             sub cursor {
210             my $self = shift;
211             if ($self->{cursor} != shift) {
212             $self->{cursor} = !$self->{cursor};
213             $self->{con}->Cursor($self->{cx},$self->{cy},-1,$self->{cursor});
214             }
215             }
216            
217             sub printw {
218             my $self = shift;
219             $self->addstr(sprintf shift, @_)
220             }
221            
222             sub addch {
223             my $self = shift;
224             $self->addstr(@_);
225             }
226            
227             sub invalidate {
228             my $self = shift;
229             my ($l, $t, $r, $b) = @_;
230             $r = 0 if ($r < 0);
231             $t = 0 if ($t < 0);
232             $b = $self->{winy} if ($b > $self->{winy});
233             $r = $self->{winx} if ($r > $self->{winx});
234            
235             if ($r < $l) {
236             my $m = $r;
237             $r = $l;
238             $l = $m;
239             }
240             if ($b < $t) {
241             my $m = $t;
242             $b = $t;
243             $t = $m;
244             }
245             $self->{invl} = $l if $l < $self->{invl};
246             $self->{invr} = $r if $r > $self->{invr};
247             $self->{invt} = $t if $t < $self->{invt};
248             $self->{invb} = $b if $b > $self->{invb};
249             }
250            
251             # read 1 event, translate and return translated value
252             sub getev {
253             my $self = shift;
254             my ($type, @e)= $self->{conin}->Input();
255             if ($type == 1) {
256             my ($kd, $rep, $vk, $vs, $c, $ctrl) = @e;
257             next if $kd;
258             return 'DOWN' if $vk == 0x28;
259             return 'RIGHT' if $vk == 0x27;
260             return 'LEFT' if $vk == 0x25;
261             return 'UP' if $vk == 0x26;
262             return 'ESC' if $c == 27;
263             return chr($c) if $c > 0;
264             }
265             return undef;
266             }
267            
268             # todo, support win32 arrow/function/control keys - ReadKey ignores them
269             sub getch {
270             my $self = shift;
271             # readkey breaks on carraige returns
272             while (1) {
273             my $c = $self->getev();
274             return $c if defined $c;
275             };
276             }
277            
278             sub nbgetch {
279             my $self = shift;
280             # readkey breaks on carraige returns
281             while ($self->{conin}->GetEvents() > 0) {
282             my $c = $self->getev();
283             return $c if defined $c;
284             };
285             return undef;
286             }
287            
288             1;