Help needed with GetAsyncKeyState...

As my other recent posts indicate, I'm rather new to Delphi. I've been fiddling around with the GetAsyncKeyState function for a program I'm starting on, but I can't seem to get it to work properly. I've made the below code just to test it:

[CODE]
WHILE GetAsyncKeyState(VK_RETURN) = 0 DO BEGIN
GotoXY(1, 1);
Write(GetAsyncKeyState(VK_DELETE));
END;
[/CODE]
The problem is that the console window just freezes, most of the time showing "0", but sometimes showing "1". If I press RETURN or DELETE nothing happens. After a while the computer just beeps every time I press a button and I have to CTRL-ALT-DEL and shut down the console window. Does this have something to do with focus? What am I doing wrong?

Comments

  • : As my other recent posts indicate, I'm rather new to Delphi. I've been fiddling around with the GetAsyncKeyState function for a program I'm starting on, but I can't seem to get it to work properly. I've made the below code just to test it:
    :
    : [CODE]
    : WHILE GetAsyncKeyState(VK_RETURN) = 0 DO BEGIN
    : GotoXY(1, 1);
    : Write(GetAsyncKeyState(VK_DELETE));
    : END;
    : [/CODE]
    : The problem is that the console window just freezes, most of the time showing "0", but sometimes showing "1". If I press RETURN or DELETE nothing happens. After a while the computer just beeps every time I press a button and I have to CTRL-ALT-DEL and shut down the console window. Does this have something to do with focus? What am I doing wrong?
    :
    The console window needs to be able to process messages. In this loop, you are not processing any messages, which will hang the console window. Console applications should only be used to write command-line tools, or programs with very little (to no) user I/O. For all other applications a GUI program is much easier to design.
  • [b][red]This message was edited by PP2005 at 2006-9-12 23:27:17[/red][/b][hr]
    : The console window needs to be able to process messages. In this loop, you are not processing any messages, which will hang the console window. Console applications should only be used to write command-line tools, or programs with very little (to no) user I/O. For all other applications a GUI program is much easier to design.
    :

    The thing is that I'm writing a textmode ASCII game. I've previously written such a game in Borland Pascal and Virtual Pascal, but that doesn't always work optimally in Windows, so this time I decided to write it in Delphi. The game will basically consist of a main game loop that loops 25 times a second, thus updating the console screen 25 times a second (using a buffer). Between each loop there will be a short delay lasting 1/25th a second. I want to use the GetAsyncKeyState, so that keypresses made during this delay will still be registered. Also, I need to be able to check if the key is down, not just if it is pressed, as the user should be able to hold a key down for continuous movement of the player character on screen. GetAsyncKeyState seems to do all this, but it is possible to use it in consoles?
  • : [b][red]This message was edited by PP2005 at 2006-9-12 23:27:17[/red][/b][hr]
    : : The console window needs to be able to process messages. In this loop, you are not processing any messages, which will hang the console window. Console applications should only be used to write command-line tools, or programs with very little (to no) user I/O. For all other applications a GUI program is much easier to design.
    : :
    :
    : The thing is that I'm writing a textmode ASCII game. I've previously written such a game in Borland Pascal and Virtual Pascal, but that doesn't always work optimally in Windows, so this time I decided to write it in Delphi. The game will basically consist of a main game loop that loops 25 times a second, thus updating the console screen 25 times a second (using a buffer). Between each loop there will be a short delay lasting 1/25th a second. I want to use the GetAsyncKeyState, so that keypresses made during this delay will still be registered. Also, I need to be able to check if the key is down, not just if it is pressed, as the user should be able to hold a key down for continuous movement of the player character on screen. GetAsyncKeyState seems to do all this, but it is possible to use it in consoles?
    :
    It is, but you should also check for windows messages in your loop. Otherwise windows will assume your program is stuck in an infinite loop.
  • : It is, but you should also check for windows messages in your loop. Otherwise windows will assume your program is stuck in an infinite loop.
    :

    I've managed to get the below message loop to work. It uses KeyEvent.bKeyDown, however, which doesn't really serve the purpose I need. Any advice on how to alter this to use GetAsyncKeyState instead?

    [CODE]
    WHILE Continue DO BEGIN
    { Read keys }
    PeekConsoleInput(GetStdHandle(STD_INPUT_HANDLE), IBuff, 1, IEvent);
    IF IEvent > 0 THEN BEGIN
    ReadConsoleInput(GetStdHandle(STD_INPUT_HANDLE), IBuff, 1, IEvent);
    CASE IBuff.EventType OF
    KEY_EVENT : BEGIN
    IF ((IBuff.Event.KeyEvent.bKeyDown = True) AND
    (IBuff.Event.KeyEvent.wVirtualKeyCode = VK_ESCAPE))
    THEN Continue := False;
    IF ((IBuff.Event.KeyEvent.bKeyDown = True) AND
    (IBuff.Event.KeyEvent.wVirtualKeyCode = VK_UP))
    THEN Dec(PosY);
    END;
    END;
    END;
    { Update screen }
    FOR X := 2 TO 79 DO BEGIN
    FOR Y := 2 TO 48 DO BEGIN
    Coord.X := X - 1;
    Coord.Y := Y - 1;
    { WriteConsoleOutputAttribute(BufferHandle, ???, 1, Coord, dW); }
    IF WriteToBuffer THEN WriteConsoleOutputCharacter(BufferHandle, ' ', 1, Coord, dW)
    ELSE WriteConsoleOutputCharacter(ConsoleHandle, ' ', 1, Coord, dW);
    END;
    END;
    Coord.X := PosX - 1;
    Coord.Y := PosY - 1;
    IF WriteToBuffer THEN BEGIN
    WriteConsoleOutputCharacter(BufferHandle, 'O', 1, Coord, dW);
    SetConsoleActiveScreenBuffer(BufferHandle);
    END
    ELSE BEGIN
    WriteConsoleOutputCharacter(ConsoleHandle, 'O', 1, Coord, dW);
    SetConsoleActiveScreenBuffer(ConsoleHandle);
    END;
    IF WriteToBuffer THEN WriteToBuffer := False ELSE WriteToBuffer := True;
    Delay(20);
    END;[/CODE]

    I use a screen buffer to write to and then set it as the active buffer for fast screen updates. The code alternates between ConsoleHandle and BufferHandle as the buffer to write to and set as the active screen. So far this code is only able to move the player character ('O') up by pressing the up arrow. I will of course add the other directions, when I get it to work properly.

    This code works, but the movement isn't smooth if the up arrow is held down. The movements also come a bit delayed (i.e. not immediately when the key is pressed).

    Also, I still haven't been able to figure out how to pass the text attribute to WriteConsoleOutputAttribute(). I've searched the net, but have only found examples of use in C++ code, which used arrays that contained the attributes. I'd really appreciate it if someone could write a clearcut example of how to set the attributes in my code...
  • : : It is, but you should also check for windows messages in your loop. Otherwise windows will assume your program is stuck in an infinite loop.
    : :
    :
    : I've managed to get the below message loop to work. It uses KeyEvent.bKeyDown, however, which doesn't really serve the purpose I need. Any advice on how to alter this to use GetAsyncKeyState instead?
    :
    : [CODE]
    : WHILE Continue DO BEGIN
    : { Read keys }
    : PeekConsoleInput(GetStdHandle(STD_INPUT_HANDLE), IBuff, 1, IEvent);
    : IF IEvent > 0 THEN BEGIN
    : ReadConsoleInput(GetStdHandle(STD_INPUT_HANDLE), IBuff, 1, IEvent);
    : CASE IBuff.EventType OF
    : KEY_EVENT : BEGIN
    : IF ((IBuff.Event.KeyEvent.bKeyDown = True) AND
    : (IBuff.Event.KeyEvent.wVirtualKeyCode = VK_ESCAPE))
    : THEN Continue := False;
    : IF ((IBuff.Event.KeyEvent.bKeyDown = True) AND
    : (IBuff.Event.KeyEvent.wVirtualKeyCode = VK_UP))
    : THEN Dec(PosY);
    : END;
    : END;
    : END;
    : { Update screen }
    : FOR X := 2 TO 79 DO BEGIN
    : FOR Y := 2 TO 48 DO BEGIN
    : Coord.X := X - 1;
    : Coord.Y := Y - 1;
    : { WriteConsoleOutputAttribute(BufferHandle, ???, 1, Coord, dW); }
    : IF WriteToBuffer THEN WriteConsoleOutputCharacter(BufferHandle, ' ', 1, Coord, dW)
    : ELSE WriteConsoleOutputCharacter(ConsoleHandle, ' ', 1, Coord, dW);
    : END;
    : END;
    : Coord.X := PosX - 1;
    : Coord.Y := PosY - 1;
    : IF WriteToBuffer THEN BEGIN
    : WriteConsoleOutputCharacter(BufferHandle, 'O', 1, Coord, dW);
    : SetConsoleActiveScreenBuffer(BufferHandle);
    : END
    : ELSE BEGIN
    : WriteConsoleOutputCharacter(ConsoleHandle, 'O', 1, Coord, dW);
    : SetConsoleActiveScreenBuffer(ConsoleHandle);
    : END;
    : IF WriteToBuffer THEN WriteToBuffer := False ELSE WriteToBuffer := True;
    : Delay(20);
    : END;[/CODE]
    :
    : I use a screen buffer to write to and then set it as the active buffer for fast screen updates. The code alternates between ConsoleHandle and BufferHandle as the buffer to write to and set as the active screen. So far this code is only able to move the player character ('O') up by pressing the up arrow. I will of course add the other directions, when I get it to work properly.
    :
    : This code works, but the movement isn't smooth if the up arrow is held down. The movements also come a bit delayed (i.e. not immediately when the key is pressed).
    :
    : Also, I still haven't been able to figure out how to pass the text attribute to WriteConsoleOutputAttribute(). I've searched the net, but have only found examples of use in C++ code, which used arrays that contained the attributes. I'd really appreciate it if someone could write a clearcut example of how to set the attributes in my code...
    :
    The data type to specify the attributes is like this:
    [code]
    type
    PTextAttributes = ^TTextAttributes;
    TTextAttributes = array[0..79] of word; // whole line of attributes

    var
    MyAttributes: TTextAttributes;

    WriteConsoleOutputAttribute({other params}, @MyAttributes, {other params});
    [/code]
    for a single character, you can change the TTextAttributes into a word.

    As for the wait, in the past I used the keyboard events to detect if the key was down and let a timer run the timing of my game. That way I could control the timing and circumvent that DOS wait after the first keypress. In pseudocode:
    [code]
    while do
    if keypressed then
    check which key and store it
    else
    clear keypress
    if timer event then begin
    case stored key of
    handle keys
    end
    handle other game events
    end
    [/code]
  • : The data type to specify the attributes is like this:
    : [code]
    : type
    : PTextAttributes = ^TTextAttributes;
    : TTextAttributes = array[0..79] of word; // whole line of attributes
    :
    : var
    : MyAttributes: TTextAttributes;
    :
    : WriteConsoleOutputAttribute({other params}, @MyAttributes, {other params});
    : [/code]
    : for a single character, you can change the TTextAttributes into a word.
    :
    : As for the wait, in the past I used the keyboard events to detect if the key was down and let a timer run the timing of my game. That way I could control the timing and circumvent that DOS wait after the first keypress. In pseudocode:
    : [code]
    : while do
    : if keypressed then
    : check which key and store it
    : else
    : clear keypress
    : if timer event then begin
    : case stored key of
    : handle keys
    : end
    : handle other game events
    : end
    : [/code]
    :


    Hmmm... Now I get the error "Incompatible types: 'Word' and 'Pointer'". I changed the code you supplied to this:

    [code]
    type
    PTextAttribute = ^TTextAttribute;
    TTextAttribute = word;

    var
    MyAttribute: TTextAttribute;

    WriteConsoleOutputAttribute({other params}, MyAttribute, {other params});
    [/code]

    And I'll try changing my code to the structure in your pseudocode.

    Thanks! :o)
Sign In or Register to comment.

Howdy, Stranger!

It looks like you're new here. If you want to get involved, click one of these buttons!

Categories