Board logo

标题: 通过大家努力,批处理可告别choice [打印本页]

作者: wangff     时间: 2008-12-9 11:37    标题: 通过大家努力,批处理可告别choice

改进版在26楼:
大家共同改进!
@echo off
call inc 2>nul
if %errorlevel%==1 (
   >inc.src echo ecs:100 B8 00 01 CD 16 B8 00 00 74 02 CD 16 B4 4C CD 21
   >>inc.src echo rcx
   >>inc.src echo 10
   >>inc.src echo w
   >>inc.src echo q
   debug inc.com < inc.src 2>nul 1>nul
   del inc.src
)
:loop
inc
if not %errorlevel%==0 (
   echo %errorlevel%
   if %errorlevel%==81 goto :eof ::q or Q exit
   if %errorlevel%==113 goto :eof
)
ping -n 2 127.1>nul
goto loop
[ Last edited by wangff on 2008-12-11 at 10:34 ]
作者: wangff     时间: 2008-12-9 16:09

@echo off
call inc 2>nul
if %errorlevel%==1 (   ::inc 不存在则创建
   >inc.src echo ecs:100 A0 5D 00 3C 20 75 09 B4 01 CD 16 B8 00 00 74 02 CD 16 B4 4C CD 21
   >>inc.src echo rcx
   >>inc.src echo 16
   >>inc.src echo w
   >>inc.src echo q
   debug inc.com < inc.src 2>nul 1>nul
   del inc.src
)
set/p =input:<nul
inc i ::有参数(任意)等待输入一个字符,通过errorlevel返回
echo %errorlevel%
:loop
inc   ::无参数检测是否有按键 无:errorlevel=0 有errorlevel=键值 可用干运行中动态检测按键
echo %errorlevel%
if not %errorlevel%==0 (
   if %errorlevel%==81 goto :eof ::q or Q exit
   if %errorlevel%==113 goto :eof
)
ping -n 2 127.1>nul
goto loop
[ Last edited by wangff on 2008-12-10 at 21:35 ]
作者: s11ss     时间: 2008-12-9 19:33
wangff兄可不可以讲解下int 16的1号功能是怎么用的?
作者: wangff     时间: 2008-12-9 20:58
键盘服务(Keyboard Service——INT 16H)  
作者:佚名  出处:中国自学编程网收集整理   发布日期:2007-09-27   

00H、10H —从键盘读入字符03H —设置重复率
01H、11H —读取键盘状态04H —设置键盘点击
02H, 12H —读取键盘标志05H —字符及其扫描码进栈
(1)、功能00H和10H
功能描述:从键盘读入字符
入口参数:AH=00H——读键盘
=10H——读扩展键盘,可根据0000:0496H单元的内容判断:扩展键盘是否有效
出口参数:AH=键盘的扫描码
AL=字符的ASCII码
(2)、功能01H和11H
功能描述:读取键盘状态
入口参数:AH=01H——检查普通键盘
=11H——检查扩展键盘
出口参数:ZF=1——无字符输入,否则,AH=键盘的扫描码,AL=ASCII码。
(3)、功能02H和12H
功能描述:读取键盘标志
入口参数:AH=02H——普通键盘的移位标志
=12H——扩展键盘的移位标志
出口参数:AL=键盘标志(02H和12H都有效),其各位之值为1时的含义如下: 位7—INS开状态位3—ALT键按下
位6—CAPS LOCK开状态位2—CTRL键按下
位5—NUM LOCK开状态位1—左SHIFT键按下
位4—SCROLL LOCK开状态位0—右SHIFT键按下
AH=扩展键盘的标志(12H有效),其各位之值为1时的含义如下:
位7—SysReq键按下位3—右ALT键按下
位6—CAPS LOCK键按下位2—右CTRL键按下
位5—NUM LOCK键按下位1—左ALT键按下
位4—SCROLL键按下位0—左CTRL键按下
(4)、功能03H
功能描述:设置重复率
入口参数:AH=03H 对于PC/AT和PS/2:AL=05H
BH=重复延迟
BL=重复率
对于PCjr:AL=00H——装入缺省的速率和延迟
=01H——增加初始延迟
=02H——重复频率降低一半
=03H——增加延迟和降低一半重复频率
=04H——关闭键盘重复功能
出口参数:无
(5)、功能04H
功能描述:设置键盘点击
入口参数:AH=04H AL=00H——关闭键盘点击功能
=01H——打开键盘点击功能
出口参数:无
(6)、功能05H
功能描述:字符及其扫描码进栈
入口参数:AH=05H
CH=字符的描述码
CL=字符的ASCII码
出口参数:CF=1——操作成功,AL=00H,否则,AL=01H
作者: s11ss     时间: 2008-12-9 21:04
不好意思,这不算讲解吧?至少给一两个例子说明下嘛:)
作者: wangff     时间: 2008-12-9 21:28
(2)、功能01H
功能描述:读取键盘状态
入口参数:AH=01H——检查普通键盘
出口参数:ZF=1——无字符输入,否则,AH=键盘的扫描码,AL=ASCII码。
mov     ah,1     ;检测是否按键
int       16h
mov     ax,0     ;ah=0 读键,清al
jz         ret      ;zf=1 无按键返回0
int       16h     ;有按键,读出的ASCII在al

