#137059 - K-Duke - Tue Aug 07, 2007 6:07 pm
Hey Everyone,
since now i've mostly used to get Keyboard-Input from the user though because of it's nature to wait for the User to finish his/her writing it's not very practical for time- and synchronous-sensitive applications.
I've found the GetAsyncKeyState-function... though it won't work out for me..
here a pseudo-code how I'm using it.
Code: |
while ( ! bQuit )
{
// Search for keys pressed since the last time GetAsyncKeyState was called
CHAR Keys[256];
CHAR Pressed = 0;
for ( ULONG i=0; i<256; i++ )
if ( GetAsyncKeyState(i) & 1 )
Keys[Pressed++] = i;
// If something was pressed...
if ( Pressed != 0 )
{
printf( "%s\n", Keys);
}
} |
Though I don't get any output onto the console....
Someone got an idea what I'm doing wrong?
_________________
Live is but a game noone asked us to play for.
Quote: |
There are 10 types of people. Those thinking binary and thos who don't. |
http://k-duke.myblog.de
www.kdukes-cave.de <--WiP!!
#137061 - elyk1212 - Tue Aug 07, 2007 6:35 pm
Quote: |
.. time- and synchronous-sensitive applications.
|
To me, this would be an argument for concurrent programming (Threads, semaphores etc). Depending on if you have an OS this is running on etc.
From what I remember, libc does have non blocking I/O routines for keyboard input, however, if this is time sensitive, you may want to look into threading, forking a process... etc.
EDIT: Never mind if you are doing this on an embedded system/GBA.
#137063 - elyk1212 - Tue Aug 07, 2007 6:44 pm
Hey also, by looking at your code, um...
Code: |
for ( ULONG i=0; i<256; i++ )
if ( GetAsyncKeyState(i) & 1 )
Keys[Pressed++] = i;
|
So, on this loop, (if I understand the GetAsyncKeyState function) you are not waiting/blocking for input, therefore the system will probably finish the loop before getting any input from the user. User input is in the order of seconds, while your loop is in the order of the speed of your CPU (quite a big difference)
For testing, maybe just use a while loop and check:
while(Pressed < x), where x is some number of keys you want to see.
#137065 - kusma - Tue Aug 07, 2007 6:55 pm
K-Duke wrote: |
Code: |
printf( "%s\n", Keys);
|
|
no wonder you get no output, i guess the key with scancode 0 is never pressed, so it becomes a string starting with the zero-termination.
#137068 - elyk1212 - Tue Aug 07, 2007 7:04 pm
"string starting with the zero-termination."
Yes, kusma is right.
If the user did input something (in time for entry into the first element):
You are printing a null terminated string of length 0. You are just appending integer values from 'i' into the Keys array (first one is 0, of course).
If they didn't do this in time, you are guaranteed garbage in the first element. Not necessarily 0, but what ever the stack frame contained from a previous allocation (could be anything). This is what ever was in the memory space of Keys from before.
Let me ask you, what is the purpose of the code? Do you wish to print out each character the user has entered?
#137070 - K-Duke - Tue Aug 07, 2007 7:20 pm
Sorry... I forgot to note thats Windows specific.
Though GetAsyncKeyState returns the last key pressed since GetAsyncKeyState has been called.
Well that's how it's defined at MSDN
Those virtual-key codes mentioned there simply are "#defines" for the ascii codes.
Quote: |
So, on this loop, [...] you are not waiting/blocking for input |
That is exactly what I don't want. To make it clear in fact it's a simple console chat client.
Though if I wait for the User to finish his/her input the client cannot receive any messages from the server as the program still waits for the cariage return.
It doesn't have to be exactly this function (GetAsyncKeyState).
If you've got another idea to do this I would appreciate any approach.
And for threads... well I don't have a clue to realize that.
_________________
Live is but a game noone asked us to play for.
Quote: |
There are 10 types of people. Those thinking binary and thos who don't. |
http://k-duke.myblog.de
www.kdukes-cave.de <--WiP!!
#137073 - elyk1212 - Tue Aug 07, 2007 7:42 pm
Quote: |
Though GetAsyncKeyState returns the last key pressed since GetAsyncKeyState has been called.
|
BTW, you are anding with 1 which will only enter the conditional when the last bit in the key code is set. So, only every other key will detected.
Does this make sense? for example, if ASCI codes were 0 to 3 for chars a,b,c,d (which they are not, but for simplicity) .
The bits would be:
A = 0000
B = 0001
C = 0010
D = 0011
Notice the LSB (least significant bit, Right hand side) is alternating every other character. This is just normal binary counting. You will see this pattern in all adjacent number values. But this is the least of your worries with that code, it is much more likely to not get anything at all from the user as the loop code will complete so fast there will be no input detected.
Quote: |
"Though if I wait for the User to finish his/her input the client cannot receive any messages from the server as the program still waits for the carriage return. "
|
This is why you need to use threads. The idea is the client thread does its thing, while another thread can block for user input, while not conflicting with one another. If they share data you will need to use semaphores to provide concurrency and eliminate things like "race conditions" etc. If this doesn't make any sense I suggest reading up on threads and concurrency, as you will pull your hair out trying to sync all of these things without it. I'd venture to say impossible, but improbable is likely a better suite.
Another alternative is using a GUI tool kit which implements threads in the widgets for you (hiding many of the details), which may be all you need. But more likely you will need to implement threads of some sort (the GUI tool kits make an easy interface for these, usually).
These can be wxWidgets, QT... for C++, or even Java swing etc. You could check out wxDev-Cpp for windBloze, if you would like. It is decent for rapid app dev.
#137076 - K-Duke - Tue Aug 07, 2007 8:12 pm
Quote: |
A = 0000
B = 0001
C = 0010
D = 0011
Notice the LSB (least significant bit, Right hand side) is alternating every other character. |
That would be if the result of GetAsyncKeyState would be used to fill Keys.
Though if you carefully look at the code you will see it works in another way as GetAsyncKeyState doesn't retun a char 8bit-Value.
The reason I anded 1 to the return-value is because the LSB doesn't contain the ascii-code but is set to clarify that the key (i) as pressed since the last call of GetAsyncKeyState.
When I press a key AFTER the function was called it (normally should) get this KeyPress from the Windows thread message-queue.
As the key has been pressed the LSB is set.
If a slash was the key returned it would be like
Code: |
(key ain't down)
| ascii scan code(also in loop counter i)
| _____|______ Flag set as the key was pressed.
\ / / \ |
0 1 0 1 1 1 1 1
&
0 0 0 0 0 0 0 1
|
resulting in in... 1 as result. --> Key i has been pressed.
Though saying this i notice i have to "!" the whole if statement...
*hitting my forehead*
_________________
Live is but a game noone asked us to play for.
Quote: |
There are 10 types of people. Those thinking binary and thos who don't. |
http://k-duke.myblog.de
www.kdukes-cave.de <--WiP!!
#137077 - elyk1212 - Tue Aug 07, 2007 8:24 pm
EDIT: Aw, I see. Just read some Win32 docs on that func. Still the concept needs work. See my response on threads and speed of execution regarding using input.
The way your code is, Keys would always be
Keys => {0... 255} // where which ever ascii code that does not conform to keys possible, there will be garbage.
Anytime the user doesn't enter a key code for a particular value (such as 0 etc), that will be a garbage value. But say you could enter in all key values from 0-255 on a keyboard, the print statement still makes little sense, in this context. Also when done in this top down 0-255 loop, mannor, order of keys pressed comes into play.
What if a user pressed key C before A, A < C therefore A would never be detected, even while the loop was going! (Or in the other case, C would not be detected and only A, depending on where we were in the loop).
Ultimately: I think... the way in which you are retrieving input does not make sense for your application. It should not be a iterative polling process that tests each key, (this takes 0(N) time!) it should be a single query that instead asks for the value of the key press (O(1) time!).
------------------------------------------
Hey, btw, did what I say about 'garbage' make sense.
Have you read about initializing data in C/C++ to avoid this. This is key to avoiding problems in C/C++. It is not needed in some higher level interpreted languages, therefore, it is worth mentioning as it is not always remembered.
Example if I had this code, what would printout?
Code: |
char stuff[3]
int z = 5;
int x;
int i;
for(i = 0; i < 3; i++)
{
printf("stuff[%d] = %c\n",i, stuff[i])
}
printf("z = %d\n",z);
printf("x = %d\n",x);
|
You are right if you said, "Who the H&*l knows?", LOL. It would be gargage for all stuff[] (what ever was left over on the stack) and would be 5 for z and gargabe for x.
So maybe it would look something like this (I say *maybe* due to garbage being unknown values):
Quote: |
stuff[0] = %
stuff[1] = 3
stuff[2] = &
z = 5
x = @
|
Last edited by elyk1212 on Tue Aug 07, 2007 8:50 pm; edited 3 times in total
#137082 - K-Duke - Tue Aug 07, 2007 8:47 pm
I think I'm missing something... >.<
Where is the point I'm pointing to non-set memory?
Could you please point out where I should get garbage?
In fact I'm not getting any garbage at all because the if-statement never becomes true. Therefore Pressed is never incremented and printf never called.
Sorry for acting dumb....
_________________
Live is but a game noone asked us to play for.
Quote: |
There are 10 types of people. Those thinking binary and thos who don't. |
http://k-duke.myblog.de
www.kdukes-cave.de <--WiP!!
#137084 - elyk1212 - Tue Aug 07, 2007 8:53 pm
No, no... you are not acting dumb. This is good stuff to discuss.
Well, when you go through that loop, can a person ever enter a ASCII character of value 1? No, how about 0? .. not really that is NULL, and a keyboard cannot 'press' null.
Therefore, when you are asking is this key pressed in a loop like that, some keys will never be possible to be depressed. Therefore, they will never be set.
But regardless, even if they were all possible ASCII values,
if the user did not press say... um 'A'. Then the value of
Keys['A'] in your array is garbage as it is never initialized to anything!
I am sorry if this does not make sense. Your code glosses over the keys that were never pushed.
BTW, even if the Pressed variable were non-zero, you would still see unpredictable things, as the concept of your application is off a bit. Especially since the first value would be zero if it were at all possible for the user to push NULL!.
More likely, the code steps through 256 iterations before you can blink or let alone push a key, and that variable is in fact zero (probably). Add a printf statement and find out.
printf("Pressed = %d\n",Pressed");
#137086 - elyk1212 - Tue Aug 07, 2007 9:01 pm
K-Duke wrote: |
I think I'm missing something... >.<
Where is the point I'm pointing to non-set memory?
|
Code: |
printf( "%s\n", Keys);
|
this equals the same thing as..
Code: |
printf( "%s\n", Keys[0]);
|
1) Keys[0] = 0, if it were possible for a user to push NULL
2) Keys[0] = Garbage in real life
If (1) were true, you would see nothing, a zero length null terminated string.
If (2) were possible, you may see the same as (1), or you may see unpredictable random crappy-crap garbled string that prints characters until it reaches the char value NULL (aka 0), etc.
I've seen these plenty of times ;)
#137088 - K-Duke - Tue Aug 07, 2007 9:07 pm
Quote: |
Code: | printf( "%s\n", Keys); |
this equals the same thing as..
Code: |
printf( "%s\n", Keys[0]); |
|
Then I wonder why server prints out "/Connect me:Nickname" calling Code: |
printf("%s\n", buf); |
after receiving exacly this message over UDP.
_________________
Live is but a game noone asked us to play for.
Quote: |
There are 10 types of people. Those thinking binary and thos who don't. |
http://k-duke.myblog.de
www.kdukes-cave.de <--WiP!!
#137090 - elyk1212 - Tue Aug 07, 2007 9:11 pm
K-Duke wrote: |
Then I wonder why server prints out "/Connect me:Nickname" calling Code: | printf("%s\n", buf); | after receiving exacly this message over UDP. |
Can you please explain more? I didn't see that code.
A guess: Likely, if that buffer is populated by some sort of network class you made or are implementing, you would have no issue with un-allocated strings.
#137092 - elyk1212 - Tue Aug 07, 2007 9:18 pm
Code: |
for ( ULONG i=0; i<256; i++ )
if ( GetAsyncKeyState(i) & 1 )
Keys[Pressed++] = i;
|
Dude, I'm tired or something, lol my understanding was way off. I thought "Keys[i++] = i; " I need to retract what I said earlier about the glossing over parts and garbage being an issue (except no termination). But anyhow, order still matters on key presses (not good), and there is no null termination at the end of retrieving input, so it could run on forever in memory when it reaches the printf statement (that is until it reaches NULL, somewhere in memory).
Concept change?:
Try a threading approach. And instead of asking each ascii value if it is pressed, ask what was pushed. Also, debug output is your friend, go nuts with printfs and see what your code is doing.
Last edited by elyk1212 on Tue Aug 07, 2007 9:35 pm; edited 2 times in total
#137093 - K-Duke - Tue Aug 07, 2007 9:22 pm
Code: |
while(1)
{
//here buf is filled. it is simply a global "char buf[256];"
rc=recvfrom(MySock, buf, 256, 0, (SOCKADDR*)&RemoteAddr, &RemoteAddrLen);
if( rc == SOCKET_ERROR)
{
printf("recvfrom\n");
system("PAUSE");
return WSAGetLastError();
}
else
{ //3
printf("%s\n", buf);
|
recvfrom is defined as follow:
Code: |
int recvfrom (
SOCKET s,
char FAR* buf,
int len,
int flags,
struct sockaddr FAR* from,
int FAR* fromlen
); |
_________________
Live is but a game noone asked us to play for.
Quote: |
There are 10 types of people. Those thinking binary and thos who don't. |
http://k-duke.myblog.de
www.kdukes-cave.de <--WiP!!
#137100 - elyk1212 - Tue Aug 07, 2007 11:00 pm
Hey man, sorry, read my last post (just placed during your last one).
I was wrong about the garbage (for input anyhow), but your prints could still produce garbage due to no null termination.
Suggestion: Redesign with thread for receiving data from server, one for receiving user input, etc. Easier to do with a GUI tool kit.... or using pthreads and friends (in your case a windows equivalent, perhaps encapsulated by the GUI tool kit you chose [?] ). At least that is what I would do.
I wrote something similar to this in Java not that long ago for a portable Yahoo chat client. I spun off a new thread every time I made a blocking (network) request, that way the GUI was still responsive.
Analogy: in your case "That way the keyboard is still responsive"... or whatever you're doing.
But given your current code, that may not be the reason you aren't seeing anything. Could be the loop completion issue I mentioned (can you see how this can be an issue?). Printf the crap out of your code and find out what's going on.
#137108 - sgeos - Wed Aug 08, 2007 12:04 am
Not sure what your are trying to do, but I have had no problems with the curses libraries.
-Brendan
#137191 - K-Duke - Wed Aug 08, 2007 7:23 pm
In the meantime I "solved" the problem...
To be exact the code I posted first was completely ok.
It is just that I have a blocking recv() call in the loop where the code snippet I posted was in too.
So it only checked if there was a keypress once. No further call of GetAsyncKeyState() was done as the code waited at recv() to get some UDP-Packets before proceeding.
Though to my disappointment it only returns capital letters.
Furthermore it isn't possible to reach shift+key characters....
I guess I have no choice but to thread the whole thing.
_________________
Live is but a game noone asked us to play for.
Quote: |
There are 10 types of people. Those thinking binary and thos who don't. |
http://k-duke.myblog.de
www.kdukes-cave.de <--WiP!!
#137194 - elyk1212 - Wed Aug 08, 2007 7:40 pm
That's good. Sorry about my previous confusion.
It would be a good idea to thread, if you are creating a serious chat app.
--- About the previous ----
Consider, any time you print a string you are constructing char by char, always NULL terminate before doing so (that avoids garbage prints, trust me). Also, if you used any string.h functions without null terminating, you'd be hosed (strcat, strcpy and friends). They can be handy. Also, consider what I said about the letter order being restricted. You aren't noticing this issue perhaps due to the speed of execution (in the loop), but you would if you stepped through.
-------------------------------
But for now, I would look at another I/O routine for keyboard input. It may be that GetAsyncKeyState() is not the best choice (since your code just checks for individual keys, not combos etc).
getchar() and such from stdio do retrieve capital letters, and you don't have to do funny things to check for input. However, the catch is it blocks by default. I do think I have heard of using non-blocking calls from stdio though. Check the libc documents.
#137198 - K-Duke - Wed Aug 08, 2007 8:09 pm
I've now found a possibility to do it.
I'll use a keyboard hook.
This way the input is only checked when a keyboard event occurs in Windows. Then Windows calls my set filter function.
So to say I use the results of the Windows intern keyboard processing thread.
_________________
Live is but a game noone asked us to play for.
Quote: |
There are 10 types of people. Those thinking binary and thos who don't. |
http://k-duke.myblog.de
www.kdukes-cave.de <--WiP!!