Hoa central
Cursor.php
Go to the documentation of this file.
1 <?php
2 
37 namespace Hoa\Console;
38 
47 class Cursor
48 {
66  public static function move($steps, $repeat = 1)
67  {
68  if (1 > $repeat) {
69  return;
70  } elseif (1 === $repeat) {
71  $handle = explode(' ', $steps);
72  } else {
73  $handle = explode(' ', $steps, 1);
74  }
75 
76  $tput = Console::getTput();
77 
78  foreach ($handle as $step) {
79  switch ($step) {
80  case 'u':
81  case 'up':
82  case '↑':
83  echo str_replace(
84  '%p1%d',
85  $repeat,
86  $tput->get('parm_up_cursor')
87  );
88 
89  break;
90 
91  case 'U':
92  case 'UP':
93  static::moveTo(null, 1);
94 
95  break;
96 
97  case 'r':
98  case 'right':
99  case '→':
100  echo str_replace(
101  '%p1%d',
102  $repeat,
103  $tput->get('parm_right_cursor')
104  );
105 
106  break;
107 
108  case 'R':
109  case 'RIGHT':
110  static::moveTo(9999);
111 
112  break;
113 
114  case 'd':
115  case 'down':
116  case '↓':
117  echo str_replace(
118  '%p1%d',
119  $repeat,
120  $tput->get('parm_down_cursor')
121  );
122 
123  break;
124 
125  case 'D':
126  case 'DOWN':
127  static::moveTo(null, 9999);
128 
129  break;
130 
131  case 'l':
132  case 'left':
133  case '←':
134  echo str_replace(
135  '%p1%d',
136  $repeat,
137  $tput->get('parm_left_cursor')
138  );
139 
140  break;
141 
142  case 'L':
143  case 'LEFT':
144  static::moveTo(1);
145 
146  break;
147  }
148  }
149 
150  return;
151  }
152 
161  public static function moveTo($x = null, $y = null)
162  {
163  if (null === $x || null === $y) {
164  $position = static::getPosition();
165 
166  if (null === $x) {
167  $x = $position['x'];
168  }
169 
170  if (null === $y) {
171  $y = $position['y'];
172  }
173  }
174 
175  echo str_replace(
176  ['%i%p1%d', '%p2%d'],
177  [$y, $x],
178  Console::getTput()->get('cursor_address')
179  );
180 
181  return;
182  }
183 
189  public static function getPosition()
190  {
191  $tput = Console::getTput();
192  $user7 = $tput->get('user7');
193 
194  if (null === $user7) {
195  return [
196  'x' => 0,
197  'y' => 0
198  ];
199  }
200 
201  echo $user7;
202 
203  // Read $tput->get('user6').
204  fread(STDIN, 2); // skip \033 and [.
205 
206  $x = null;
207  $y = null;
208  $handle = &$y;
209 
210  do {
211  $char = fread(STDIN, 1);
212 
213  switch ($char) {
214  case ';':
215  $handle = &$x;
216 
217  break;
218 
219  case 'R':
220  break 2;
221 
222  default:
223  $handle .= $char;
224  }
225  } while (true);
226 
227  return [
228  'x' => (int) $x,
229  'y' => (int) $y
230  ];
231  }
232 
238  public static function save()
239  {
240  echo Console::getTput()->get('save_cursor');
241 
242  return;
243  }
244 
250  public static function restore()
251  {
252  echo Console::getTput()->get('restore_cursor');
253 
254  return;
255  }
256 
271  public static function clear($parts = 'all')
272  {
273  $tput = Console::getTput();
274 
275  foreach (explode(' ', $parts) as $part) {
276  switch ($part) {
277  case 'a':
278  case 'all':
279  case '↕':
280  echo $tput->get('clear_screen');
281  static::moveTo(1, 1);
282 
283  break;
284 
285  case 'u':
286  case 'up':
287  case '↑':
288  echo "\033[1J";
289 
290  break;
291 
292  case 'r':
293  case 'right':
294  case '→':
295  echo $tput->get('clr_eol');
296 
297  break;
298 
299  case 'd':
300  case 'down':
301  case '↓':
302  echo $tput->get('clr_eos');
303 
304  break;
305 
306  case 'l':
307  case 'left':
308  case '←':
309  echo $tput->get('clr_bol');
310 
311  break;
312 
313  case 'line':
314  case '↔':
315  echo "\r" . $tput->get('clr_eol');
316 
317  break;
318  }
319  }
320 
321  return;
322  }
323 
329  public static function hide()
330  {
331  echo Console::getTput()->get('cursor_invisible');
332 
333  return;
334  }
335 
341  public static function show()
342  {
343  echo Console::getTput()->get('cursor_visible');
344 
345  return;
346  }
347 
379  public static function colorize($attributes)
380  {
381  static $_rgbTo256 = null;
382 
383  if (null === $_rgbTo256) {
384  $_rgbTo256 = [
385  '000000', '800000', '008000', '808000', '000080', '800080',
386  '008080', 'c0c0c0', '808080', 'ff0000', '00ff00', 'ffff00',
387  '0000ff', 'ff00ff', '00ffff', 'ffffff', '000000', '00005f',
388  '000087', '0000af', '0000d7', '0000ff', '005f00', '005f5f',
389  '005f87', '005faf', '005fd7', '005fff', '008700', '00875f',
390  '008787', '0087af', '0087d7', '0087ff', '00af00', '00af5f',
391  '00af87', '00afaf', '00afd7', '00afff', '00d700', '00d75f',
392  '00d787', '00d7af', '00d7d7', '00d7ff', '00ff00', '00ff5f',
393  '00ff87', '00ffaf', '00ffd7', '00ffff', '5f0000', '5f005f',
394  '5f0087', '5f00af', '5f00d7', '5f00ff', '5f5f00', '5f5f5f',
395  '5f5f87', '5f5faf', '5f5fd7', '5f5fff', '5f8700', '5f875f',
396  '5f8787', '5f87af', '5f87d7', '5f87ff', '5faf00', '5faf5f',
397  '5faf87', '5fafaf', '5fafd7', '5fafff', '5fd700', '5fd75f',
398  '5fd787', '5fd7af', '5fd7d7', '5fd7ff', '5fff00', '5fff5f',
399  '5fff87', '5fffaf', '5fffd7', '5fffff', '870000', '87005f',
400  '870087', '8700af', '8700d7', '8700ff', '875f00', '875f5f',
401  '875f87', '875faf', '875fd7', '875fff', '878700', '87875f',
402  '878787', '8787af', '8787d7', '8787ff', '87af00', '87af5f',
403  '87af87', '87afaf', '87afd7', '87afff', '87d700', '87d75f',
404  '87d787', '87d7af', '87d7d7', '87d7ff', '87ff00', '87ff5f',
405  '87ff87', '87ffaf', '87ffd7', '87ffff', 'af0000', 'af005f',
406  'af0087', 'af00af', 'af00d7', 'af00ff', 'af5f00', 'af5f5f',
407  'af5f87', 'af5faf', 'af5fd7', 'af5fff', 'af8700', 'af875f',
408  'af8787', 'af87af', 'af87d7', 'af87ff', 'afaf00', 'afaf5f',
409  'afaf87', 'afafaf', 'afafd7', 'afafff', 'afd700', 'afd75f',
410  'afd787', 'afd7af', 'afd7d7', 'afd7ff', 'afff00', 'afff5f',
411  'afff87', 'afffaf', 'afffd7', 'afffff', 'd70000', 'd7005f',
412  'd70087', 'd700af', 'd700d7', 'd700ff', 'd75f00', 'd75f5f',
413  'd75f87', 'd75faf', 'd75fd7', 'd75fff', 'd78700', 'd7875f',
414  'd78787', 'd787af', 'd787d7', 'd787ff', 'd7af00', 'd7af5f',
415  'd7af87', 'd7afaf', 'd7afd7', 'd7afff', 'd7d700', 'd7d75f',
416  'd7d787', 'd7d7af', 'd7d7d7', 'd7d7ff', 'd7ff00', 'd7ff5f',
417  'd7ff87', 'd7ffaf', 'd7ffd7', 'd7ffff', 'ff0000', 'ff005f',
418  'ff0087', 'ff00af', 'ff00d7', 'ff00ff', 'ff5f00', 'ff5f5f',
419  'ff5f87', 'ff5faf', 'ff5fd7', 'ff5fff', 'ff8700', 'ff875f',
420  'ff8787', 'ff87af', 'ff87d7', 'ff87ff', 'ffaf00', 'ffaf5f',
421  'ffaf87', 'ffafaf', 'ffafd7', 'ffafff', 'ffd700', 'ffd75f',
422  'ffd787', 'ffd7af', 'ffd7d7', 'ffd7ff', 'ffff00', 'ffff5f',
423  'ffff87', 'ffffaf', 'ffffd7', 'ffffff', '080808', '121212',
424  '1c1c1c', '262626', '303030', '3a3a3a', '444444', '4e4e4e',
425  '585858', '606060', '666666', '767676', '808080', '8a8a8a',
426  '949494', '9e9e9e', 'a8a8a8', 'b2b2b2', 'bcbcbc', 'c6c6c6',
427  'd0d0d0', 'dadada', 'e4e4e4', 'eeeeee'
428  ];
429  }
430 
431  $tput = Console::getTput();
432 
433  if (1 >= $tput->count('max_colors')) {
434  return;
435  }
436 
437  $handle = [];
438 
439  foreach (explode(' ', $attributes) as $attribute) {
440  switch ($attribute) {
441  case 'n':
442  case 'normal':
443  $handle[] = 0;
444 
445  break;
446 
447  case 'b':
448  case 'bold':
449  $handle[] = 1;
450 
451  break;
452 
453  case 'u':
454  case 'underlined':
455  $handle[] = 4;
456 
457  break;
458 
459  case 'bl':
460  case 'blink':
461  $handle[] = 5;
462 
463  break;
464 
465  case 'i':
466  case 'inverse':
467  $handle[] = 7;
468 
469  break;
470 
471  case '!b':
472  case '!bold':
473  $handle[] = 22;
474 
475  break;
476 
477  case '!u':
478  case '!underlined':
479  $handle[] = 24;
480 
481  break;
482 
483  case '!bl':
484  case '!blink':
485  $handle[] = 25;
486 
487  break;
488 
489  case '!i':
490  case '!inverse':
491  $handle[] = 27;
492 
493  break;
494 
495  default:
496  if (0 === preg_match('#^([^\(]+)\(([^\)]+)\)$#', $attribute, $m)) {
497  break;
498  }
499 
500  $shift = 0;
501 
502  switch ($m[1]) {
503  case 'fg':
504  case 'foreground':
505  $shift = 0;
506 
507  break;
508 
509  case 'bg':
510  case 'background':
511  $shift = 10;
512 
513  break;
514 
515  default:
516  break 2;
517  }
518 
519  $_handle = 0;
520  $_keyword = true;
521 
522  switch ($m[2]) {
523  case 'black':
524  $_handle = 30;
525 
526  break;
527 
528  case 'red':
529  $_handle = 31;
530 
531  break;
532 
533  case 'green':
534  $_handle = 32;
535 
536  break;
537 
538  case 'yellow':
539  $_handle = 33;
540 
541  break;
542 
543  case 'blue':
544  $_handle = 34;
545 
546  break;
547 
548  case 'magenta':
549  $_handle = 35;
550 
551  break;
552 
553  case 'cyan':
554  $_handle = 36;
555 
556  break;
557 
558  case 'white':
559  $_handle = 37;
560 
561  break;
562 
563  case 'default':
564  $_handle = 39;
565 
566  break;
567 
568  default:
569  $_keyword = false;
570 
571  if (256 <= $tput->count('max_colors') &&
572  '#' === $m[2][0]) {
573  $rgb = hexdec(substr($m[2], 1));
574  $r = ($rgb >> 16) & 255;
575  $g = ($rgb >> 8) & 255;
576  $b = $rgb & 255;
577  $distance = null;
578 
579  foreach ($_rgbTo256 as $i => $_rgb) {
580  $_rgb = hexdec($_rgb);
581  $_r = ($_rgb >> 16) & 255;
582  $_g = ($_rgb >> 8) & 255;
583  $_b = $_rgb & 255;
584 
585  $d = sqrt(
586  pow($_r - $r, 2)
587  + pow($_g - $g, 2)
588  + pow($_b - $b, 2)
589  );
590 
591  if (null === $distance ||
592  $d <= $distance) {
593  $distance = $d;
594  $_handle = $i;
595  }
596  }
597  } else {
598  $_handle = intval($m[2]);
599  }
600  }
601 
602  if (true === $_keyword) {
603  $handle[] = $_handle + $shift;
604  } else {
605  $handle[] = (38 + $shift) . ';5;' . $_handle;
606  }
607  }
608  }
609 
610  echo "\033[" . implode(';', $handle) . "m";
611 
612  return;
613  }
614 
622  public static function changeColor($fromCode, $toColor)
623  {
624  $tput = Console::getTput();
625 
626  if (true !== $tput->has('can_change')) {
627  return;
628  }
629 
630  $r = ($toColor >> 16) & 255;
631  $g = ($toColor >> 8) & 255;
632  $b = $toColor & 255;
633 
634  echo str_replace(
635  [
636  '%p1%d',
637  'rgb:',
638  '%p2%{255}%*%{1000}%/%2.2X/',
639  '%p3%{255}%*%{1000}%/%2.2X/',
640  '%p4%{255}%*%{1000}%/%2.2X'
641  ],
642  [
643  $fromCode,
644  '',
645  sprintf('%02x', $r),
646  sprintf('%02x', $g),
647  sprintf('%02x', $b)
648  ],
649  $tput->get('initialize_color')
650  );
651 
652  return;
653  }
654 
666  public static function setStyle($style, $blink = true)
667  {
668  if (OS_WIN) {
669  return;
670  }
671 
672  switch ($style) {
673  case 'b':
674  case 'block':
675  case '▋':
676  $_style = 1;
677 
678  break;
679 
680  case 'u':
681  case 'underline':
682  case '_':
683  $_style = 2;
684 
685  break;
686 
687  case 'v':
688  case 'vertical':
689  case '|':
690  $_style = 5;
691 
692  break;
693  }
694 
695  if (false === $blink) {
696  ++$_style;
697  }
698 
699  // Not sure what tput entry we can use here…
700  echo "\033[" . $_style . " q";
701 
702  return;
703  }
704 
710  public static function bip()
711  {
712  echo Console::getTput()->get('bell');
713 
714  return;
715  }
716 }
717 
721 Console::advancedInteraction();
static moveTo($x=null, $y=null)
Definition: Cursor.php:161
static getPosition()
Definition: Cursor.php:189
static hide()
Definition: Cursor.php:329
static getTput()
Definition: Console.php:306
static colorize($attributes)
Definition: Cursor.php:379
static move($steps, $repeat=1)
Definition: Cursor.php:66
static changeColor($fromCode, $toColor)
Definition: Cursor.php:622
static restore()
Definition: Cursor.php:250
static clear($parts= 'all')
Definition: Cursor.php:271
static setStyle($style, $blink=true)
Definition: Cursor.php:666
static save()
Definition: Cursor.php:238
static show()
Definition: Cursor.php:341
static bip()
Definition: Cursor.php:710