ret:
mov     ah,4ch   ;将al返回给 errorleve
int       21h
不知说清楚否?打字很慢,请谅解.
作者: s11ss     时间: 2008-12-9 22:03
mov ah,0
int 16

上面两句不就是读输入么,还要1号功能干什么?
作者: wangff     时间: 2008-12-9 22:15


  Quote:
Originally posted by s11ss at 2008-12-9 22:03:
mov ah,0
int 16

上面两句不就是读输入么,还要1号功能干什么?

ah=0: 是等待输入   ah=1: 只检测,不读取(还在键盘缓冲中),如有输入还必须用ah=0读出

[ Last edited by wangff on 2008-12-9 at 22:17 ]
作者: s11ss     时间: 2008-12-9 22:20


  Quote:
Originally posted by wangff at 2008-12-9 10:15 PM:



ah=0: 是等待输入   ah=1: 只检测,不读取(还在键盘缓冲中),如有输入还必须用ah=0读出

[ Last edited by wangff on 2008-12-9 at 22:17 ]

C:\>debug
-a
0B22:0100 mov ah,0
0B22:0102 int 16
0B22:0104
-t

AX=0000  BX=0000  CX=0000  DX=0000  SP=FFEE  BP=0000  SI=0000  DI=0000
DS=0B22  ES=0B22  SS=0B22  CS=0B22  IP=0102   NV UP EI PL NZ NA PO NC
0B22:0102 CD16          INT     16
-p
(此处输入的是a)
AX=1E61  BX=0000  CX=0000  DX=0000  SP=FFEE  BP=0000  SI=0000  DI=0000
DS=0B22  ES=0B22  SS=0B22  CS=0B22  IP=0104   NV UP EI PL NZ NA PO NC
0B22:0104 381C          CMP     [SI],BL                            DS:0000=CD
-

我还是觉得用0号就行了

[ Last edited by s11ss on 2008-12-9 at 22:22 ]
作者: wangff     时间: 2008-12-9 22:36
2楼的例子:
inc i ::有参数(任意)等待输入一个字符,通过errorlevel返回

就只用了ah=0

而:
inc   ::无参数检测是否有按键 无:errorlevel=0 有errorlevel=键值 可用干运行中动态检测按键

则必须用到 ah=1
作者: s11ss     时间: 2008-12-9 22:48


  Quote:
Originally posted by wangff at 2008-12-9 10:36 PM:
2楼的例子:
inc i ::有参数(任意)等待输入一个字符,通过errorlevel返回

就只用了ah=0

而:
inc   ::无参数检测是否有按键 无:errorlevel=0 有errorlevel=键值 可用干运行中动态检测按键

则必须用到 ah=1

无按键是直接回车的情况么?如果只用0号的话,al是0d啊
作者: wangff     时间: 2008-12-9 23:02

@echo off

:loop
for /f "tokens=*" %%a in ('ping -n 1 127.1 ^| findstr /i "Request Reply"') do echo.%%a
inc   ::无参数检测是否有按键 无:errorlevel=0 有errorlevel=键值 可用干运行中动态检测按键
if not %errorlevel%==0 (
   if %errorlevel%==112 pause   ::input p or P pause
   if %errorlevel%==90  pause
   if %errorlevel%==81 goto :eof ::input q or Q exit
   if %errorlevel%==113 goto :eof
)
ping -n 2 127.1>nul
goto loop
这个例子就可说明,只用ah=0做不到这种效果

[ Last edited by wangff on 2008-12-9 at 23:06 ]
作者: s11ss     时间: 2008-12-9 23:30
我慢慢体会吧,有劳了,wangff兄
作者: s11ss     时间: 2008-12-9 23:59
二楼的ecs:100 A0 5D 00 3C 20 75 09 B4 01 CD 16 B8 00 00 74 02 CD 16 B4 4C CD 21 CD 21 CD 21中,3次int 21,何故?
作者: wangff     时间: 2008-12-10 08:22


  Quote:
Originally posted by s11ss at 2008-12-9 23:59:
二楼的ecs:100 A0 5D 00 3C 20 75 09 B4 01 CD 16 B8 00 00 74 02 CD 16 B4 4C CD 21 CD 21 CD 21中,3次int 21,何故?

谢谢s11ss的细心,是从debug考下多余的,被长度16h约束没存到inc.com中不影响使用,已修改.
作者: wangff     时间: 2008-12-10 08:32


  Quote:
Originally posted by s11ss at 2008-12-9 22:48:


无按键是直接回车的情况么?如果只用0号的话,al是0d啊

无按键就是沒动键盘.
作者: wxcute     时间: 2008-12-10 14:00
真的很强,像我等不懂汇编的就只能望洋兴叹了。
作者: 本是     时间: 2008-12-10 14:31
上面的程序中mov ax,0长3字节,改mov ah,0或xor ah,ah或sub ah,ah就能少1个字节。

其实,此类程序最短的只要8字节。

DEBUG
a
  mov ah,0
  int 16h
  mov ah,4Ch
  int 21h

rcx
8
nkeycode.com
w
q
作者: s11ss     时间: 2008-12-10 14:55


  Quote:
Originally posted by 本是 at 2008-12-10 02:31 PM:
上面的程序中mov ax,0长3字节,改mov ah,0或xor ah,ah或sub ah,ah就能少1个字节。

其实,此类程序最短的只要8字节。

DEBUG
a
  mov ah,0
  int 16h
  mov ah,4Ch
...

我的意思就是不用int 16h的1号功能,看来还是行的~

其实好像可以不写com,直接用debug调用:)
作者: wangff     时间: 2008-12-10 15:32


  Quote:
Originally posted by 本是 at 2008-12-10 14:31:
上面的程序中mov ax,0长3字节,改mov ah,0或xor ah,ah或sub ah,ah就能少1个字节。

其实,此类程序最短的只要8字节。

DEBUG
a
  mov ah,0
  int 16h
  mov ah,4Ch
...

还是误解了,试一下12楼的例子就会发现与上面的程序不一样之处
作者: wangff     时间: 2008-12-10 15:45

@echo off
call inc 2>nul
if %errorlevel%==1 (
   >inc.src echo ecs:100 B8 00 01 CD 16 B8 00 00 74 02 CD 16 B4 4C CD 21
   >>inc.src echo rcx
   >>inc.src echo 10
   >>inc.src echo w
   >>inc.src echo q
   debug inc.com < inc.src 2>nul 1>nul
   del inc.src
)
:loop
inc


echo %errorlevel%



if not %errorlevel%==0 (
   if %errorlevel%==81 goto :eof ::q or Q exit
   if %errorlevel%==113 goto :eof
)
ping -n 2 127.1>nul
goto loop
或试一下这个,没输入时循环一直在跑.而不是等输入.

本帖主要就是用int 16h的ah=1,(也就是它与choice的主耍区别)没说清楚就毫无意义.
也许是我的表达能力不行,站内高手云云,有谁能邦我说明白?

[ Last edited by wangff on 2008-12-10 at 17:51 ]
作者: wangff     时间: 2008-12-10 17:47


  Quote:
Originally posted by s11ss at 2008-12-10 14:55:


我的意思就是不用int 16h的1号功能,看来还是行的~

其实好像可以不写com,直接用debug调用:)

不用com也行,但要有脚本 如 c.txt
a
MOV     AX,0100
INT     16
MOV     AX,0000
JZ      010C
INT     16
MOV     AH,4C
INT     21

g
q
p代码:
@echo off

:loop
debug <c.txt>nul


echo %errorlevel%



if not %errorlevel%==0 (
   if %errorlevel%==81 goto :eof ::q or Q exit
   if %errorlevel%==113 goto :eof
)
ping -n 2 127.1>nul
goto loop
效果一样.

[ Last edited by wangff on 2008-12-10 at 17:52 ]
作者: wangff     时间: 2008-12-10 18:56
只用int 16h功能ah=0的例子:

脚本: a.txt
a
  mov ah,0
  int 16
  mov ah,4C
  int 21

g
q
p代码:
@echo off

:loop
debug <a.txt>nul


echo %errorlevel%



