Win32.pm.svn-base
上传用户:market2
上传日期:2018-11-18
资源大小:18786k
文件大小:15k
源码类别:

外挂编程

开发平台:

Windows_Unix

  1. #########################################################################
  2. #  OpenKore - Interface::Console::Win32
  3. #
  4. #  Copyright (c) 2004 OpenKore development team 
  5. #
  6. #  This program is free software; you can redistribute it and/or modify
  7. #  it under the terms of the GNU General Public License as published by
  8. #  the Free Software Foundation; either version 2 of the License, or
  9. #  (at your option) any later version.
  10. #
  11. #  This program is distributed in the hope that it will be useful,
  12. #  but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. #  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14. #  GNU General Public License for more details.
  15. #
  16. #
  17. #  $Revision$
  18. #  $Id$
  19. #
  20. #########################################################################
  21. ##
  22. # MODULE DESCRIPTION: 
  23. #
  24. # Support for asyncronous input on MS Windows computers
  25. package Interface::Console::Win32;
  26. use strict;
  27. use warnings;
  28. die "W32 only, this module should never be called on any other OSn"
  29. unless ($^O eq 'MSWin32' || $^O eq 'cygwin');
  30. use Carp;
  31. use Time::HiRes qw/time sleep/;
  32. use Text::Wrap;
  33. use Win32::Console;
  34. use Utils::Win32;
  35. use encoding 'utf8';
  36. use Encode;
  37. use I18N qw(stringToBytes);
  38. use Translation qw(T);
  39. use Globals;
  40. use Settings qw(%sys);
  41. use base qw(Interface::Console);
  42. our %fgcolors;
  43. our %bgcolors;
  44. sub new {
  45. my $class = shift;
  46. my $self = {
  47. input_list => [],
  48. last_line_end => 1,
  49. input_lines => [],
  50. input_offset => 0,
  51. input_part => '',
  52. };
  53. bless $self, $class;
  54. $self->{out_con} = new Win32::Console(STD_OUTPUT_HANDLE()) 
  55. or die "Could not init output Console: $!n";
  56. $self->{in_con} = new Win32::Console(STD_INPUT_HANDLE()) 
  57. or die "Could not init input Console: $!n";
  58. $self->setWinDim();
  59. $self->{out_con}->Cursor(0, $self->{in_line});
  60. $self->{codepage} = $self->{out_con}->OutputCP;
  61. return $self;
  62. }
  63. sub DESTROY {
  64. my $self = shift;
  65. $self->color('reset');
  66. }
  67. sub setWinDim {
  68. my $self = shift;
  69. my($wLeft, $wTop, $wRight, $wBottom) = $self->{out_con}->Window() or die "Can't find initial dimentions for the output windown";
  70. my($bCol, $bRow) = $self->{out_con}->Size() or die "Can't find dimentions for the output buffern";
  71. $self->{out_con}->Window(1, $wLeft, $bRow - $wBottom - 1, $wRight, $bRow - 1);# or die "Can't set dimentions for the output windown";
  72. @{$self}{qw(left out_top right in_line)} = $self->{out_con}->Window() or die "Can't find new dimentions for the output windown";
  73. $self->{out_bot} = $self->{in_line} - 1; #one line above the input line
  74. $self->{out_line} = $self->{in_line};
  75. $self->{out_col} = $self->{in_pos} = $self->{left};
  76. }
  77. sub getInput {
  78. # return undef unless ($enabled);
  79. my $self = shift;
  80. my $timeout = shift;
  81. $self->readEvents();
  82. my $msg;
  83. if ($timeout < 0) {
  84. until (defined $msg) {
  85. $self->readEvents();
  86. sleep 0.01;
  87. if (@{$self->{input_lines}}) {
  88. $msg = shift @{$self->{input_lines}};
  89. }
  90. }
  91. } elsif ($timeout > 0) {
  92. my $end = time + $timeout;
  93. until ($end < time || defined $msg) {
  94. $self->readEvents();
  95. sleep 0.01;
  96. if (@{$self->{input_lines}}) {
  97. $msg = shift @{$self->{input_lines}};
  98. }
  99. }
  100. } else {
  101. if (@{$self->{input_lines}}) {
  102. $msg = shift @{$self->{input_lines}};
  103. }
  104. }
  105. undef $msg if (defined $msg && $msg eq '');
  106. return $msg;
  107. }
  108. ##
  109. # readEvents()
  110. #
  111. # reads low level events from the input console, for key presses it
  112. # updates the console input variables
  113. #
  114. # note: most of this is commented out, it need a cordinated output
  115. # system to use the separate input line (meaning output does not
  116. # over write your input line)
  117. sub readEvents {
  118. my $self = shift;
  119. # local($|) = 1;
  120. while ($self->{in_con}->GetEvents()) {
  121. my @event = $self->{in_con}->Input();
  122. if (@event && $event[5] < 0) {
  123. # Special characters are returned as unsigned integer
  124. # (dunno why). Fix this.
  125. $event[5] = 256 + $event[5];
  126. }
  127. if (@event && $event[0] == 1 && $event[1] == 0 && $event[3] == 18) {
  128. # Alt was released and there's an ASCII code. This is
  129. # a special character. Change @events as if a normal key
  130. # was pressed.
  131. $event[1] = 1;
  132. }
  133. if (@event && $event[0] == 1 && $event[1] == 1) {
  134. ##Ctrl+U (erases entire line)
  135. if ($event[6] == 40 && $event[5] == 21) {
  136. $self->{in_pos} = 0;
  137. $self->{out_con}->Scroll(
  138. 0, $self->{in_line}, $self->{right}, $self->{in_line},
  139. -$self->{right}, $self->{in_line}, ord(' '), $main::ATTR_NORMAL, 
  140. 0, $self->{in_line}, $self->{right}, $self->{in_line},
  141. );
  142. $self->{out_con}->Cursor(0, $self->{in_line});
  143. $self->{input_part} = '';
  144. ##Backspace
  145. } elsif ($event[5] == 8) {
  146. $self->{in_pos}-- if $self->{in_pos} > 0;
  147. substr($self->{input_part}, $self->{in_pos}, 1, '');
  148. $self->{out_con}->Scroll(
  149. $self->{in_pos}, $self->{in_line}, $self->{right}, $self->{in_line},
  150. $self->{in_pos}-1, $self->{in_line}, ord(' '), $main::ATTR_NORMAL, 
  151. $self->{in_pos}, $self->{in_line}, $self->{right}, $self->{in_line},
  152. );
  153. $self->{out_con}->Cursor($self->{in_pos}, $self->{in_line});
  154. # print "10 10";
  155. ##Enter
  156. } elsif ($event[5] == 13) {
  157. my $ret = $self->{out_con}->Scroll(
  158. $self->{left}, 0, $self->{right}, $self->{in_line},
  159. 0, -1, ord(' '), $main::ATTR_NORMAL, 
  160. $self->{left}, 0, $self->{right}, $self->{in_line}
  161. );
  162. $self->{out_con}->Cursor(0, $self->{in_line});
  163. $self->{in_pos} = 0;
  164. $self->{input_list}[0] = $self->{input_part};
  165. if ($self->{input_part} ne ""
  166.  && ( @{$self->{input_list}} < 2 || $self->{input_list}[1] ne $self->{input_part} )) {
  167. unshift(@{ $self->{input_list} }, "");
  168. }
  169. push @{ $self->{input_lines} }, $self->{input_part};
  170. $self->{out_col} = 0;
  171. $self->{input_offset} = 0;
  172. $self->{input_part} = '';
  173. # print "n";
  174. #Other ASCII (+ ISO Latin-*)
  175. } elsif ($event[5] >= 32 && $event[5] != 127 && $event[5] <= 255) {
  176. my $char;
  177. eval {
  178. $char = Encode::decode("cp" . $self->{codepage}, chr($event[5]));
  179. };
  180. if ($@ =~ /^Unknown encoding/s) {
  181. $self->errorDialog(T("Your Windows's default language is not supported by OpenKore.n" .
  182. "Please go to 'Start->Control Panel->Regional and language options' and set " .
  183. "the Windows default language to English."));
  184. exit 1;
  185. } elsif ($@) {
  186. die $@;
  187. }
  188. if ($self->{in_pos} < length($self->{input_part})) {
  189. $self->{out_con}->Scroll(
  190. $self->{in_pos}, $self->{in_line}, $self->{right}, $self->{in_line},
  191. $self->{in_pos}+1, $self->{in_line}, ord(' '), $main::ATTR_NORMAL, 
  192. $self->{in_pos}, $self->{in_line}, $self->{right}, $self->{in_line},
  193. );
  194. } elsif ($self->{in_pos} > length($self->{input_part})) {
  195. $self->{in_pos} = length($self->{input_part});
  196. }
  197. $self->{out_con}->Cursor($self->{in_pos}, $self->{in_line});
  198. Utils::Win32::printConsole($char);
  199. substr($self->{input_part}, $self->{in_pos}, 0, $char) if ($self->{in_pos} <= length($self->{input_part}));
  200. $self->{in_pos}++;
  201. # } elsif ($event[3] == 33) {
  202. # __PACKAGE__->writeOutput("pgupn");
  203. # } elsif ($event[3] == 34) {
  204. # __PACKAGE__->writeOutput("pgdnn");
  205. ##End
  206. } elsif ($event[3] == 35) {
  207. $self->{out_con}->Cursor($self->{in_pos} = length($self->{input_part}), $self->{in_line});
  208. ##Home
  209. } elsif ($event[3] == 36) {
  210. $self->{out_con}->Cursor($self->{in_pos} = 0, $self->{in_line});
  211. ##Left Arrow
  212. } elsif ($event[3] == 37) {
  213. $self->{in_pos}--;
  214. $self->{out_con}->Cursor($self->{in_pos}, $self->{in_line});
  215. ##Up Arrow
  216. } elsif ($event[3] == 38) {
  217. unless ($self->{input_offset}) {
  218. $self->{input_list}[$self->{input_offset}] = $self->{input_part};
  219. }
  220. $self->{input_offset}++;
  221. $self->{input_offset} = $#{$self->{input_list}} if ($self->{input_offset} > $#{$self->{input_list}});
  222. #$self->{input_offset} -= $#{ $self->{input_list} } + 1 while $self->{input_offset} > $#{ $self->{input_list} };
  223. $self->{out_con}->Cursor(0, $self->{in_line});
  224. $self->{out_con}->Write(' ' x length($self->{input_part}));
  225. $self->{out_con}->Cursor(0, $self->{in_line});
  226. $self->{input_part} = $self->{input_list}[$self->{input_offset}];
  227. Utils::Win32::printConsole($self->{input_part});
  228. $self->{in_pos} = length($self->{input_part});
  229. ##Right Arrow
  230. } elsif ($event[3] == 39) {
  231. if ($self->{in_pos} + 1 <= length($self->{input_part})) {
  232. $self->{in_pos}++;
  233. $self->{out_con}->Cursor($self->{in_pos}, $self->{in_line});
  234. }
  235. ##Down Arrow
  236. } elsif ($event[3] == 40) {
  237. unless ($self->{input_offset}) {
  238. $self->{input_list}[$self->{input_offset}] = $self->{input_part};
  239. }
  240. $self->{input_offset}--;
  241. $self->{input_offset} = 0 if ($self->{input_offset} < 0);
  242. #$self->{input_offset} += $#{ $self->{input_list} } + 1 while $self->{input_offset} < 0;
  243. $self->{out_con}->Cursor(0, $self->{in_line});
  244. $self->{out_con}->Write(' ' x length($self->{input_part}));
  245. $self->{out_con}->Cursor(0, $self->{in_line});
  246. $self->{input_part} = $self->{input_list}[$self->{input_offset}];
  247. Utils::Win32::printConsole($self->{input_part});
  248. $self->{in_pos} = length($self->{input_part});
  249. ##Insert
  250. # } elsif ($event[3] == 45) {
  251. # __PACKAGE__->writeOutput("insertn");
  252. ##Delete
  253. } elsif ($event[3] == 46) {
  254. substr($self->{input_part}, $self->{in_pos}, 1, '');
  255. $self->{out_con}->Scroll(
  256. $self->{in_pos}, $self->{in_line}, $self->{right}, $self->{in_line},
  257. $self->{in_pos} - 1, $self->{in_line}, ord(' '), $main::ATTR_NORMAL, 
  258. $self->{in_pos}, $self->{in_line}, $self->{right}, $self->{in_line},
  259. );
  260. ##F1-F12
  261. # } elsif ($event[3] >= 112 && $event[3] <= 123) {
  262. # __PACKAGE__->writeOutput("F" . ($event[3] - 111) . "n");
  263. # } else {
  264. # __PACKAGE__->writeOutput(join '-', @event, "n");
  265. }
  266. # } else {
  267. # __PACKAGE__->writeOutput(join '-', @event, "n");
  268. }
  269. }
  270. }
  271. sub writeOutput {
  272. my ($self, $type, $message, $domain) = @_;
  273. #wrap the text
  274. local($Text::Wrap::columns) = $self->{right} - $self->{left} + 1;
  275. my ($endspace) = $message =~ /(s*)$/; #Save trailing whitespace: wrap kills spaces near wraps, especialy at the end of stings, so "n" becomes "", not what we want
  276. $message = wrap('', '', $message);
  277. $message =~ s/s*$/$endspace/; #restore the whitespace
  278. my $lines = $message =~ s/r?n/n/g; #fastest? way to count newlines
  279. #this paragraph is all about handleing lines that don't end in a newline. I have no clue how it works, even though I wrote it, but it does. =)
  280. $lines++ if (!$lines && $self->{last_line_end});
  281. if ($lines && !$self->{last_line_end}) {
  282. $lines--;
  283. $self->{out_line}--;
  284. } elsif (!$self->{last_line_end}) {
  285. $self->{out_line}--;
  286. }
  287. $self->{last_line_end} = ($message =~ /n$/) ? 1 : 0;
  288. my $ret = $self->{out_con}->Scroll(
  289. $self->{left}, 0, $self->{right}, $self->{out_bot},
  290. 0, 0-$lines, ord(' '), $main::ATTR_NORMAL, 
  291. $self->{left}, 0, $self->{right}, $self->{out_bot}
  292. );
  293. my ($ocx, $ocy) = $self->{out_con}->Cursor();
  294. $self->{out_con}->Cursor($self->{out_col}, $self->{out_line} - $lines);
  295. $self->setColor($type, $domain);
  296. #$self->{out_con}->Write($message);
  297. Utils::Win32::printConsole($message);
  298. $self->color('reset');
  299. ($self->{out_col}, $self->{out_line}) = $self->{out_con}->Cursor();
  300. $self->{out_line} -= $self->{last_line_end} - 1;
  301. $self->{out_con}->Cursor($ocx, $ocy);
  302. }
  303. sub setColor {
  304. return if (!$consoleColors{''}{'useColors'});
  305. my $self = shift;
  306. my ($type, $domain) = @_;
  307. my $color;
  308. $color = $consoleColors{$type}{$domain} if (defined $type && defined $domain && defined $consoleColors{$type});
  309. $color = $consoleColors{$type}{'default'} if (!defined $color && defined $type);
  310. $self->color($color) if (defined $color);
  311. }
  312. sub color {
  313. my $self = shift;
  314. my $color = shift;
  315. my ($bgcolor, $fgcode, $bgcode);
  316. $color =~ s//(.*)//;
  317. $bgcolor = $1 || "default";
  318. $fgcode = $fgcolors{$color} || $fgcolors{'default'};
  319. $bgcode = $bgcolors{$bgcolor} || $bgcolors{'default'};
  320. $self->{out_con}->Attr($fgcode | $bgcode);
  321. }
  322. sub title {
  323. my ($self, $title) = @_;
  324. if (defined $title) {
  325. if (!defined $self->{currentTitle} || $self->{currentTitle} ne $title) {
  326. Utils::Win32::setConsoleTitle($title);
  327. $self->{currentTitle} = $title;
  328. }
  329. } else {
  330. return $self->{out_con}->Title();
  331. }
  332. }
  333. # IRGB
  334. # 8421
  335. # Deal with ActivePerl version incompatibilities
  336. if (defined($main::ATTR_NORMAL)) {
  337. %fgcolors = (
  338. 'reset' => $main::ATTR_NORMAL,
  339. 'default' => $main::ATTR_NORMAL,
  340. 'black' => $main::FG_BLACK,
  341. 'darkgray' => FOREGROUND_INTENSITY(),
  342. 'darkgrey' => FOREGROUND_INTENSITY(),
  343. 'darkred' => $main::FG_RED,
  344. 'red' => $main::FG_LIGHTRED,
  345. 'darkgreen' => $main::FG_GREEN,
  346. 'green' => $main::FG_LIGHTGREEN,
  347. 'brown' => $main::FG_BROWN,
  348. 'yellow' => $main::FG_YELLOW,
  349. 'darkblue' => $main::FG_BLUE,
  350. 'blue' => $main::FG_LIGHTBLUE,
  351. 'darkmagenta' => $main::FG_MAGENTA,
  352. 'magenta' => $main::FG_LIGHTMAGENTA,
  353. 'darkcyan' => $main::FG_CYAN,
  354. 'cyan' => $main::FG_LIGHTCYAN,
  355. 'gray' => $main::FG_GRAY,
  356. 'grey' => $main::FG_GRAY,
  357. 'white' => $main::FG_WHITE,
  358. );
  359. } else {
  360. %fgcolors = (
  361. 'reset' => $Win32::Console::ATTR_NORMAL,
  362. 'default' => $Win32::Console::ATTR_NORMAL,
  363. 'black' => $Win32::Console::FG_BLACK,
  364. 'darkgray' => FOREGROUND_INTENSITY(),
  365. 'darkgrey' => FOREGROUND_INTENSITY(),
  366. 'darkred' => $Win32::Console::FG_RED,
  367. 'red' => $Win32::Console::FG_LIGHTRED,
  368. 'darkgreen' => $Win32::Console::FG_GREEN,
  369. 'green' => $Win32::Console::FG_LIGHTGREEN,
  370. 'brown' => $Win32::Console::FG_BROWN,
  371. 'yellow' => $Win32::Console::FG_YELLOW,
  372. 'darkblue' => $Win32::Console::FG_BLUE,
  373. 'blue' => $Win32::Console::FG_LIGHTBLUE,
  374. 'darkmagenta' => $Win32::Console::FG_MAGENTA,
  375. 'magenta' => $Win32::Console::FG_LIGHTMAGENTA,
  376. 'darkcyan' => $Win32::Console::FG_CYAN,
  377. 'cyan' => $Win32::Console::FG_LIGHTCYAN,
  378. 'gray' => $Win32::Console::FG_GRAY,
  379. 'grey' => $Win32::Console::FG_GRAY,
  380. 'white' => $Win32::Console::FG_WHITE,
  381. );
  382. }
  383. #   I  R  G  B
  384. # 128 64 32 16
  385. if (defined($main::BG_BLACK)) {
  386. %bgcolors = (
  387. '' => $main::BG_BLACK,
  388. 'default' => $main::BG_BLACK,
  389. 'black' => $main::BG_BLACK,
  390. 'darkgray' => BACKGROUND_INTENSITY(),
  391. 'darkgrey' => BACKGROUND_INTENSITY(),
  392. 'darkred' => $main::BG_RED,
  393. 'red' => $main::BG_LIGHTRED,
  394. 'darkgreen' => $main::BG_GREEN,
  395. 'green' => $main::BG_LIGHTGREEN,
  396. 'brown' => $main::BG_BROWN,
  397. 'yellow' => $main::BG_YELLOW,
  398. 'darkblue' => $main::BG_BLUE,
  399. 'blue' => $main::BG_LIGHTBLUE,
  400. 'darkmagenta' => $main::BG_MAGENTA,
  401. 'magenta' => $main::BG_LIGHTMAGENTA,
  402. 'darkcyan' => $main::BG_CYAN,
  403. 'cyan' => $main::BG_LIGHTCYAN,
  404. 'gray' => $main::BG_GRAY,
  405. 'grey' => $main::BG_GRAY,
  406. 'white' => $main::BG_WHITE,
  407. );
  408. } else {
  409. %bgcolors = (
  410. '' => $Win32::Console::BG_BLACK,
  411. 'default' => $Win32::Console::BG_BLACK,
  412. 'black' => $Win32::Console::BG_BLACK,
  413. 'darkgray' => BACKGROUND_INTENSITY(),
  414. 'darkgrey' => BACKGROUND_INTENSITY(),
  415. 'darkred' => $Win32::Console::BG_RED,
  416. 'red' => $Win32::Console::BG_LIGHTRED,
  417. 'darkgreen' => $Win32::Console::BG_GREEN,
  418. 'green' => $Win32::Console::BG_LIGHTGREEN,
  419. 'brown' => $Win32::Console::BG_BROWN,
  420. 'yellow' => $Win32::Console::BG_YELLOW,
  421. 'darkblue' => $Win32::Console::BG_BLUE,
  422. 'blue' => $Win32::Console::BG_LIGHTBLUE,
  423. 'darkmagenta' => $Win32::Console::BG_MAGENTA,
  424. 'magenta' => $Win32::Console::BG_LIGHTMAGENTA,
  425. 'darkcyan' => $Win32::Console::BG_CYAN,
  426. 'cyan' => $Win32::Console::BG_LIGHTCYAN,
  427. 'gray' => $Win32::Console::BG_GRAY,
  428. 'grey' => $Win32::Console::BG_GRAY,
  429. 'white' => $Win32::Console::BG_WHITE,
  430. );
  431. }
  432. 1 #end of module