Hi
I have troubles trying to read only one char from the console.
When I type a char and press enter, the console input buffer stores
the first char and the CR and LF chars too.
I want to read only the first char, not the rest of the line.
So, I use the FlushConsoleInputBuffer function to remove the CR and LF
chars from the console buffer, but the CR and LF chars are still there, Why?
LENBUFFER=1
.data
buffer db LENBUFFER+1 dup(0)
readBytes dd ?
hConInput HANDLE ?
.code
start:
push 0
call SetLastError
push STD_INPUT_HANDLE
call GetStdHandle
mov hConInput,eax
readChar:
call Crlf ; print a CRLF
mWrite "(0 to quit) Give me a char: " ; macro to print text
push 0
push offset readBytes
push 1 ; read only the first char
push offset buffer
push hConInput
call ReadConsole
cmp eax,0
je error
cmp byte ptr[buffer],30h ; stop condition
je exit
mov edx,offset buffer
call WriteString ; print the stored char
push hConInput
call FlushConsoleInputBuffer ; remove remaining chars
cmp eax,0
je error
jmp readChar ; read another char
error:
call WriteWindowsMsg ; print error messages
exit:
push 0
call ExitProcess
end start
the carriage return signifies the "end of file" for the console
the console window is buggish - lol
the best results i have seen for this type of keyboard input is to use the CRT functions
here is a routine that i use and a program showing how it might be used
.XCREF
.NOLIST
INCLUDE \masm32\include\masm32rt.inc
.LIST
;#########################################################################
.CODE
;*************************************************************************
_main PROC
print chr$('Press Esc to Exit'),13,10
jmp short kloop2
kloop1: INVOKE Sleep,40
kloop2: call InKyb
jz kloop1
push eax
cmp ah,0
jz kloop3
push 2020h
jmp short kloop4
kloop3: mov ah,20h
push eax
kloop4: print esp
pop edx
pop eax
push eax
print right$(uhex$(eax),4),13,10
pop eax
cmp eax,1Bh
jnz kloop2
exit
_main ENDP
;*************************************************************************
InKyb PROC
;Polled Keyboard Input - DednDave 8, 2010
;
;This function returns a keystroke in EAX if there is one in the buffer.
;If the buffer is empty, the function returns immediately.
;
;If the keyboard buffer is empty, AH = 0, AL = 0, ZF = 1.
;If the stroke is a regular key, AH = 0, AL = key char, ZF = 0.
;If the stroke is an extended key, AH = extended key, AL = E0h, ZF = 0.
;If the stroke is a function key, AH = function key, AL = 0, ZF = 0.
;
;ECX, EDX are not preserved.
call crt__kbhit
or eax,eax
jz InKyb1
call crt__getch
and eax,0FFh
jz InKyb0
cmp al,0E0h
jnz InKyb1
InKyb0: push eax
call crt__getch
pop edx
shl eax,8
or eax,edx
InKyb1: retn
InKyb ENDP
;#########################################################################
END _main
---
If its only one byte you are after and you want to use the API instead of the C runtime function, why not just read the first byte and ignore the trailing CR LF ?
Modify according to your needs (if you prefer it complicated, use PeekConsoleInput or ReadConsoleInput).
include \masm32\include\masm32rt.inc
.code
start:
.While 1
getkey
.Break .if eax==13 ; Cr aka Return
push eax
print esp
pop eax
.Endw
exit
end start
Here is the Unicode version, for use with e.g. the €uro key or exotic keyboards:
include \masm32\MasmBasic\MasmBasic.inc ; download (http://www.masm32.com/board/index.php?topic=94.0)
.code
start:
.While 1
Inkey
.Break .if eax==13 ; Cr aka Return
push eax ; create a buffer and fill it with one zero-delimited byte
wPrint esp
pop eax
.Endw
exit
end start
Quote
I have troubles trying to read only one char from the console.
When I type a char and press enter, the console input buffer stores
the first char and the CR and LF chars too
The _getch function do that
Quote
Gets a character from the console without echo.
int _getch( void );
wint_t _getwch( void );
Return Value
Returns the character read. There is no error return.
Remarks
The _getch and_getwch functions read a single character from the console without echoing the character. None of these functions can be used to read CTRL+C. When reading a function key or an arrow key, each function must be called twice; the first call returns 0 or 0xE0, and the second call returns the actual key code
Quote from: hutch-- on October 20, 2012, 04:14:43 PM
If its only one byte you are after and you want to use the API instead of the C runtime function, why not just read the first byte and ignore the trailing CR LF ?
I can't ignore the trailing CR LF because I need read from the console more than once.
This tends to become in a return of this forum
http://www.programmersheaven.com/mb/windows/265472/265484/re-problem-with-console-app/?S=B20000 (http://www.programmersheaven.com/mb/windows/265472/265484/re-problem-with-console-app/?S=B20000)
I have the same problem, but in assembly language.
By the way, the last answer in that forum didn't work for me.
Looks like the FlushConsoleInputBuffer function doesn't work really.
It's that right?
one solution might be....
write a routine that reads all the bytes into a buffer
then, parse the buffer, converting the first carriage return or line feed into a null (0) byte
that way, the routine always returns a null-terminated string with the cr/lf stripped off
the function can be used for single-char or multiple-char keyboard entry
another way to go...
if you want a single key only, you can use something like this...
;*************************************************************************************************************
AnyKey PROC
;Wait for Any Console Key Press - DednDave 12-2011
;
; This function returns when any console key is pressed (bKeyDown = 1).
;A possible drawback is that all input event records are removed from
;the console input queue until a key is pressed. In many cases, this is
;not an issue. The virtual key code, virtual scan code, TCHAR character,
;and control key state values are returned in registers.
;Call With: Nothing
;
; Returns: EAX = TCHAR character (high word of EAX = 0)
; ECX = control key state flags
; Bit Name Meaning
; 0 RIGHT_ALT_PRESSED Right ALT key is pressed
; 1 LEFT_ALT_PRESSED Left ALT key is pressed
; 2 RIGHT_CTRL_PRESSED Right CTRL key is pressed
; 3 LEFT_CTRL_PRESSED Left CTRL key is pressed
; 4 SHIFT_PRESSED SHIFT key is pressed
; 5 NUMLOCK_ON NUM LOCK light is on
; 6 SCROLLLOCK_ON SCROLL LOCK light is on
; 7 CAPSLOCK_ON CAPS LOCK light is on
; 8 ENHANCED_KEY Key is enhanced
; EDX:
; low word (DX) = virtual key code
; high word = virtual scan code
;
; all other registers are preserved
push ebx
push ebp
sub esp,(sizeof INPUT_RECORD+3) and -4
mov ebp,esp
INVOKE GetStdHandle,STD_INPUT_HANDLE
xchg eax,ebx
push ecx
AnyKy0: INVOKE ReadConsoleInput,ebx,ebp,1,esp
movzx edx,word ptr [ebp].INPUT_RECORD.EventType
cmp edx,KEY_EVENT ;KEY_EVENT EQU 1
jnz AnyKy0
cmp edx,[ebp].INPUT_RECORD.KeyEvent.bKeyDown
jnz AnyKy0
pop ecx
movzx eax,word ptr [ebp].INPUT_RECORD.KeyEvent.UnicodeChar
mov edx,dword ptr [ebp].INPUT_RECORD.KeyEvent.wVirtualKeyCode
mov ecx,[ebp].INPUT_RECORD.KeyEvent.dwControlKeyState
add esp,(sizeof INPUT_RECORD+3) and -4
pop ebp
pop ebx
ret
AnyKey ENDP
;*************************************************************************************************************
personally, i prefer the crt method i showed in the earlier post :P
Quote from: dedndave on October 21, 2012, 03:58:58 AM
if you want a single key only, you can use something like this...
Looks complicated. What about SetConsoleMode() and resetting ENABLE_LINE_INPUT flag ( temporarily ).
it's not that bad - lol
i wrote that function because i wanted the state of the shift/alt/ctrl keys :P
it's also a synchronous function - which was what i needed for that case
i much prefer the asynchronous method using crt__kbhit and crt__getch as shown in my earlier post
it allows the program to do other things while there is no keystroke
also - the crt functions fix some issues caused by console window bugs that are difficult to deal with
Quote from: japheth on October 21, 2012, 04:30:16 AM
Looks complicated. What about SetConsoleMode() and resetting ENABLE_LINE_INPUT flag ( temporarily ).
I've already tried that and didn't work.
I'm going to use dedndave's approach, momentarily.
But I still want to know, why the function doesn't work?, what I'm doing wrong?
Quote
But I still want to know, why the function doesn't work?, what I'm doing
You just think that a function must run as you want.There is none in the full sdk who can do that.It's the usual mistake of all beginners.
Just use one and add code to adapt it to your need.
This works:
push STD_INPUT_HANDLE
call GetStdHandle
mov hConInput,eax
push eax
push edx ; create a slot
invoke GetConsoleMode, eax, esp
pop eax ; get current mode
and eax, NOT (ENABLE_LINE_INPUT or ENABLE_ECHO_INPUT)
pop edx
invoke SetConsoleMode, edx, eax
Note that MSDN (http://msdn.microsoft.com/en-us/library/windows/desktop/ms686033%28v=vs.85%29.aspx) is plain wrong here:
ENABLE_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.
Right is that setting ENABLE_ECHO_INPUT enables line input, too.
Quote from: ToutEnMasm on October 22, 2012, 03:16:20 AM
Quote
There is none in the full sdk who can do that.
You're missing something here. Read each one of the post from the beginning.
Thanks jj2007, the problem has been solved. :biggrin:
(but the doubt remains ::))
well - i think your original code would work, with a little change in flow
you do not provide a method for it to catch the carriage return
you might, for example, return 0 in EAX if it is a carriage return or a 1 if otherwise
then, it could be tested in the calling procedure, and not displayed