carlos-montiers / enhancedbatch

Enhances your windows command prompt https://www.enhancedbatch.com
Other
5 stars 1 forks source link

Change caller KBHIT #37

Open carlos-montiers opened 4 years ago

carlos-montiers commented 4 years ago

I think is better rename the caller KBHIT to KBUFF and it should returns 0 if no key was pressed and 1 if yes.

adoxa commented 4 years ago

I would argue keeping KBHIT as the call, modify it to return 0 or 1 (more specifically, modify it to leave the key in the buffer) and rename KBHIT variable, since it does extract the key from the buffer (or also change it to 0/1 and leave the key in the buffer).

carlos-montiers commented 4 years ago

I'm not fan of leave keys in the buffer. What about KBEAT? It returns 1 if was possible eat a key :) else 0.

thus:

call KBEAT && set @next=
adoxa commented 4 years ago

That's really just GETKB. Hm, if you don't want to leave keys in the buffer how about KBFLUSH? 0 if the buffer was empty, 1 if it was made empty, removing all keys.

carlos-montiers commented 4 years ago

I agree on it, maybe also can be useful for some other things, like for example handle keyboard inputs, if you press many keys by seconds, like for example for videogame, in one second, get one key pressed in that second and clear all. What about provide other function for also get the last key in the buffer. Currently I don't know if getkb return the first or last key in the buffer, but if is the first, thus maybe will be useful get the last.

adoxa commented 4 years ago

So you want to flush all but the last? That's not really a flush.

carlos-montiers commented 4 years ago

I want flush all, but before I want have the capacity of read: the first key in the buffer or the last key in the buffer. Currently this that I'm commenting is other feature flush all will solve the issue

adoxa commented 4 years ago

Not everything has to be done within the extension.

set $key=-1
set $hit=@kbhit
for (not !$hit!==-1) do (
  set $key=!$hit!
  set $hit=@kbhit
)

What is the scenario where you need to keep the last key and discard the rest?

carlos-montiers commented 4 years ago

The scenario is this next:

I have a batch game loop of 1 second, thus I want update as max the position of some variable for example max 3 times by second. Suppose for example the classic worm game, the up key is pressed many times in this case each 50 ms, but before crash the left key us pressed. In the batch processing if I read only the 3 first keys from the buffer, I cannot read the last vital movement, because I'm reading the first and discarding the rest. If I not discard the key buffer, in the next iteration is possible get a enormous list of keys that should not be considered.

I not know how getch works if it return the first or the last key. I think is better have the possiblity of get the last key.

adoxa commented 4 years ago

If you're discarding any of the player's keys it sounds like your game logic is broken.

I don't know how to answer that without sounding snarky. Why would you think it gets the last key? Have you ever typed 123 and gotten 321?

carlos-montiers commented 4 years ago

Mmm, GETCH always get the first key from the buffer removing that key from it. Thus, I want an additional extension that allow me get the last key from the keyboard buffer and clean the buffer.

adoxa commented 4 years ago

See my earlier comment.

carlos-montiers commented 4 years ago

What about call SHIFTK // returns 1 if was possible read a key, else 0. ? I have this idea because in PUSHD and POPD, the D is for directory. In this case there are not a POP because the key is not the last, but the first, because that the shift word. the K is for KEY.

DaveBenham commented 4 years ago

adoxa wrote:

If you're discarding any of the player's keys it sounds like your game logic is broken.

I don't know how to answer that without sounding snarky. Why would you think it gets the last key? Have you ever typed 123 and gotten 321?

Actually I think there can be a very good reason to clear out the input buffer when developing something like my SNAKE.BAT game that uses multiple processes with asynchronous communication between them.

The user may input keys (actions) faster than the game can keep up. For example W to go up, followed by D to go right.

But upon the game processing the W input, some game event occurs that makes the D no longer valid (some collision might have occurred resulting in death)

The game might then want to prompt the user for what to do next. and the D (and any other keys in the buffer) might interfere. I would display the input prompt and then immediately clear the buffer prior to reading a response. That way I have confidence that the keys that I read are in response to my most recent prompt.

But I agree that a flush should be all or nothing - it should not flush all but the last key.

adoxa commented 4 years ago

