[新手上路]批处理新手入门导读[视频教程]批处理基础视频教程[视频教程]VBS基础视频教程[批处理精品]批处理版照片整理器
[批处理精品]纯批处理备份&还原驱动[批处理精品]CMD命令50条不能说的秘密[在线下载]第三方命令行工具[在线帮助]VBScript / JScript 在线参考
返回列表 发帖

[特效代码] Windows 10 虚拟终端控制字符序列-指针数字双显时钟

本帖最后由 a20150604 于 2019-8-12 19:06 编辑



更新 20190812_190023: 让指针在数字显示区域被遮挡, 不再干扰数码管的显示

Windows 10 对 控制台虚拟终端序列 的初步支持 让 CMD 字符绘图又多了途径, 比如可以用 24 位色, 可以轻松随意控制光标在屏幕上的位置.

转义序列的行为基于 VT100 和派生的终端仿真器技术,最具体的是xterm终端仿真器

https://docs.microsoft.com/en-us ... s#text-modification

在旧版的 CMD 上, 我制作过十五段数码管时钟和指针式时钟.

指针式时钟的运行速度一直不理想, 主要原因是三角函数, 画线算法, 程序整体框架, 变量环境不够优化; 其次旧版 CMD 对字符绘图的支持方式也不如现在.

对 Windows 10 控制台虚拟终端序列 的初步尝试, 我选择了指针数字双显时钟.

测试环境:
    Windows 10 Pro 64-bit (10.0, Build 18362)
    Intel(R) Core(TM) i7-8750H CPU @ 2.20GHz (12 CPUs), ~2.2GHz
    电源方案: 高性能模式
   
窗口大小设置:
    51 字符 (_SIZE 变量)
   
运行 FPS: 30+

不要尝试在 Windows 8 以及更老版本的 CMD 上运行此程序, 即使是 Windows 10 也不是所有版本都能正常支持 虚拟终端控制字符转义序列, 而是在某个版本开始才引入此功能(具体版本号我没查清楚), 近期版本是没问题的.

如果 Windows 10 版本并非过老, 而不能正常运行, 你还要确保在 CMD 的属性对话框上 不要 勾选 使用旧版控制台 这个复选框, 关掉窗口, 然后重新运行文件才有效

请将控制台字体设置为 光栅字体 8X8