if not %errorlevel%==0 (
   if %errorlevel%==81 goto :eof ::q or Q exit
   if %errorlevel%==113 goto :eof
)
ping -n 2 127.1>nul
goto loop

作者: s11ss     时间: 2008-12-10 19:07
可以不要临时文件的
goto :main
a
;MOV     AX,0100
;INT     16
MOV     AX,0000
;JZ      010C
INT     16
MOV     AH,4C
INT     21

g
q

:main
@echo off

:loop
debug <"%~f0">nul


echo %errorlevel%



if not %errorlevel%==0 (
   if %errorlevel%==81 goto :eof ::q or Q exit
   if %errorlevel%==113 goto :eof
)
ping -n 2 127.1>nul
goto loop

作者: zh159     时间: 2008-12-10 21:47
加两行快速清除“goto :main”显示和支持中文显示(XP测试)

  Quote:
......

:main
cls
@echo off
chcp 437|graftabl 936>nul

......


作者: pyjhhh     时间: 2008-12-10 23:32
好帖子
作者: wangff     时间: 2008-12-11 09:19
2楼可带参数的完善版:
@echo off
goto main
a
MOV     AL,[005D]
CMP     AL,20
JNZ     0110
MOV     AH,01
INT     16
MOV     AX,0000
JZ      0112
INT     16
MOV     AH,4C
INT     21

g
q
:main
chcp 437|graftabl 936>nul
set/p =input:<nul
::有参数(任意)等待输入一个字符,通过errorlevel返回
debug a.com i<"%~f0">nul 2>nul
echo %errorlevel%
:loop
::无参数检测是否有按键 无:errorlevel=0 有errorlevel=键值 可用干运行中动态检测按键
debug<"%~f0">nul
echo %errorlevel%
if not %errorlevel%==0 (
   if %errorlevel%==81 goto :eof ::q or Q exit
   if %errorlevel%==113 goto :eof
)
ping -n 2 127.1>nul
goto loop

作者: wangff     时间: 2008-12-11 10:56
自动运行:
@echo off
goto main
a
MOV     AL,[005D]
CMP     AL,20
JNZ     0110
MOV     AH,01
INT     16
MOV     AX,0000
JZ      0112
INT     16
MOV     AH,4C
INT     21

g
q
:main
chcp 437|graftabl 936>nul
set/p =等待...<nul&set/a n=0
:loop
set/a n+=1
set/p =.%n%<nul
debug<"%~f0">nul
if not %errorlevel%==0 (
   if %errorlevel%==81 goto :eof ::q or Q exit
   if %errorlevel%==113 goto :eof
)
if %n% gtr 5 goto p1
ping -n 2 127.1>nul
goto loop

:p1
echo.
echo 计时到,自动运行!
pause

作者: Helloworld     时间: 2008-12-11 13:19
兄们的创造能力实在是厉害!
作者: s11ss     时间: 2008-12-11 13:23
告别choice,这么说好像有点牵强,choice功能还是相对强大的说:)
作者: wangff     时间: 2008-12-11 13:33
可否举个例子?
作者: s11ss     时间: 2008-12-11 14:13


  Quote:
Originally posted by wangff at 2008-12-11 01:33 PM:
可否举个例子?

choice /?
作者: wangff     时间: 2008-12-11 14:20
我是这样理解的:
1.关于键盘输入choice不外乎也是用ah=0及ah=1两基本功能来实现的
2.choice再好也不是每套系统都有预装(我的xp就没有)
3.choice功能再強也是固定的,而p只要有了这两基本功能其它的就发挥大家的想象能力,是鱼好还是渔杆好大家都明白
4.告别choice作为一个目标,大家共同努力

[ Last edited by wangff on 2008-12-11 at 15:11 ]
作者: zh159     时间: 2008-12-11 18:19
这样就不用那么多跳转了
...
ping -n 2 127.1>nul
if %n% LEQ 5 goto loop

echo.
echo 计时到,自动运行!
pause

作者: qzwqzw     时间: 2008-12-11 18:33
“是鱼好还是渔杆好大家都明白”
相信真正明白的没有几个
毕竟与鱼相比
鱼竿还需要一汪水和一片饵

如果真要说鱼竿好
那么再问是鱼竿与木棍+线+钩子孰好?
而鱼与红烧鲤鱼孰好?
又该怎么抉择

别忘了debug在cmd是个很麻烦的东西
用起来会有很多潜在的问题(不仅仅是代码页)
作者: wangff     时间: 2008-12-11 19:29
35楼说的有道理,但:
"别忘了debug在cmd是个很麻烦的东西
用起来会有很多潜在的问题(不仅仅是代码页)"