SHIFTK sounds like you want the status of the shift key, so no, that's a bad name for testing if any key is pressed. The C kbhit only tests if a key is pressed or not, it was your idea to make it read the key as well.

carlos-montiers commented 4 years ago

Yes c khbit is as you mentions, but because the normal usage in a c game loop is if kbhit() { getch() }, kbhit usage is a way for read the keyboard input without block the thread, thus because almost all cases when the kbhit is true it is followed by getch, and because in batch is good save some lines for speed I thinked that is good read the key immediately for save batch lines of code, but maybe is needed choose other name for avoid confussion with the c function. Altough the EB getch is not like the c getch, because EB getch means get a character. What about rename the EB functions?: kbhit -> getnwkb chhit -> getnwch nw means no wait

and add: caller extension readkey // returns 1 if was possible read a key, else 0.

adoxa commented 4 years ago

Again, readkey is not a good name for determining if a key is available. How about:

getkey: wait for a key readkey: get a key if one is available peekkey: test if a key is available

Replace "key" with "char" for the character versions. Then there'd be flushkey(s) to discard all keys (no char version, as it's the same thing).

carlos-montiers commented 4 years ago

I agree on this last proposal. I think are really good names of functions.

carlos-montiers commented 4 years ago

@adoxa what about checkkey instead of peekkey. I get this name found in a book called "Jamsa's 1001 DOS and PC Tips" trick 318. It provides CHECKKEY.SRC for build CHECKKEY.COM using debug. Returns 1 if the user has pressed a key, else 0.

N CHECKKEY.COM
A 100
MOV AH,B
INT 21
AND AL,1
MOV AH,4C
INT 21

R CX
A
W
Q

I think is a good name, what do you think ?

adoxa commented 4 years ago

Peekkey combines both the current kbhit and checkkey, in that if there's no key it returns -1, otherwise the key, leaving it in the buffer. If you don't care about that checkkey would be a better name.

DaveBenham commented 4 years ago

I like the concept of PEEKKEY. If you don't care about the actual key value, PEEKKEY still can work just as efficiently as CHECKKEY. So it doesn't make sense to have both. I would stick with the more powerful PEEKKEY.

I think there are 3 basic read extension operations:

PEEK - return value, but keep value in keyboard buffer HIT - return next value in buffer if it exits, don't wait GET - return next value in buffer, wait if not there

And there are two variants:

CH - return the character string literal, ignore non-character keys KB - return the numeric code for all keys.

The naming convention ought to be consistent for all permutations. CHPEEK, CHHIT, CHGET or PEEKCH, HITCH, GETCH KBPEEK, KBHIT, KBGET or PEEEKKB, HITKB, GETKB or whatever terms abbreviations we want to settle on.

If I were to name them, I would use PEEKCHR, GETCHR, WAITCHR PEEKKEY, GETKEY, WAITKEY where GET becomes WAIT, and HIT becomes GET. But I'm not overly invested in any one set of terms, as long as we are consistent.

So all of the above are read extensions accessed by percent or delayed expansion - they don't take any arguments.

I do have one request - I would prefer that PEEK and HIT return nothing (an empty string) instead of -1 if there is no key waiting in the buffer. That would allow things like

set "key=!@KBHIT!"
if defined key ...

Currently the only version that can be CALLed is KBHIT. But I don't see the value in the current CALLed form. It serves the exact same purpose as !@KBHIT! except it puts the return value in ERRORLEVEL. I'm struggling to come up with a scenario where I would rather have the value in ERRORLEVEL instead of a variable of my choosing via SET "VAR=!@KBHIT!".

Why not have a called form for all that specifies the variable to receive the value, and has options to specify which keys are accepted and also options to force returned value to be upper or lower case.

If we were to use my proposed names, then we could have

CALL @PEEKCHR [/L] [/U] returnVar ["acceptedCharList"]
CALL @GETCHR [/L] [/U] returnVar ["acceptedCharList"]
CALL @WAITCHR [/L] [/U] [/F] [/P "prompt"] [/E] returnVar ["acceptedCharList"]
CALL @PEEKKEY [/L] [/U] returnVar ["acceptedCodeList"]
CALL @GETKEY [/L] [/U] returnVar ["acceptedCodeList"]
CALL @WAITKEY [/L] [/U] [/F] [/P "prompt"] [/E] returnVar ["acceptedCodeList"]

