News:

MASM32 SDK Description, downloads and other helpful links
MASM32.com New Forum Link
masmforum WebSite

Windows Console Input

Started by joemc, June 23, 2011, 06:36:17 PM

Previous topic - Next topic

joemc

i am actually using C++, but my question is language independent and more of a API question. 

I've tried searching for the answer in several different places, but i cant figure out the correct keywords to describe the question because they all all very common words related to windows console programming. Finally:

How would i ask for input with a default value. Ex:
"Name: Joe"

and you can press backspace up to "Name: "

Right now i am guessing i might just have to launch another thread, ask for input, and than the separate thread will just simulate the keypresses, that just does not sound ideal. anyone have done anything like this before?

Misc:
Target is windows 7 (Version 6.1.7600) but don't think anything related has changed in API for a long time.

dedndave

hi Joe
that's a good question - lol

i have never played with it, but you might try WriteConsoleInput

joemc

Thanks.  don't need a second thread works fine:


int WriteInput(std::string s)
{
static HANDLE hConIn = GetStdHandle(STD_INPUT_HANDLE);
std::vector <INPUT_RECORD> ir;
DWORD n=0;

ir.resize(s.size());

for ( unsigned int i=0 ; i < ir.size(); i++ )
{
ir[i].EventType = KEY_EVENT;
ir[i].Event.KeyEvent.bKeyDown = TRUE;
ir[i].Event.KeyEvent.dwControlKeyState = 0;
ir[i].Event.KeyEvent.uChar.UnicodeChar = s[i];
ir[i].Event.KeyEvent.wRepeatCount = 1;
ir[i].Event.KeyEvent.wVirtualKeyCode = s[i];
ir[i].Event.KeyEvent.wVirtualScanCode = MapVirtualKey(s[i], MAPVK_VK_TO_VSC);
}

WriteConsoleInput(hConIn,&ir[0],ir.size(),&n);

return 0;
}
int main()
{

WriteInput("Joe");
std::string x;
std::cout<< "Name: ";
std::cin>>x;
std::cout<<x;
return 0;
}

dedndave

spoken like a true C programmer   :P

joemc

Doesnt work with over 4 characters, oh well i figure something out. atleast in right direction now.

dedndave

i am guessing that is because the OS is only allowing 4 keys to be pressed at once
for each char in the string, you need 2 event structures - one for key down, one for key up
(i would build them on the stack in a loop, then spit them out)

i can foresee another issue that you may run into
that is - a real key event occurs
this could ball up the works pretty nicely   :P
although - the function is pretty fast
still, it might be prudent to flush the input buffer just before the WriteConsoleInput call

jj2007

Quote from: joemc on June 24, 2011, 04:49:19 PM
Doesnt work with over 4 characters, oh well i figure something out. atleast in right direction now.

Try the attachment :bg

Quoteinclude \masm32\MasmBasic\MasmBasic.inc   ; download
   Init
   Open "O", #1, "YourData.txt"
   PrintLine #1, Input$("Hobbies:\t",   "Assembler, ")   ; the prompt can contain a tab escape,
   PrintLine #1, Input$("Profession:\t",   "Programmer")   ; and you can define a prefilled string
   Close
   Print
"Bye"
   Delay 1000
   Exit
end start

dedndave

that Jochen guy is SUCH a show off   :P
i played with some code, but i must have a bug someplace
i may look at it again, tomorrow

joemc


push 0 ; looks unprofessional but it works better without MapVirtualKey

thanks :) works now

jj2007

Quote from: joemc on June 25, 2011, 07:56:08 AM

push 0 ; looks unprofessional but it works better without MapVirtualKey

thanks :) works now


Yeah, it took me a while to test this out. With MVK, behaviour was a bit erratic; and MSDN says it may return 0 if translation is not needed. Besides, even umlauts work fine with the current version, so I'll leave it "as is".

dedndave

that was my problem, as well
it is really strange that the only key-related member that needs to be set is "char"

;---------------------------------------------------------------------------------------------

ConInDefStr PROTO :DWORD,:DWORD,:DWORD,:DWORD

;---------------------------------------------------------------------------------------------

        OPTION  PROLOGUE:None
        OPTION  EPILOGUE:None

ConInDefStr PROC lpBuf:DWORD,dwLen:DWORD,szPrmptStr,szDefStr:DWORD

;Console Input with Prompt and Default Strings
;DednDave 6-2011
;
;Call With: lpBuf      = address of input buffer
;           dwLen      = length of input buffer, less 1 for the terminator
;           szPrmptStr = address of prompt string
;           szDefStr   = address of default input string
;
;  Returns: EAX        = length of user-input (buffer) string