本人确实不知,能否告知一二,如果致命则放弃这种想法.因debug为p嵌入小汇编成为可行,我觉得廷重要的.

[ Last edited by wangff on 2008-12-11 at 19:32 ]
作者: qzwqzw     时间: 2008-12-12 09:27
大约的情形可以参考下面的帖子
http://www.cn-dos.net/forum/viewthread.php?tid=9452
http://www.cn-dos.net/forum/viewthread.php?tid=20682

目前已知的是
使用Debug必然要启用ntvdm
而它是与cmd差异很大的一种命令行环境
比如命令行自动完成
比如长短文件名
作者: wxcute     时间: 2008-12-12 12:49
还有个问题,这个 choice 不能暂停等待输入(可能就是楼上 qzwqzw 兄说的 "命令行自动完成" 罢),而是一直在 :loop 标签里循环。
作者: wangff     时间: 2008-12-12 14:21
37楼的问题正在确认...
38 楼的问题 应该不存在,是否会沒带参,是哪一搂的程序?
作者: wxcute     时间: 2008-12-12 14:34    标题: 回复 39 楼 wangff

是我没看清,原来 27 楼有带参数暂停的功能。

还有一个问题(环境 XP SP3)
动态检测时如果按了某些键(如 Ctrl)之后就会假死,即再按什么也没有反应了。
快速按几个字母也会出现上述情况。
不知带参执行时会不会?
作者: wangff     时间: 2008-12-12 15:03
"假死"现象会出现,正在找原因...
但应该与debug无关,inc.com也会.
作者: s11ss     时间: 2008-12-13 03:18
写了一段代码,可返回ascii:
>i.com echo h#CX-~AP[hSTX-#pP]3/1/h$CX-}AP[h#JX-V3P]3/1/h'CX-~AP[h$pX-p#P]3/1/h#CX-xAP[h?EX-r#P]3/1/uK
i
echo %errorlevel%

作者: chenall     时间: 2008-12-13 18:24
都系强人,看不懂收藏下备用.
作者: winxos     时间: 2008-12-17 21:53    标题:

不过还是借助了汇编。
作者: mmfy     时间: 2009-1-15 19:09    标题: 这是我的一个想法:


@echo off
echo h#CX-~AP[hSTX-#pP]3/1/h$CX-}AP[h#JX-V3P]3/1/h'CX-~AP[h$pX-p#P]3/1/h#CX-xAP[h?EX-r#P]3/1/uK>key.com
chcp 437>nul&graftabl 936>nul
color 2f
:1
cls
echo 请输入密码:%es%
key
set pk=%errorlevel%
set tmp=
if %pk%==13 goto t1
if %pk%==8 goto backspace
if %pk%==97 set tmp=a
if %pk%==98 set tmp=b
if %pk%==99 set tmp=c
if %pk%==100 set tmp=d
if %pk%==101 set tmp=e
if %pk%==102 set tmp=f
if %pk%==103 set tmp=g
if %pk%==104 set tmp=h
if %pk%==105 set tmp=i
if %pk%==106 set tmp=j
if %pk%==107 set tmp=k
if %pk%==108 set tmp=l
if %pk%==109 set tmp=m
if %pk%==110 set tmp=n
if %pk%==111 set tmp=o
if %pk%==112 set tmp=p
if %pk%==113 set tmp=q
if %pk%==114 set tmp=r
if %pk%==115 set tmp=s
if %pk%==116 set tmp=t
if %pk%==117 set tmp=u
if %pk%==118 set tmp=v
if %pk%==119 set tmp=w
if %pk%==120 set tmp=x
if %pk%==121 set tmp=y
if %pk%==122 set tmp=z
if %pk%==48 set tmp=0
if %pk%==49 set tmp=1
if %pk%==50 set tmp=2
if %pk%==51 set tmp=3
if %pk%==52 set tmp=4
if %pk%==53 set tmp=5
if %pk%==54 set tmp=6
if %pk%==55 set tmp=7
if %pk%==56 set tmp=8
if %pk%==59 set tmp=9
if %tmp%== goto 1
set es=%es%*
set ep=%ep%%tmp%
goto 1
:backspace
if "%ep%"=="" goto 1
set ep=%ep:~0,-1%
set es=%es:~0,-1%
goto 1
:t1
echo 你的密码是:%ep%
pause

作者: xiaolongkun0     时间: 2009-4-11 13:48
研究下