where:

We might also want a stand-alone CALL @FLUSHKB to flush the keyboard buffer.

Finally, we might want to consider having versions that read from stdin instead of the keyboard.

adoxa commented 4 years ago

If I were to name them, I would use PEEKCHR, GETCHR, WAITCHR PEEKKEY, GETKEY, WAITKEY where GET becomes WAIT, and HIT becomes GET.

I could go with CHR, but not GET/WAIT.

I do have one request - I would prefer that PEEK and HIT return nothing (an empty string) instead of -1 if there is no key waiting in the buffer.

I've thought of that, but don't know why I didn't. There's not much difference.

Currently the only version that can be CALLed is KBHIT. But I don't see the value in the current CALLed form.

I originally created it so I could do call @kbhit && set @next=, but then Carlos goes and makes it return -1 instead, thus totally ruining it. I may remove it, although Carlos wants the keys to return virtual key names (e.g. VK_UP) instead of numbers, so I could keep the function for the numbers.

CALL @PEEKCHR [/L] [/U] returnVar ["acceptedCharList"]
CALL @GETCHR [/L] [/U] returnVar ["acceptedCharList"]
CALL @WAITCHR [/L] [/U] [/F] [/P "prompt"] [/E] returnVar ["acceptedCharList"]
CALL @PEEKKEY [/L] [/U] returnVar ["acceptedCodeList"]
CALL @GETKEY [/L] [/U] returnVar ["acceptedCodeList"]
CALL @WAITKEY [/L] [/U] [/F] [/P "prompt"] [/E] returnVar ["acceptedCodeList"]

No, we'd have one function, with peek/get/chr as additional options.

carlos-montiers commented 4 years ago

call @kbhit && set @next=, but then Carlos goes and makes it return -1 instead

Is because is a inconsistency, caller kbhit returning 0 and getter kbhit returning -1, that was bad. But for the usage of the previous call @kbhit && set @next= in the future it can be call @checkkey && set @next=

I not see the useful of peekkey, who wants keeps readed keys in the buffer? I prefer only checkkey.

adoxa commented 4 years ago

Consistency didn't matter, since you want the variable to return a string, anyway (what's the point of having the call return -1 when the variable returns VK_NONE, or even nothing, as Dave wants?).

It'll basically cost nothing to have peek instead of check, so why not?

In any event all this can wait until I replace the conio kbhit/getch with our own implementation.

carlos-montiers commented 4 years ago

Consistency didn't matter, since you want the variable to return a string, anyway (what's the point of having the call return -1 when the variable returns VK_NONE, or even nothing, as Dave wants?).

I mean consistency as how the functions are currently, current function getter kbhit returns -1 if no key was pressed, the caller kbhit previously returned 0 if no key was pressed, that is the inconsistency and the solution is that caller function be named checkkey and returns 0 if no key was pressed, 1 if a key was pressed, my solution for the inconsistency of change the return of 0 to -1 is not the solution, the solution is renamed it to checkkey.

The new keyboard functions should return the key names, VK_NONE is nice. Checkkey should return integer 0 / 1 for allow the usage: call @checkkey && set @next=

It'll basically cost nothing to have peek instead of check, so why not? I want the checkkey, it is not an instance of function.

If peekkey is useful for Dave or someone, it can also exist additionally, but I think is not a good idea not remove the key from the buffer.

In any event all this can wait until I replace the conio kbhit/getch with our own implementation.

Please, It will be nice.

adoxa commented 4 years ago

It will be a while.

carlos-montiers commented 4 years ago

I implemented checkkey in 5914efa

adoxa commented 4 years ago

I do have one request - I would prefer that PEEK and HIT return nothing (an empty string) instead of -1 if there is no key waiting in the buffer.

It might not matter too much, but that would introduce a discrepancy using it on the command line, as an empty value keeps the variable name. Even so, I think I'd prefer it to return an explicit value, as that's easier to test directly: if !@kbhit! == VK_NONE as opposed to if "!@kbhit!" == "".