I want to do a simple addition using numbers provided by the console line, something like this:
.486
.model flat, stdcall
option casemap :none
include \masm32\include\windows.inc
include \masm32\include\kernel32.inc
include \masm32\include\masm32.inc
include \masm32\include\user32.inc
includelib \masm32\lib\kernel32.lib
includelib \masm32\lib\masm32.lib
includelib \masm32\lib\user32.lib
.data
msg1 BYTE "Insert a number:"
msg2 BYTE "The sum is:"
.data?
oHandle DWORD ?
iHandle DWORD ?
bufferLen DWORD ?
buffer BYTE ?
.code
start:
invoke GetStdHandle, -11
mov oHandle, eax
invoke GetStdHandle, -10
mov iHandle, eax
invoke WriteFile, oHandle, addr msg1, lengthof msg1, NULL, NULL
invoke ReadFile, iHandle, addr buffer, 1, addr bufferLen, NULL
mov al, 0h
mov al, buffer
mov buffer, 0h ; I need some way to clean the buffer, this way doesn't work
invoke WriteFile, oHandle, addr msg1, lengthof msg1, NULL, NULL
invoke ReadFile, iHandle, addr buffer, 1, addr bufferLen, NULL
add al, buffer
mov buffer, al
invoke WriteFile, oHandle, addr msg2, lengthof msg2, NULL, NULL
invoke WriteFile, oHandle, addr buffer, lengthof buffer, NULL, NULL
invoke ExitProcess, 0
end start
Can someone give me a light?
Something like the principle of this code...
Thanks..
well - you need different buffers for the 2 values
this
mov al, 0h
mov al, buffer
mov buffer, 0h
and this
add al, buffer
mov buffer, al
make no sense
the value in EAX (AX, AL) is not preserved across API calls
so - you put the first number in buffer1
put the second number in buffer2
then, convert them from ASCII decimal to binary
then, add them together
then, convert the result from binary to ASCII decimal and display it
Hmmm... Sorry for my stupidity, but I have another problem, when I do this:
invoke WriteFile, oHandle, addr msg1, lengthof msg1, NULL, NULL
invoke ReadFile, iHandle, addr buffer1, 1, addr bufferLen1, NULL
invoke WriteFile, oHandle, addr msg1, lengthof msg1, NULL, NULL
invoke ReadFile, iHandle, addr buffer2, 1, addr bufferLen2, NULL
The first number is repeated in the second request, then program ends...... I think there's a problem with keyboard buffer, right? How can I solve this?
that problem is caused by using NULL for lpNumberOfBytesWritten
give it a valid pointer to a dword variable, and it should work
QuoteThis parameter can be NULL only when the lpOverlapped parameter is not NULL.
you've done quite well, really :t
but, let's step back a little and look at some other things
these are not critical problems, but may help you in the future
.486
.model flat, stdcall
option casemap :none
include \masm32\include\windows.inc
include \masm32\include\kernel32.inc
include \masm32\include\masm32.inc
include \masm32\include\user32.inc
includelib \masm32\lib\kernel32.lib
includelib \masm32\lib\masm32.lib
includelib \masm32\lib\user32.lib
all of that stuff can be replaced with a single line
include \masm32\include\masm32rt.inc
that is a plain text file that you can browse with NotePad to see what's inside
invoke GetStdHandle, -11
mov oHandle, eax
invoke GetStdHandle, -10
mov iHandle, eax
the windows.inc file defines hundreds of windows constants that will make your code easier to read
STD_INPUT_HANDLE equ -10
STD_OUTPUT_HANDLE equ -11
so, if i were to write it, it might look like this...
INVOKE GetStdHandle,STD_INPUT_HANDLE
mov hStdInp,eax
INVOKE GetStdHandle,STD_OUTPUT_HANDLE
mov hStdOut,eax
the "lengthof" and "sizeof" operators are a little different
in the case of bytes, they yield the same thing
but, if i were to get the "lengthof dwValue" of a dword variable, it would yield 1
if i were to get the "sizeof dwValue" of a dword variable, it would yield 4
lengthof gives you the number of elements
sizeof gives you the number of bytes
it makes little difference in this case, but if i were to modify the program for UNICODE, i'd have a bug
the WriteFile function wants the "number of bytes", not the "number of characters"
in that case, "sizeof" would be more appropriate
Oh thanks, really, I don't know how to thank you... Precious tips! But still with the same problem, but now the first number is not repeated in the second request... The program only shows the second request and ends, doesn't wait the input!
The code is:
include \masm32\include\masm32rt.inc
.data
msg1 BYTE "Insert a number:"
msg2 BYTE "The sum is:"
.data?
oHandle DWORD ?
iHandle DWORD ?
writeLen1 DWORD ?
writeLen2 DWORD ?
bufferLen1 DWORD ?
bufferLen2 DWORD ?
buffer1 BYTE ?
buffer2 BYTE ?
.code
start:
invoke GetStdHandle, STD_OUTPUT_HANDLE
mov oHandle, eax
invoke GetStdHandle, STD_INPUT_HANDLE
mov iHandle, eax
invoke WriteConsole, oHandle, addr msg1, lengthof msg1, addr writeLen1, NULL
invoke ReadConsole, iHandle, addr buffer1, 2, addr bufferLen1, NULL
invoke WriteConsole, oHandle, addr msg1, lengthof msg1, addr writeLen2, NULL
invoke ReadConsole, iHandle, addr buffer2, 2, addr bufferLen2, NULL
invoke ExitProcess, 0
end start
Sorry for being annoying, I really want to learn Assembly from the basic to the advanced (maybe even create an OS hohoho :lol:)
ok - that time, you are reading 2 bytes into 1 byte buffers
ohh... :redface: not resolved switch for reading one byte...
well - i didn't notice that you were using WriteConsole/ReadConsole
i would typically use WriteFile/ReadFile
give me a minute to play with it....
Both API functions are producing the same problem... Doesn't matter if I use WriteFile/ReadFile or WriteConsole/ReadConsole, in both cases the second Read function is ignored!
yah - i understand what's happening - sort of - lol
the buffer is 1 char long
but, when you enter a value, you are entering a char, plus the carriage return :P
another problem arises because the ReadFile function does not limit the number of characters entered
so - if you have a buffer of 2 chars and enter 10, those extra characters are still in the buffer
the next time you call ReadFile, poof - those extra characters are sitting there, waiting - lol
you can set up the standard input device so that doesn't happen
invoke SetConsoleMode,hStdInp,ENABLE_LINE_INPUT or ENABLE_ECHO_INPUT or ENABLE_PROCESSED_INPUT
once at the beginning of the program
then use ReadFile and WriteFile in preference to ReadConsole and WriteConsole
Quote from: dedndave on April 09, 2013, 05:43:57 AM
but, when you enter a value, you are entering a char, plus the carriage return :P
Yep!
buffer1 BYTE 100 dup(?)
buffer2 BYTE 100 dup(?)
.code
start:
invoke GetStdHandle, STD_OUTPUT_HANDLE
mov oHandle, eax
invoke GetStdHandle, STD_INPUT_HANDLE
mov iHandle, eax
invoke WriteConsole, oHandle, addr msg1, lengthof msg1, addr writeLen1, NULL
invoke ReadConsole, iHandle, addr buffer1, 100, addr bufferLen1, NULL
invoke WriteConsole, oHandle, addr msg1, lengthof msg1, addr writeLen2, NULL
invoke ReadConsole, iHandle, addr buffer2, 100, addr bufferLen2, NULL
also - make the buffer n+1 length
in other words, pass the (buffer length-1) to the function
i did the above and it still acts strangely :lol:
let me fix it.....
Very strange, with the way of jj2007 works well, but... 100 bytes buffer to do this?
yah - you should be able to use a smaller buffer and specify it's length
i must be doing something wrong, here
here is the test program i am using
in this case, i added 3 extra bytes to the buffer and passed a length 3 less
it acts as though the input buffer is not being emptied by ReadFile
;###############################################################################################
.XCREF
.NoList
INCLUDE \Masm32\Include\Masm32rt.inc
.List
;###############################################################################################
.DATA
msg1 BYTE "Insert a number: "
msg2 BYTE "The sum is: "
CrLf BYTE 13,10
;***********************************************************************************************
.DATA?
oHandle DWORD ?
iHandle DWORD ?
RdWrBytes DWORD ?
buffer1 BYTE 4 dup(?)
buffer2 BYTE 4 dup(?)
;###############################################################################################
.CODE
;***********************************************************************************************
_main PROC
invoke GetStdHandle, STD_OUTPUT_HANDLE
mov oHandle, eax
invoke GetStdHandle, STD_INPUT_HANDLE
mov iHandle, eax
invoke SetConsoleMode,iHandle,ENABLE_LINE_INPUT or ENABLE_ECHO_INPUT or ENABLE_PROCESSED_INPUT
invoke WriteFile, oHandle, addr msg1, sizeof msg1, addr RdWrBytes, NULL
invoke ReadFile, iHandle, addr buffer1, sizeof buffer1-3, addr RdWrBytes, NULL
invoke WriteFile, oHandle, addr msg1, sizeof msg1, addr RdWrBytes, NULL
invoke ReadFile, iHandle, addr buffer2, sizeof buffer2-3, addr RdWrBytes, NULL
invoke WriteFile, oHandle, addr buffer1, sizeof buffer1-3, addr RdWrBytes, NULL
invoke WriteFile, oHandle, addr CrLf, sizeof CrLf, addr RdWrBytes, NULL
invoke WriteFile, oHandle, addr buffer2, sizeof buffer2-3, addr RdWrBytes, NULL
invoke WriteFile, oHandle, addr CrLf, sizeof CrLf, addr RdWrBytes, NULL
INVOKE ExitProcess,0
_main ENDP
;###############################################################################################
END _main
I'm searching and I can not find any similar case, this is getting weirder........ :icon_confused:
it maybe simpler for you to use the C runtime library (CRT) for console IO, instead of that raw input method.
include \masm32\include\masm32rt.inc
.const
frmt1 CHAR "%d",0
sz0 CHAR "calculates C = A+B whereas A, B and C are signed integers",13,10
CHAR "A = ",0
sz1 CHAR "B = ",0
frmt2 CHAR "C = %d",13,10,0
.code
main proc
LOCAL value1:SDWORD,value2:SDWORD
invoke crt_printf,OFFSET sz0
invoke crt_scanf,OFFSET frmt1,ADDR value1
invoke crt_printf,OFFSET sz1
invoke crt_scanf,OFFSET frmt1,ADDR value2
mov eax,value1
add eax,value2
invoke crt_printf,OFFSET frmt2,eax
inkey
exit
main endp
end main
Remarks that the CRT functions are prefixed by "crt_" in the MASM32 package.
Yeap, but I want to use direct the Win32 API :S
I still look for a solution, but it's complicated. :(
Quote from: demondoido on April 09, 2013, 08:35:45 AM
I still look for a solution, but it's complicated. :(
You should move your focus on assembler programming and not waste your time by implementing boring console IO by hand.
;__UNICODE__ EQU 1
include \masm32\include\masm32rt.inc
TCHR macro lbl,args:VARARG
IFDEF __UNICODE__
UCSTR lbl,args
ELSE
lbl CHAR args
ENDIF
endm
.const
TCHR szNewLine,13,10,0
.code
;return: SDWORD
tchr2sdword proc uses esi pszBuffer: ptr TCHAR
LOCAL bSigned:BOOL
mov bSigned,FALSE
mov esi,pszBuffer
xor ecx,ecx
xor eax,eax
movzx edx,TCHAR ptr [esi]
.if edx == '-'
mov bSigned,TRUE
inc ecx
.elseif edx == '+'
inc ecx
.endif
.while 1
movzx edx,TCHAR ptr [esi+ecx*TCHAR]
.break .if edx != 20h && edx != 9
inc ecx
.endw
.while 1
movzx edx,TCHAR ptr [esi+ecx*TCHAR]
.break .if !edx || ecx > 10
imul eax,10
lea eax,[eax+edx-'0']
inc ecx
.endw
.if bSigned
neg eax
.endif
ret
tchr2sdword endp
; return: BOOL
readLine proc pszBuffer: ptr TCHAR,cc:DWORD
LOCAL hStdIn:HANDLE
LOCAL NumberOfCharsRead:DWORD
mov hStdIn,rv(GetStdHandle,STD_INPUT_HANDLE)
invoke SetConsoleMode,hStdIn,ENABLE_LINE_INPUT or ENABLE_ECHO_INPUT or ENABLE_PROCESSED_INPUT
.if rv(ReadConsole,hStdIn,pszBuffer,cc,ADDR NumberOfCharsRead,0) && NumberOfCharsRead
mov edx,pszBuffer
xor ecx,ecx
.while ecx < NumberOfCharsRead
.if TCHAR ptr [edx+ecx*TCHAR] == 13
mov TCHAR ptr [edx+ecx*TCHAR],0
.break
.endif
inc ecx
.endw
mov eax,TRUE
.else
xor eax,eax
.endif
ret
readLine endp
; return: BOOL
printTStr proc pszTStr:ptr TCHAR,bCRLF:BOOL
LOCAL hStdOut:HANDLE
LOCAL NumberOfCharsWrite:DWORD
mov hStdOut,rv(GetStdHandle,STD_OUTPUT_HANDLE)
invoke SetConsoleMode,hStdOut,ENABLE_PROCESSED_OUTPUT or ENABLE_WRAP_AT_EOL_OUTPUT
mov edx,rv(lstrlen,pszTStr)
invoke WriteConsole,hStdOut,pszTStr,edx,ADDR NumberOfCharsWrite,0
.if bCRLF
invoke WriteConsole,hStdOut,ADDR szNewLine,2,ADDR NumberOfCharsWrite,0
.endif
ret
printTStr endp
main proc
LOCAL value1:SDWORD
LOCAL sz[256]:TCHAR
.repeat
fn printTStr,"A = ",FALSE
.break .if !rv(readLine,ADDR sz,LENGTHOF sz)
invoke tchr2sdword,ADDR sz
mov value1,eax
fn printTStr,"B = ",FALSE
.break .if !rv(readLine,ADDR sz,LENGTHOF sz)
invoke tchr2sdword,ADDR sz
add eax,value1
fn wsprintf,ADDR sz,"C = %d",eax ; WinAPI ;-)
invoke printTStr,ADDR sz,TRUE
;inkey
.until 1
invoke ExitProcess,0
main endp
end main
i agree - there's no real need to have a perfect console app
the console is buggish, by nature
however, we should be able to limit line input to some specified length
it shouldn't be that difficult - lol
here is what i'm thinking
when we SetConsoleMode, turn off the ENABLE_LINE_INPUT bit
then, we use ReadFile to read individual bytes until
a) the buffer is full
b) carriage return is detected
i'll play with this some more tomorrow
i had a little time to play today - not as much as i had hoped :(
we are in the middle of doing repairs on my sister's house, and it rained last night
made for an interesting evening
at any rate.....
this has been an educational little experience - lol
as far as using Write/Read File/Console, we have typically used the File functions in the past
but, if you want to write UNICODE aware routines,
i would have to say that WriteConsole and ReadConsole make the transition a little smoother
they deal with
character counts, whereas the File functions deal with
byte counts
the masm32 stdin functions use ReadFile for ANSI and ReadConsole for UNICODE
with a little adjustment, it may be best to use ReadConsole and make a single routine for both
the problem concerning line input, where the function does not limit the character count......
this problem occurs because we normally run with the ENABLE_LINE_INPUT mode bit set
that is how we are able to use ENABLE_ECHO_INPUT
we also typically use ENABLE_PROCESSED_INPUT
QuoteENABLE_ECHO_INPUT
Characters read by the ReadFile or ReadConsole function are written to the active screen buffer
as they are read. This mode can be used only if the ENABLE_LINE_INPUT mode is also enabled.
ENABLE_LINE_INPUT
The ReadFile or ReadConsole function returns only when a carriage return character is read.
If this mode is disabled, the functions return when one or more characters are available.
ENABLE_PROCESSED_INPUT
CTRL+C is processed by the system and is not placed in the input buffer. If the input buffer is
being read by ReadFile or ReadConsole, other control keys are processed by the system and
are not returned in the ReadFile or ReadConsole buffer. If the ENABLE_LINE_INPUT mode is
also enabled, backspace, carriage return, and line feed characters are handled by the system.
it's like a domino effect of caveats - lol
if you look at the masm32 package StdIn routines,
(\Masm32\M32Lib\stdin.asm and \Masm32\M32Lib\stdinW.asm)
you will see that the input mode is set as mentioned above
what i am just now learning is that "the console mode" is actually 2 different "console modes"
you'd think i would have figured that out, long ago :lol:
actually, i guess i knew it, but didn't realize the impact
and, i am also learning that the mode set for hStdOut affects the behaviour of hStdInp :redface:
QuoteENABLE_PROCESSED_OUTPUT
Characters written by the WriteFile or WriteConsole function or echoed by the ReadFile or
ReadConsole function are examined for ASCII control sequences and the correct action is
performed. Backspace, tab, bell, carriage return, and line feed characters are processed.
ENABLE_WRAP_AT_EOL_OUTPUT
When writing with WriteFile or WriteConsole or echoing with ReadFile or ReadConsole,
the cursor moves to the beginning of the next row when it reaches the end of the current
row. This causes the rows displayed in the console window to scroll up automatically
when the cursor advances beyond the last row in the window. It also causes the contents
of the console screen buffer to scroll up (discarding the top row of the console screen buffer)
when the cursor advances beyond the last row in the console screen buffer. If this mode is
disabled, the last character in the row is overwritten with any subsequent characters.
more domino caveats
actually, the descriptions are incomplete and a little inaccurate
they do not mention the behaviour of the left and right arrow keys
and, the input buffer ENABLE_INSERT_MODE seems to be enabled even when the bit is cleared
also true of some of the mouse stuff
so, when we read input, we really ought to be controlling the standard output mode, as well
after playing around with the different mode combinations, i have come to the conclusion
that the best way to go is to turn off ENABLE_LINE_INPUT and ENABLE_ECHO_INPUT,
and write your own code to handle the echo and cursor control stuff
this allows you to control the line length according to buffer size (a la DOS buffered input)
a bit more code - but we get more control over the behaviour - not that bad
on the bright side, the input buffer mode doesn't seem to affect the write functions :biggrin:
tomorrow, i should have a little time to write a set of routines
here is a UNICODE aware ConOut routine
ConOut PROTO :LPVOID,:DWORD
;***********************************************************************************************
ConOut PROC USES EBX lpBuffer:LPVOID,nChars:DWORD
;UNICODE aware ConOut routine - DednDave, 4-2013
;--------------------------------------------
LOCAL dwOrigModeOut :DWORD
LOCAL nNumberOfCharsWritten :DWORD
;--------------------------------------------
INVOKE GetStdHandle,STD_OUTPUT_HANDLE
xchg eax,ebx
INVOKE GetConsoleMode,ebx,addr dwOrigModeOut
mov edx,ENABLE_PROCESSED_OUTPUT or ENABLE_WRAP_AT_EOL_OUTPUT
.if edx!=dwOrigModeOut
INVOKE SetConsoleMode,ebx,edx
.endif
xor ecx,ecx
mov nNumberOfCharsWritten,ecx
INVOKE WriteConsole,ebx,lpBuffer,nChars,addr nNumberOfCharsWritten,ecx
mov edx,dwOrigModeOut
.if edx!=(ENABLE_PROCESSED_OUTPUT or ENABLE_WRAP_AT_EOL_OUTPUT)
INVOKE SetConsoleMode,ebx,edx
.endif
mov eax,nNumberOfCharsWritten
ret
ConOut ENDP
;***********************************************************************************************
EDIT: modified so it gets standard handle - a reasonably fast API
EDIT: corrected syntax error "or" was "||"
Good work, Dave. Thank you. :t
Gunther
Wow, you're amazing... Perfect!
thanks Gunther
and thanks Doido :P
i don't know about "amazing", though - lol
you can use that routine with INVOKE
put the prototype near the beginning of the source file
INVOKE ConOut,offset sString,lengthof sString
i also like to use qWord's macro to define ANSI/UNICODE strings
;tchr macro by qWord
tchr MACRO lbl,args:VARARG
IFDEF __UNICODE__
UCSTR lbl,args
ELSE
lbl db args
ENDIF
ENDM
then, before the INCLUDE line, you can define the symbol __UNICODE__
with an equate to build a UNICODE version of the program
by commenting it out, you can build the ANSI version
when i get finished with the ConInp routine, i'll post an example
Thank you Dave. A clean and clear solution.
Gunther
It should be mention that Read/WriteConsole only works with console input/output screen buffers. For pipes and files the function fails (e.g. redirection). The "correct" code is more complicated and that why we should simply use the CRT...
that may be true for pipes
but, how often do we want a function that simply gets a string from the user ?
i actually prefer using the CRT for keyboard input, but we should be able to program around the API, too - lol
Dave,
Quote from: dedndave on April 11, 2013, 05:40:48 AM
that may be true for pipes
but, how often do we want a function that simply gets a string from the user ?
i actually prefer using the CRT for keyboard input, but we should be able to program around the API, too - lol
I agree with you. On the other hand, qWord isn't wrong. For the beginners it's not easy to distinguish the essential from the inessential.
Gunther
:biggrin:
long ago, i reported some buggish behaviour of the console window
http://www.masmforum.com/board/index.php?topic=11927.msg90572#msg90572 (http://www.masmforum.com/board/index.php?topic=11927.msg90572#msg90572)
using the CRT input functions seems to help those problems a little, but not completely
at one time, i debugged into the CRT getch function - it is a very involved routine - lol
the guys at ms have been working on improving the CRT for a long time
so - it's probably as good as it gets
even so, i am always interested in learning more about the specifics of console behaviour
but, if i want something to work in a half-way predictable manner, i write a GUI app 8)
wellllll
i have finally finished analyzing the edit keys - lol
along the way, i discovered a little undocumented fact of line edit modes with ReadConsole and ReadFile
these functions only allow a line length of 254 characters, plus the enter key
so - the simple way to use them is to use a buffer length of 256 chars :t
still, that doesn't allow you to limit the line length to, say, 10 characters or something
Years back I've written the following function, which limits the input by processing the console events retuned by ReadConsoleInput():
;__UNICODE__ EQU 1
include \masm32\include\masm32rt.inc
.686
TCCHR macro lbl,args:VARARG
IFDEF __UNICODE__
UCCSTR lbl,args
ELSE
?cstr? lbl,args
ENDIF
endm
ReadConsoleTimeOut proto psz:ptr TCHAR,cc:DWORD,dwTimeOut:DWORD
IsValidTChar proto TChar:DWORD
TStrCopyN proto pDest:ptr TCHAR,ccDest:DWORD,pszSrc:ptr TCHAR,ccSrc:DWORD
TStrCat proto pBuffer:DWORD,ccBuffer:DWORD,psz1:DWORD,psz2:DWORD
.code
main proc
LOCAL sz[256]:TCHAR
print "enter up to 10 characters: "
invoke ReadConsoleTimeOut,ADDR sz,11,INFINITE
print "your input: ",%'<'
print ADDR sz,%'>'
print chr$(13,10)
print "enter up to 128 characters: "
invoke ReadConsoleTimeOut,ADDR sz,129,INFINITE
print ADDR sz,13,10
print "your input: ",%'<'
print ADDR sz,%'>'
print chr$(13,10)
inkey
exit
main endp
ReadConsoleTimeOut proc uses edi esi ebx psz:ptr TCHAR,cc:DWORD,dwTimeOut:DWORD
LOCAL hStdIn:HANDLE
LOCAL hStdOut:HANDLE
LOCAL pBuffer:ptr TCHAR
LOCAL nEvents:DWORD
LOCAL ticks:DWORD
LOCAL csbi:CONSOLE_SCREEN_BUFFER_INFO
LOCAL ir[10]:INPUT_RECORD
mov eax,psz
mov TCHAR ptr [eax],0
.if !cc
ret
.endif
mov edx,cc
lea edx,[edx*TCHAR]
.if !rvx(pBuffer = GlobalAlloc,GPTR,edx)
ret
.endif
mov hStdIn,rv(GetStdHandle,STD_INPUT_HANDLE)
mov hStdOut,rv(GetStdHandle,STD_OUTPUT_HANDLE)
.if dwTimeOut != INFINITE
mov ticks,rv(GetTickCount)
.endif
xor edi,edi
xor esi,esi
.while 1
.break .if rv(WaitForSingleObject,hStdIn,dwTimeOut) == WAIT_FAILED || eax == WAIT_TIMEOUT
.if dwTimeOut != INFINITE
mov edx,rv(GetTickCount)
sub edx,ticks
.break .if edx > dwTimeOut
sub dwTimeOut,edx
mov ticks,eax
.endif
lea ebx,ir
assume ebx: ptr INPUT_RECORD
.break .if !rv(ReadConsoleInput,hStdIn,ebx,LENGTHOF ir,&nEvents)
.while nEvents != 0
.if [ebx].EventType == KEY_EVENT && [ebx].KeyEvent.bKeyDown
fn GetConsoleScreenBufferInfo,hStdOut,&csbi
movzx edx,[ebx].KeyEvent.wVirtualKeyCode
.if edx == VK_RETURN || edx == VK_ESCAPE
jmp _exit
.elseif edx == VK_BACK
@@: .if edi > 0
.if csbi.dwCursorPosition.x > 0
sub csbi.dwCursorPosition.x,1
.else
.if csbi.dwCursorPosition.y > 0
sub csbi.dwCursorPosition.y,1
movzx eax,csbi.dwSize.x
sub eax,1
mov csbi.dwCursorPosition.x,ax
.endif
.endif
invoke SetConsoleCursorPosition,hStdOut,DWORD ptr csbi.dwCursorPosition
dec edi
jmp @F
.endif
.elseif edx == VK_DELETE
@@: .if edi < esi
mov edx,psz
lea edx,[edx+edi*TCHAR]
mov TCHAR ptr [edx],0
lea eax,[edx+TCHAR]
invoke TStrCat,psz,cc,psz,eax
mov ecx,eax
sub ecx,edi
invoke WriteConsole,hStdOut,edx,ecx,0,0
fn WriteConsole,hStdOut," ",1,0,0
invoke SetConsoleCursorPosition,hStdOut,DWORD ptr csbi.dwCursorPosition
sub esi,1
.endif
.elseif edx == VK_LEFT
.if edi > 0
.if csbi.dwCursorPosition.x > 0
sub csbi.dwCursorPosition.x,1
.else
.if csbi.dwCursorPosition.y > 0
sub csbi.dwCursorPosition.y,1
mov ax,csbi.dwSize.x
dec ax
mov csbi.dwCursorPosition.x,ax
.endif
.endif
invoke SetConsoleCursorPosition,hStdOut,DWORD ptr csbi.dwCursorPosition
sub edi,1
.endif
.elseif edx == VK_RIGHT
.if edi < esi
movzx eax,csbi.dwSize.x
sub eax,1
.if csbi.dwCursorPosition.x >= ax
mov csbi.dwCursorPosition.x,0
add csbi.dwCursorPosition.y,1
.else
add csbi.dwCursorPosition.x,1
.endif
invoke SetConsoleCursorPosition,hStdOut,DWORD ptr csbi.dwCursorPosition
add edi,1
.endif
.else
lea edx,[esi+1]
movzx ecx,[ebx].KeyEvent.UnicodeChar
.if edx < cc && rv(IsValidTChar,ecx)
mov edx,psz
lea eax,[edx+edi*TCHAR]
invoke TStrCopyN,pBuffer,cc,eax,-1
movzx ecx,TCHAR ptr [ebx].KeyEvent.UnicodeChar
mov WORD ptr [edx+edi*TCHAR],cx
mov WORD ptr [edx+edi*TCHAR+TCHAR],0
mov esi,rv(TStrCat,psz,cc,psz,pBuffer)
sub eax,edi
lea edx,[edx+edi*TCHAR]
invoke WriteConsole,hStdOut,edx,eax,0,0
add edi,1
movzx edx,csbi.dwSize.x
sub edx,1
.if csbi.dwCursorPosition.x >= dx
mov csbi.dwCursorPosition.x,0
add csbi.dwCursorPosition.y,1
.else
add csbi.dwCursorPosition.x,1
.endif
invoke SetConsoleCursorPosition,hStdOut,DWORD ptr csbi.dwCursorPosition
.endif
.endif
.endif
add ebx,INPUT_RECORD
dec nEvents
.endw
.endw
_exit:
invoke GlobalFree,pBuffer
fn WriteConsole,hStdOut,chr$(13,10),2,0,0
mov eax,esi
ret
ReadConsoleTimeOut endp
; OUT: valid if eax > 0
IsValidTChar proc uses edx ecx TChar:DWORD
.const
TCCHR ValidCharT," \t.,:;\x-_#'\q+-*/\\?{}\a\b[]&\p$\r\l|^~´`=@"
.code
.if rv(IsCharAlphaNumeric,TChar)
ret
.endif
and TChar,0ffffh
mov edx,OFFSET ValidCharT
movzx eax,TCHAR ptr [edx]
.while eax != 0
lea edx,[edx+TCHAR]
.break .if eax == TChar
movzx eax,TCHAR ptr [edx]
.endw
ret
IsValidTChar endp
TStrCopyN proc uses ecx edx ebx edi esi pDest:ptr TCHAR,ccDest:DWORD,pszSrc:ptr TCHAR,ccSrc:DWORD
LOCAL cc:DWORD
mov edx,pDest
mov ecx,ccDest
mov eax,pszSrc
mov cc,0
.repeat
sub ecx,1 ; for termination zero
.break .if ZERO?
test ccSrc,-1
.break .if ZERO?
.repeat
movzx ebx,TCHAR ptr [eax]
test ebx,ebx
.break .if ZERO?
IFDEF __UNICODE__
mov TCHAR ptr [edx],bx
ELSE
mov TCHAR ptr [edx],bl
ENDIF
lea eax,[eax+TCHAR]
lea edx,[edx+TCHAR]
add cc,1
sub ccSrc,1
.break .if ZERO?
sub ecx,1
.until ZERO?
.until 1
mov TCHAR ptr [edx],0
mov eax,cc
ret
TStrCopyN endp
TStrCat proc uses ecx edx ebx edi esi pBuffer:DWORD,ccBuffer:DWORD,psz1:DWORD,psz2:DWORD
mov edi,pBuffer
mov ecx,ccBuffer
mov esi,psz1
mov edx,psz2
mov eax,1
mov ccBuffer,0
sub ecx,1 ; for termination-zero
jz _exit
_begin:
movzx ebx,TCHAR ptr [esi]
test ebx,ebx
jz @F
IFDEF __UNICODE__
mov TCHAR ptr [edi],bx
ELSE
mov TCHAR ptr [edi],bl
ENDIF
lea edi,[edi+TCHAR]
lea esi,[esi+TCHAR]
inc ccBuffer
sub ecx,1
jz _exit
jmp _begin
@@:
test eax,eax
cmovnz eax,ebx
cmovnz esi,edx
jnz _begin
_exit:
mov TCHAR ptr [edi],0
mov eax,ccBuffer
ret
TStrCat endp
end main
interesting code, qWord
i have something similar in mind, but i had no intention of providing a timeout - lol
the basic form i am using looks like this...
.repeat
.repeat
INVOKE ReadConsoleInput,hStdInp,addr ir,1,addr uRecCnt
movzx edx,word ptr ir.EventType
.until (edx==KEY_EVENT) && (edx==ir.KeyEvent.bKeyDown)
movzx eax,word ptr ir.KeyEvent.UnicodeChar
mov ecx,ir.KeyEvent.dwControlKeyState
movzx edx,word ptr ir.KeyEvent.wVirtualKeyCode
; .if
; .elseif
; .elseif handle line input and edit keys here
; .elseif
; .endif
.until (ax==VK_RETURN) && !(cx&(LEFT_CTRL_PRESSED or RIGHT_CTRL_PRESSED or LEFT_ALT_PRESSED or RIGHT_ALT_PRESSED))
Quote from: dedndave on April 13, 2013, 12:44:12 AMbut i had no intention of providing a timeout
removing that few extra lines should be no problem for anyone ;)
you know me - i like to write my own stuff :P
i am not much of a script kiddie
here are some operations i found - couple of them i wasn't aware of
line edit supports these keys:
backspace, tab, enter, insert, delete, home, end, left/right cursor
combinations:
ctrl left/right arrow - moves cursor to first/last character
ctrl home - removes all characters preceeding the cursor
ctrl end - removes all characters from cursor to end of line
i didn't play with all the key combinations - there might be an "undo" somewhere :P
or - there could be
Quote from: dedndave on April 13, 2013, 02:28:48 AM
i didn't play with all the key combinations - there might be an "undo" somewhere :P
or - there could be
Ctrl Z doesn't work, and SetConsoleCtrlHandler concerns only special keys like Ctrl C and Ctrl Break. If you are really keen on undo, handle Ctrl Break...
ctrl-z is normally used to generate an EOF (SUB char)
ctrl-c and ctrl-break should exit/abort
i can make that happen, if i want to
but, my thinking was that the guy might have some ctrl handler in place to handle log off or shut down
i doubt there is an undo in the console - lol
but, we could add our own
i was thinking maybe one of the function keys, perhaps with ctrl or alt
in this first set of routines, i use a ConIn256 routine that assumes a buffer length of 256 TCHAR's
that makes it simple
in the attachment are both ANSI and UNICODE builds
any problem reports appreciated :P