此代码在 github 公开
  1. ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
  2. ::
  3. ::  指针数字双显时钟
  4. ::
  5. ::  pointer_digital_dual_display_clock_WIN10.cmd
  6. ::
  7. ::  author: neorobin ver: 20190812_190023
  8. ::
  9. ::  https://github.com/neorobin/WIN10CMD_Console-Virtual-Terminal-Sequences_ANSI/blob/master/pointer_digital_dual_display_clock_WIN10/pointer_digital_dual_display_clock_WIN10.cmd
  10. ::
  11. ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
  12. @echo off & setlocal DISABLEDELAYEDEXPANSION
  13. >nul chcp 437
  14. (for /f "delims==" %%a in ('set') do set "%%a=") & set "Path=%SystemRoot%\system32"
  15. :: for Fifteen-segment display logic
  16. :: The following pattern code is not necessary, just to illustrate the logical principle of the show
  17. ::
  18. ::  ###   # ### ### # # ### ### ### ### ### ABC
  19. ::  # #   #   #   # # # #   #     # # # # # DEF
  20. ::  # #   # ### ### ### ### ###   # ### ### GHI
  21. ::  # #   # #     #   #   # # #   # # #   # JKL
  22. ::  ###   # ### ###   # ### ###   # ### ### MNO
  23.     set "$_A="#A=!!(#-1)""
  24.     set "$_B="#B=(!!(#-1)^&!!(#-4))""
  25.     set "$_C="#C=1""
  26.     set "$_D="#D=(!(#^&3)^|!!(#^&~3))^&!!(#-7)""
  27. REM set "$_E="#E=0""                                    & rem never display
  28.     set "$_F="#F=!!(#-5)^&!!(#-6)""
  29.     set "$_G="#G=!!(#-1)^&!!(#-7)""
  30.     set "$_H="#H=!(!#^|!(#-1)^|!(#-7))""
  31. REM set "$_I="#I=1""                                    & rem Replaced by C
  32.     set "$_J="#J=~#^&1^&!!(#-4)""
  33. REM set "$_K="#K=0""                                    & rem never display
  34.     set "$_L="#L=!!(#-2)""
  35.     set "$_M="#M=(!!(#-1)^&!!(#-4)^&!!(#-7))""
  36. REM set "$_N="#N=(!!(#-1)^&!!(#-4)^&!!(#-7))""          & rem Replaced by M
  37. REM set "$_O="#O=1""                                    & rem Replaced by C
  38.     set "$__="#_=0""                                    & rem Replace the calculation where E and K position
  39.                                                           rem 用于 代替 在 E 和 K 位 的计算
  40. REM "#_=0" 用于 在 E 和 K 位 让运算式 "S=!S!#!#%%$!" 有值可取
  41. @echo off & setlocal enabledelayedexpansion
  42. for /F %%a in ('echo prompt $E^| cmd') do set "_ESC=%%a"
  43. set "_PEN=#"
  44. set "_PEN_SCALE=*"
  45. set /a "_SIZE=51" & REM Set the size of the clock, recommended from 37 to 100
  46. set /a "_LOW_LIMIT_OF_WIDTH_OF_FIFTEEN_SEGMENT_DISPLAY=37"
  47. set /a "_s=(_SIZE-15)>>31, _SIZE=(_LOW_LIMIT_OF_WIDTH_OF_FIFTEEN_SEGMENT_DISPLAY&_s)+(_SIZE&~_s)" & REM size lower limit: 37
  48. set /a "_WID=_HEI=_SIZE|1,_R_FACE=_WID/2-1, _R_FACE_SQ=_R_FACE*_R_FACE, _R_FACE_1=_R_FACE-1,_R_FACE_2=_R_FACE-2"
  49. set /a "_LEFT_FIFTEEN_SEGMENT_DISPLAY=(_WID-_LOW_LIMIT_OF_WIDTH_OF_FIFTEEN_SEGMENT_DISPLAY)/2+1, _TOP_FIFTEEN_SEGMENT_DISPLAY=_WID/2+_R_FACE/4, _RIGHT_PLUS_1_FIFTEEN_SEGMENT_DISPLAY=_LEFT_FIFTEEN_SEGMENT_DISPLAY+_LOW_LIMIT_OF_WIDTH_OF_FIFTEEN_SEGMENT_DISPLAY, _BOTTOM_PLUS_1_FIFTEEN_SEGMENT_DISPLAY=_TOP_FIFTEEN_SEGMENT_DISPLAY+5"
  50. color 0F & mode %_WID%,%_HEI%
  51. REM The work that needs "Path" is done, now you can clean it up.
  52. set "Path="
  53. set "_SIN=(#-#*#/1875*#/320000+#*#/1875*#/15625*#/16000*#/2560000-#*#/1875*#/15360*#/15625*#/15625*#/16000*#/44800000)"
  54. set "_COS=(10000-#*#/20000+#*#/1875*#/15625*#/819200-#*#/1875*#/15360*#/15625*#/15625*#/10240000+#*#/1875*#/15360*#/15625*#/15625*#/16000*#/15625*#/229376000)"
  55. REM 角度常量, 不直接用字面数值, 让 宏代码 定义更易读
  56. set /a "_PI=31416, _2PI=2*_PI, _PI#2=_PI/2, _3PI#2=3*_PI/2, _3PI#2_1=_3PI#2-1"
  57. set "_SIN(t)=(#=(t) %% %_2PI%, #+=#>>31&%_2PI%, #1=(#-%_PI#2%^#-%_3PI#2%)>>31, #3=%_3PI#2_1%-#>>31, #=(-#&#1)+(#&~#1)+(%_PI%&#1)+(-%_2PI%&#3), %_SIN%)"
  58. set "_COS(t)=(#=(t) %% %_2PI%, #+=#>>31&%_2PI%, #1=(#-%_PI#2%^#-%_3PI#2%)>>31, #3=%_3PI#2_1%-#>>31, #=(-#&#1)+(#&~#1)+(%_PI%&#1)+(-%_2PI%&#3), #=%_COS%, (-#&#1)+(#&~#1))"
  59. set "_SIN(t),_COS(t)=(#=(t) %% %_2PI%, #+=#>>31&%_2PI%, #1=(#-%_PI#2%^#-%_3PI#2%)>>31, #3=%_3PI#2_1%-#>>31, #=(-#&#1)+(#&~#1)+(%_PI%&#1)+(-%_2PI%&#3), #S=%_SIN%, #=%_COS%, #C=(-#&#1)+(#&~#1))"
  60. set /a "_DEG=_PI/180, _6DEG=6*_PI/180, _30DEG=30*_PI/180, _3.6DEG=36*_PI/(180*10)"
  61. set /a "_XCZOOM = 10000 * _WID/2, _XC=_WID/2+1, _YCZOOM = 10000 * _HEI/2, _YC=_HEI/2+1, _TH0=-_PI#2"
  62. set /a "_2XC=2*_XC, _2YC=2*_YC"
  63. <nul set /p "=%_ESC%[?25l" & REM ESC [ ? 25 l  DECTCEM   Text Cursor Enable Mode Hide  Hide the cursor
  64. ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
  65. ::
  66. :: angle of HOUR PIN:           HH * 30deg + MM * 30deg / 60 + SS * 30deg / 3600
  67. ::                              = ((HH * 60 + MM) * 60 + SS) * 30deg / 3600
  68. ::                              = ((HH * 60 + MM) * 60 + SS) * deg / 120
  69. ::
  70. :: angle of MINUTE PIN:         MM * 6deg + SS * 6deg / 60
  71. ::                              = (MM * 60 + SS) * 6deg / 60
  72. ::                              = (MM * 60 + SS) * deg / 10
  73. ::
  74. :: angle of SECOND PIN:         SS * 6deg
  75. ::                              OR
  76. ::                              (SS * 100 + CC)    / 100 * 6deg
  77. ::                              = (SS * 100 + CC) * 6deg / 100
  78. ::
  79. :: angle of CENTISECOND PIN:    CC * 360deg / 100 = CC * 36deg / 10
  80. ::
  81. ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
  82. set "_RGB_SCALE=0;0;255"
  83. set "_RGB_FACE=255;255;255"
  84. set "$erase_last_pin="
  85. set /a "_DENSITY=150, _SPEED=3*%_DEG%, th=_TH0"
  86. set /a "_CENTISECONDS_OF_A_DAY=24*60*60*100"
  87. set "_LEFT37DOWN1=%_ESC%[37D%_ESC%[1B"
  88. title pointer_digital_dual_display_clock_WIN10
  89. REM 每 _GAP 帧计算一次 FPS, ! _GAP 必须是 2 的幂, 并且不小于 2
  90. set /a "_GAP=2<<5"
  91. (
  92.     for /f "delims==" %%a in ('set _') do set "%%a="
  93.     set /a "_PIN_LEN_S=%_R_FACE%-3,_PIN_LEN_M=_PIN_LEN_S-1,_PIN_LEN_H=_PIN_LEN_S/2+%_SIZE%/15,_PIN_LEN_C=_PIN_LEN_S/4-0"
  94.     set "_RGB_C=0;255;0"
  95.     set "_RGB_S=255;0;0"
  96.     set "_RGB_M=100;100;100"
  97.     set "_RGB_H=0;0;0"
  98.     <nul set /p "=%_ESC%[48;2;%_RGB_FACE%m"
  99.     REM gen clock dial: Distance method, quick but not meticulous
  100.     REM title gen clock dial: Distance method, quick but not meticulous
  101.     for /L %%x in (%_XC% -1 1) do (
  102.         for /L %%y in (%_YC% -1 1) do (
  103.             set /a "_dx=%%x-%_XC%, _dy=%%y-%_YC%, t=_dx*_dx+_dy*_dy-%_R_FACE_SQ%-1"
  104.             if !t! lss 0 (
  105.                 set /a "#x_=%_2XC%-%%x, #y_=%_2YC%-%%y"
  106.                 set "$pin=%_ESC%[%%y;!#x_!H%_PEN%%_ESC%[!#y_!;%%xH%_PEN%%_ESC%[!#y_!;!#x_!H%_PEN%%_ESC%[%%y;%%xH%_PEN%!$pin!"
  107.             )
  108.         )
  109.         set "$pin=%_ESC%[38;2;%_RGB_FACE%m!$pin!"
  110.         <nul set /p "=!$pin!"
  111.         set "$pin="
  112.     )
  113.     REM gen clock dial: rotary scanning polishing edge
  114.     for /L %%i in (0 1 %_DENSITY%) do (
  115.         set /a "th+=%_SPEED%, %_SIN(t),_COS(t):t=th%, #x=(%_XCZOOM%+%_R_FACE%*#C)/10000+1, #y=(%_YCZOOM%+%_R_FACE%*#S)/10000+1, #x_=%_2XC%-#x, #y_=%_2YC%-#y"
  116.         set "$pin=%_ESC%[!#y!;!#x_!H%_PEN%%_ESC%[!#y_!;!#x!H%_PEN%%_ESC%[!#y_!;!#x_!H%_PEN%%_ESC%[!#y!;!#x!H%_PEN%!$pin!"
  117.         set "$pin=%_ESC%[38;2;%_RGB_FACE%m!$pin!"
  118.         <nul set /p "=!$pin!"
  119.         set "$pin="
  120.     )
  121.     REM nail up scale
  122.     <nul set /p "=%_ESC%[48;2;%_RGB_FACE%m"
  123.     for /L %%i in (0 1 3) do (
  124.         set /a "r3=%%i %% 3"
  125.         set /a "th=-%_PI#2% + %%i*%_2PI%/12, %_SIN(t),_COS(t):t=th%, $x=%_XCZOOM%-#C, $y=%_YCZOOM%-#S"
  126.         for /l %%a in (0 1 %_R_FACE%) do (
  127.             set /a "#x=($x+=#C)/10000+1, #y=($y+=#S)/10000+1, #x_=%_2XC%-#x, #y_=%_2YC%-#y"
  128.             if !r3!==0 (
  129.                 if %%a geq %_R_FACE_2% if %%a lss %_R_FACE% (
  130.                     set "$pin=%_ESC%[!#y!;!#x!H%_PEN_SCALE%%_ESC%[!#y_!;!#x_!H%_PEN_SCALE%%_ESC%[!#y!;!#x_!H%_PEN_SCALE%%_ESC%[!#y_!;!#x!H%_PEN_SCALE%!$pin!"
  131.                 )
  132.             ) else (
  133.                 if %%a equ %_R_FACE_1% (
  134.                     set "$pin=%_ESC%[!#y!;!#x!H%_PEN_SCALE%%_ESC%[!#y_!;!#x_!H%_PEN_SCALE%%_ESC%[!#y!;!#x_!H%_PEN_SCALE%%_ESC%[!#y_!;!#x!H%_PEN_SCALE%!$pin!"
  135.                 )
  136.             )
  137.         )
  138.         set "$pin=%_ESC%[38;2;%_RGB_SCALE%m!$pin!"
  139.         <nul set /p "=!$erase_last_pin!!$pin!"
  140.         set "$pin="
  141.     )
  142.     <nul set /p "=%_ESC%[48;2;%_RGB_FACE%m"
  143.     set /a "_cnt=0, $v=0"
  144.     for /L %%i in () do (
  145.         set "tm=!time: =0!" & set /a "SS=1!tm:~6,2!-100, MM=1!tm:~3,2!-100, HH=1!tm:~0,2!-100, CC=1!tm:~-2!-100"
  146.         set /a "th_S=-%_PI#2% + (SS * 100 + CC) * %_6DEG% / 100, th_M=-%_PI#2% + (MM * 60 + SS) * %_DEG% / 10, th_H=-%_PI#2% + ((HH * 60 + MM) * 60 + SS) * %_DEG% / 120, th_C=-%_PI#2% + CC*%_3.6DEG%"
  147.         REM Draw 4 pointers
  148.         for %%K in (C S M H) do (
  149.             set /a "th=th_%%K, %_SIN(t),_COS(t):t=th%, $x=%_XCZOOM%-#C, $y=%_YCZOOM%-#S"
  150.             for /l %%a in (0 1 !_PIN_LEN_%%K!) do (
  151.                 REM (#-a^#-b)>>31 == -1    : # in [a,b)
  152.                 REM (#-a^#-(b+1))>>31 == -1: # in [a,b]
  153.                 REM hid: 让指针在数字显示区域被遮挡, 不再干扰数码管的显示
  154.                 set /a "#x=($x+=#C)/10000+1, #y=($y+=#S)/10000+1, hid=(#x-%_LEFT_FIFTEEN_SEGMENT_DISPLAY%^#x-%_RIGHT_PLUS_1_FIFTEEN_SEGMENT_DISPLAY%)&(#y-%_TOP_FIFTEEN_SEGMENT_DISPLAY%^#y-%_BOTTOM_PLUS_1_FIFTEEN_SEGMENT_DISPLAY%)"
  155.                 if !hid! geq 0 (
  156.                     set "$pin=%_ESC%[!#y!;!#x!H%_PEN%!$pin!"
  157.                 )
  158.             )
  159.             set "$pin=%_ESC%[38;2;!_RGB_%%K!m!$pin!"
  160.         )
  161.         <nul set /p "=!$erase_last_pin!!$pin!"
  162.         set "$erase_last_pin=!$pin:%_PEN%= !"
  163.         set "$pin="
  164.         REM Fifteen segment display
  165.         set "S=" & set "_0or1=0"
  166.         REM 从上到下 逐次 生成 第 1 ~ 第 5 行图形
  167.         REM "A B C" "D _ F" "G H I" "J _ L" "M N O"
  168.         REM I 和 O 的逻辑与 C 完全一致, 由 C 代替
  169.         REM N 的逻辑与 M 完全一致, 由 M 代替
  170.         for %%L in ("A B C" "D _ F" "G H C" "J _ L" "M M C") do (
  171.             REM 每行从左到右依次计算并填充各个位置
  172.             for %%d in (0 _ 1 _ : _ 3 _ 4 _ : _ 6 _ 7 _ : _ 9 _ 10) do (
  173.                 if "%%d" geq "0" (
  174.                     REM 获取 1 个单独数字
  175.                     set "#=!tm:~%%d,1!"
  176.                     REM 一个数字位占 3 个像素宽, 要逐个像素计算 是否 显示
  177.                     REM "S=!S!_!#%%$!" :  !#%%$! 的结果是加入一个 0 或者 1,
  178.                     REM 在 0 或者 1 前加一个 _ 号, 这个符号不能用作画笔字符, 否则替换可能出错
  179.                     REM 为了在后续将这些 0 或者 1, 便于被替换成 空格 或者 画笔字符
  180.                     for %%$ in (%%~L) do (
  181.                         set /a !$_%%$!
  182.                         set "S=!S!_!#%%$!"
  183.                     )
  184.                 ) else if "!_0or1!%%d"=="1:" (
  185.                     REM 第 2, 4 行的分隔位
  186.                     set "S=!S!%_PEN%"
  187.                 ) else (
  188.                     REM 恒空白位
  189.                     set "S=!S! "
  190.                 )
  191.             )
  192.             REM 先左移 37 到图形最左边, 再下移一行
  193.             set "S=!S!%_LEFT37DOWN1%"
  194.             set /a "_0or1^=1"
  195.         )
  196.         set "S=!S:_0= !"
  197.         <nul set /p "=%_ESC%[%_TOP_FIFTEEN_SEGMENT_DISPLAY%;%_LEFT_FIFTEEN_SEGMENT_DISPLAY%H!S:_1=%_PEN%!"
  198.         set /a "t=-((_cnt+=1)&(%_GAP%-1))>>31, $$=($u=((HH*60+MM)*60+SS)*100+CC)-$v, $$+=$$>>31&%_CENTISECONDS_OF_A_DAY%, $$=(~t&$$)+(t&1), FPS=(~t&(100*%_GAP%/$$))+(t&FPS), $v=(~t&$u)+(t&$v)"
  199.         if !t!==0 (
  200.             <nul set /p "=%_ESC%[48;2;0;0;0m%_ESC%[1;1HFPS:!FPS! %_ESC%[48;2;%_RGB_FACE%m"
  201.         )
  202.     )
  203. )
  204. >nul pause
  205. exit
复制代码
3

评分人数

返回列表