;[EBP+28] = szDefStr
;[EBP+24] = szPrmtpStr
;[EBP+20] = dwLen
;[EBP+16] = lpBuf
;[EBP+12] = RET address
;[EBP+8]  = saved EBX value
;[EBP+4]  = saved ESI value
;[EBP]    = saved EBP value
;[EBP-4]  = standard input handle
;[EBP-8]  = length of default string

        push    ebx
        push    esi
        push    ebp
        mov     ebp,esp
        INVOKE  GetStdHandle,STD_INPUT_HANDLE
        push    eax                           ;[EBP-4] = standard input handle
        print   [ebp+24]                      ;szPrmptStr
        mov     esi,[ebp+28]                  ;szDefStr
        push    1
        INVOKE  StrLen,esi
        pop     ecx                           ;ECX = 1 (TRUE, KEY_EVENT, wRepeatCount)
        xor     edx,edx                       ;EDX = 0 (FALSE)
        push    eax                           ;[EBP-8] = length of szDefStr
        jmp short Cids01

Cids00: movzx   ebx,byte ptr [esi+eax]
        shl     ebx,16

;key up record

        push    edx                           ;KEY_EVENT_RECORD.dwControlKeyState = 0
        push    ebx                           ;KEY_EVENT_RECORD.wVirtualScanCode = 0, char = character
        push    ecx                           ;KEY_EVENT_RECORD.wRepeatCount = 1, wVirtualKeyCode = 0
        push    edx                           ;KEY_EVENT_RECORD.bKeyDown = FALSE (key up)
        push    ecx                           ;INPUT_RECORD.EventType = KEY_EVENT

;key down record

        push    edx                           ;KEY_EVENT_RECORD.dwControlKeyState = 0
        push    ebx                           ;KEY_EVENT_RECORD.wVirtualScanCode = 0, char = character
        push    ecx                           ;KEY_EVENT_RECORD.wRepeatCount = 1, wVirtualKeyCode = 0
        push    ecx                           ;KEY_EVENT_RECORD.bKeyDown = TRUE (key down)
        push    ecx                           ;INPUT_RECORD.EventType = KEY_EVENT

Cids01: dec     eax
        jns     Cids00

        INVOKE  FlushConsoleInputBuffer,[ebp-4]
        mov     eax,[ebp-8]
        mov     edx,esp
        shl     eax,1
        jz      Cids02

        push    ecx
        INVOKE  WriteConsoleInput,[ebp-4],edx,eax,esp
        pop     eax

Cids02: push    ecx
        mov     eax,esp
        INVOKE  ReadConsole,[ebp-4],[ebp+16],[ebp+20],eax,NULL
        pop     eax
        leave
        pop     esi
        pop     ebx
        ret     16

ConInDefStr ENDP

        OPTION  PROLOGUE:PrologueDef
        OPTION  EPILOGUE:EpilogueDef

;---------------------------------------------------------------------------------------------


attached is a demo program with source...

jj2007

One more - source (30 lines) will come tonight :bg

dedndave

 :bg
Hobbies:       Assembler
Profession:    Script Kiddie

These are your hobbies: [Assembler]
... and your profession is [Script Kiddie]

Write to MyData.txt (y) ?

jj2007

#13
Quoteinclude \masm32\MasmBasic\MasmBasic.inc   ; download
  Init
 
lea ebx, [4+Locate(y)]   ; get current Y position, add 4 lines
  xor ecx, ecx      ; flag "round 2 needed"
  .Repeat
   .if ecx
      Locate(0, ebx-1)   ; set position to column 0, row ebx-1
      PrintLine " Do not confuse hobby and profession, please!!", Chr$(7)      ; bark at user
   .endif
   Locate(0, ebx)   ; set position to column 0, row ebx
   Let esi="These are your hobbies: ["+Input$(" Hobbies:\t", "Assembler")+"]"
   Let edi=Input$(" Profession:\t", "Programmer")   ; prompts may contain tabs
   mov ecx, Instr_(edi, "program", 1)   ; check for bad words, 1=case-insensitive
  .Until !ecx
  Inkey CrLf$, esi, CrLf$, "... and your profession is [", edi, "]", CrLf$, CrLf$, "Write to MyData.txt (y) ? "
  .if al=="y"
   Open "A", #1, "MyData.txt"   ; append your strings to this file
   Print #1, esi, CrLf$, "Prof=", edi, CrLf$
   Close
  .endif
  Exit
end start

So it can be done in 22 lines :bg
(the bad news is you need at least MB version 30 June...)