Textboxes - keys repeat too quickly

Started by alcitos517, Sun 08/03/2009 01:55:28

Previous topic - Next topic

alcitos517

Has anyone had a problem like this?  I have a textbox and I will type "hello" and it comes out "hhhelllllloooo", for example.  Is there a way to control this?  Thanks for your help.

Khris

Does this happen only in AGS?
-> Yes -> Weird.
-> No -> Check Control Panel / Keyboard

alcitos517

Yes, it happens in any textbox, including the save game textbox where you type the name of the game.  Does it not happen for you?  It doesn't happen in other applications outside of AGS for me, however. 

I actually tried lowering the keyboard repeat rate in control panel to the lowest level and it didn't make it any better. 

monkey0506

What exactly is the code for your textbox? Specifically anything modifying the text would be important.

alcitos517

It's just a standard GUI textbox.  The only code I used was to make the GUI visible.  However, the same thing happens in the built-in saved game GUI when typing, not only in my game, but also in the KQ3 remake and "A Tale of Two Kingdoms", and in the Demo game, which leads me to believe it couldn't be something I did.  It would have to be either common to AGS, or specific to certain types of computer hardware, wouldn't it?

For reference, I'm running an AMD 64 X2 Dual Core 6000+, 3.01 GHz CPU, 4 GB ram, Windows XP pro

Akatosh

Heh, I know that problem. It usually helps to wait a few seconds after the textbox shows up.

alcitos517

Is there a way in scripting to control the flow of text into a textbox?  I know that when a GUI with a textbox is on that the text is not passed to the "on key press" function in the global script, so it doesn't seem like there's any way to prevent the keys from repeating so quickly.  Any ideas?

GarageGothic

A bit of a hack, but if you don't have anything else going on in the background while the textbox is displayed (i.e. the game is paused), you could try to SetGameSpeed(int new_speed) to something lower than 40 (and revert this change once you close the textbox GUI). If this doesn't work, the only solution I see would be to code your own textbox replacement, using on_key_press and displaying the entered text on a label for instance.

Pumaman

That certainly shouldn't happen, and I haven't heard any reports of it happening to anyone before.

As you're getting it with ATOTK and KQ3 it does sound like an AGS-specific problem, though I'm not sure what might be causing it. Has anyone else ever experienced anything like this?

alcitos517

#9
It seems like when it passes text to a textbox that it checks the key being pressed and passes it on each game loop.  If I am extremely careful about typing the letters, I can avoid repeating a lot, but some repeating is still unavoidable, and it requires a lot of care to get that far.  Using GarageGothic's 2nd suggestion (the first didnt work out), I came up with some code to use a label within a GUI as a custom textbox and control the flow that way, and it works pretty good (not perfect).  It seeks to delay repeat of keys by a couple of extra loops.  Of course, a native textbox that doesn't have this repeat issue would be better :)   But this method wouldn't be too bad for my current need since it's just to type in answers to specific questions in a specific room.  My code is below:

// room script file

int lastKeyPress; // the last key that was pressed prior to the current one
String keyPressed; // string value of the current key pressed.
int keyPresses = 0; // number of loops during which the key has been pressed.

function room_FirstLoad()
{
  // Set the GUI to visible for easy testing.
  gTesting.Visible = true;
}


function on_key_press(eKeyCode keycode)
{
  int pkp = 0;
  // continue only if the GUI is visible
  if (gTesting.Visible == true)
  {
    // Prevent global key press function from executing
  ClaimEvent();

    // Check each pertinent key to see if it is the pressed key.
    // If one of these keys is pressed: First set the string variable (keyPressed) to the appropriate character,
    // Then check if this key was also the last key that was pressed previously.  If it was not, set the KeyPresses
    // to 3, which will allow it to be appended right away and reset keyPresses to 1.  If it was the last key,
    // increment key presses by 1, until it reaches 3, at which point it will be appended, creating the delay. 
    if (keycode == eKeyA) {keyPressed = "A"; pkp = 1; if(lastKeyPress == eKeyA) {keyPresses = keyPresses + 1;} else {keyPresses = 3;}}
    if (keycode == eKeyB) {keyPressed = "B"; pkp = 1; if(lastKeyPress == eKeyB) {keyPresses = keyPresses + 1;} else {keyPresses = 3;}}
    if (keycode == eKeyC) {keyPressed = "C"; pkp = 1; if(lastKeyPress == eKeyC) {keyPresses = keyPresses + 1;} else {keyPresses = 3;}}
    if (keycode == eKeyD) {keyPressed = "D"; pkp = 1; if(lastKeyPress == eKeyD) {keyPresses = keyPresses + 1;} else {keyPresses = 3;}}
    if (keycode == eKeyE) {keyPressed = "E"; pkp = 1; if(lastKeyPress == eKeyE) {keyPresses = keyPresses + 1;} else {keyPresses = 3;}}
    if (keycode == eKeyF) {keyPressed = "F"; pkp = 1; if(lastKeyPress == eKeyF) {keyPresses = keyPresses + 1;} else {keyPresses = 3;}}
    if (keycode == eKeyG) {keyPressed = "G"; pkp = 1; if(lastKeyPress == eKeyG) {keyPresses = keyPresses + 1;} else {keyPresses = 3;}}
    if (keycode == eKeyH) {keyPressed = "H"; pkp = 1; if(lastKeyPress == eKeyH) {keyPresses = keyPresses + 1;} else {keyPresses = 3;}}
    if (keycode == eKeyI) {keyPressed = "I"; pkp = 1; if(lastKeyPress == eKeyI) {keyPresses = keyPresses + 1;} else {keyPresses = 3;}}
    if (keycode == eKeyJ) {keyPressed = "J"; pkp = 1; if(lastKeyPress == eKeyJ) {keyPresses = keyPresses + 1;} else {keyPresses = 3;}}
    if (keycode == eKeyK) {keyPressed = "K"; pkp = 1; if(lastKeyPress == eKeyK) {keyPresses = keyPresses + 1;} else {keyPresses = 3;}}
    if (keycode == eKeyL) {keyPressed = "L"; pkp = 1; if(lastKeyPress == eKeyL) {keyPresses = keyPresses + 1;} else {keyPresses = 3;}}
    if (keycode == eKeyM) {keyPressed = "M"; pkp = 1; if(lastKeyPress == eKeyM) {keyPresses = keyPresses + 1;} else {keyPresses = 3;}}
    if (keycode == eKeyN) {keyPressed = "N"; pkp = 1; if(lastKeyPress == eKeyN) {keyPresses = keyPresses + 1;} else {keyPresses = 3;}}
    if (keycode == eKeyO) {keyPressed = "O"; pkp = 1; if(lastKeyPress == eKeyO) {keyPresses = keyPresses + 1;} else {keyPresses = 3;}}
    if (keycode == eKeyP) {keyPressed = "P"; pkp = 1; if(lastKeyPress == eKeyP) {keyPresses = keyPresses + 1;} else {keyPresses = 3;}}
    if (keycode == eKeyQ) {keyPressed = "Q"; pkp = 1; if(lastKeyPress == eKeyQ) {keyPresses = keyPresses + 1;} else {keyPresses = 3;}}
    if (keycode == eKeyR) {keyPressed = "R"; pkp = 1; if(lastKeyPress == eKeyR) {keyPresses = keyPresses + 1;} else {keyPresses = 3;}}
    if (keycode == eKeyS) {keyPressed = "S"; pkp = 1; if(lastKeyPress == eKeyS) {keyPresses = keyPresses + 1;} else {keyPresses = 3;}}
    if (keycode == eKeyT) {keyPressed = "T"; pkp = 1; if(lastKeyPress == eKeyT) {keyPresses = keyPresses + 1;} else {keyPresses = 3;}}
    if (keycode == eKeyU) {keyPressed = "U"; pkp = 1; if(lastKeyPress == eKeyU) {keyPresses = keyPresses + 1;} else {keyPresses = 3;}}
    if (keycode == eKeyV) {keyPressed = "V"; pkp = 1; if(lastKeyPress == eKeyV) {keyPresses = keyPresses + 1;} else {keyPresses = 3;}}
    if (keycode == eKeyW) {keyPressed = "W"; pkp = 1; if(lastKeyPress == eKeyW) {keyPresses = keyPresses + 1;} else {keyPresses = 3;}}
    if (keycode == eKeyX) {keyPressed = "X"; pkp = 1; if(lastKeyPress == eKeyX) {keyPresses = keyPresses + 1;} else {keyPresses = 3;}}
    if (keycode == eKeyY) {keyPressed = "Y"; pkp = 1; if(lastKeyPress == eKeyY) {keyPresses = keyPresses + 1;} else {keyPresses = 3;}}
    if (keycode == eKeyZ) {keyPressed = "Z"; pkp = 1; if(lastKeyPress == eKeyZ) {keyPresses = keyPresses + 1;} else {keyPresses = 3;}}
    if (keycode == eKeySpace) {keyPressed = " "; pkp = 1; if(lastKeyPress == eKeySpace) {keyPresses = keyPresses + 1;} else {keyPresses = 3;}}
    if (keycode == eKeyBackspace) {keyPressed = "*"; pkp = 1; if(lastKeyPress == eKeyBackspace) {keyPresses = keyPresses + 1;} else {keyPresses = 3;}}
 
    // set the last key that was pressed
    lastKeyPress = keycode;
   
    // if a pertinent key isn't being pressed, exit function
    if (pkp != 1) {return;}
    // Can't append a backspace via a string variable
    if (keycode != eKeyBackspace) {
      // If the key has been pressed either for 3 loops, or this is the first loop during which the key was pressed
      // (see above), append the value of the key to the label text.
      if (keyPresses >= 3 && keycode != 0) { lblText.Text = lblText.Text.Append(keyPressed); keyPresses = 0;}
    }
    else {
      // Similarly controlling the rate of the backspace key.
    if (keyPresses >= 3 && lblText.Text.Length > 0) { lblText.Text = lblText.Text.Truncate(lblText.Text.Length - 1); keyPresses = 0; }
    }
     
  }
}

Lt. Smash

#10
you can make that long code much shorter:
Code: ags

    if (keycode == eKeyA) {keyPressed = "A"; pkp = 1; if(lastKeyPress == eKeyA) {keyPresses = keyPresses + 1;} else {keyPresses = 3;}}
    if (keycode == eKeyB) {keyPressed = "B"; pkp = 1; if(lastKeyPress == eKeyB) {keyPresses = keyPresses + 1;} else {keyPresses = 3;}}
    if (keycode == eKeyC) {keyPressed = "C"; pkp = 1; if(lastKeyPress == eKeyC) {keyPresses = keyPresses + 1;} else {keyPresses = 3;}}
    if (keycode == eKeyD) {keyPressed = "D"; pkp = 1; if(lastKeyPress == eKeyD) {keyPresses = keyPresses + 1;} else {keyPresses = 3;}}
    if (keycode == eKeyE) {keyPressed = "E"; pkp = 1; if(lastKeyPress == eKeyE) {keyPresses = keyPresses + 1;} else {keyPresses = 3;}}
    if (keycode == eKeyF) {keyPressed = "F"; pkp = 1; if(lastKeyPress == eKeyF) {keyPresses = keyPresses + 1;} else {keyPresses = 3;}}
    if (keycode == eKeyG) {keyPressed = "G"; pkp = 1; if(lastKeyPress == eKeyG) {keyPresses = keyPresses + 1;} else {keyPresses = 3;}}
    if (keycode == eKeyH) {keyPressed = "H"; pkp = 1; if(lastKeyPress == eKeyH) {keyPresses = keyPresses + 1;} else {keyPresses = 3;}}
    if (keycode == eKeyI) {keyPressed = "I"; pkp = 1; if(lastKeyPress == eKeyI) {keyPresses = keyPresses + 1;} else {keyPresses = 3;}}
    if (keycode == eKeyJ) {keyPressed = "J"; pkp = 1; if(lastKeyPress == eKeyJ) {keyPresses = keyPresses + 1;} else {keyPresses = 3;}}
    if (keycode == eKeyK) {keyPressed = "K"; pkp = 1; if(lastKeyPress == eKeyK) {keyPresses = keyPresses + 1;} else {keyPresses = 3;}}
    if (keycode == eKeyL) {keyPressed = "L"; pkp = 1; if(lastKeyPress == eKeyL) {keyPresses = keyPresses + 1;} else {keyPresses = 3;}}
    if (keycode == eKeyM) {keyPressed = "M"; pkp = 1; if(lastKeyPress == eKeyM) {keyPresses = keyPresses + 1;} else {keyPresses = 3;}}
    if (keycode == eKeyN) {keyPressed = "N"; pkp = 1; if(lastKeyPress == eKeyN) {keyPresses = keyPresses + 1;} else {keyPresses = 3;}}
    if (keycode == eKeyO) {keyPressed = "O"; pkp = 1; if(lastKeyPress == eKeyO) {keyPresses = keyPresses + 1;} else {keyPresses = 3;}}
    if (keycode == eKeyP) {keyPressed = "P"; pkp = 1; if(lastKeyPress == eKeyP) {keyPresses = keyPresses + 1;} else {keyPresses = 3;}}
    if (keycode == eKeyQ) {keyPressed = "Q"; pkp = 1; if(lastKeyPress == eKeyQ) {keyPresses = keyPresses + 1;} else {keyPresses = 3;}}
    if (keycode == eKeyR) {keyPressed = "R"; pkp = 1; if(lastKeyPress == eKeyR) {keyPresses = keyPresses + 1;} else {keyPresses = 3;}}
    if (keycode == eKeyS) {keyPressed = "S"; pkp = 1; if(lastKeyPress == eKeyS) {keyPresses = keyPresses + 1;} else {keyPresses = 3;}}
    if (keycode == eKeyT) {keyPressed = "T"; pkp = 1; if(lastKeyPress == eKeyT) {keyPresses = keyPresses + 1;} else {keyPresses = 3;}}
    if (keycode == eKeyU) {keyPressed = "U"; pkp = 1; if(lastKeyPress == eKeyU) {keyPresses = keyPresses + 1;} else {keyPresses = 3;}}
    if (keycode == eKeyV) {keyPressed = "V"; pkp = 1; if(lastKeyPress == eKeyV) {keyPresses = keyPresses + 1;} else {keyPresses = 3;}}
    if (keycode == eKeyW) {keyPressed = "W"; pkp = 1; if(lastKeyPress == eKeyW) {keyPresses = keyPresses + 1;} else {keyPresses = 3;}}
    if (keycode == eKeyX) {keyPressed = "X"; pkp = 1; if(lastKeyPress == eKeyX) {keyPresses = keyPresses + 1;} else {keyPresses = 3;}}
    if (keycode == eKeyY) {keyPressed = "Y"; pkp = 1; if(lastKeyPress == eKeyY) {keyPresses = keyPresses + 1;} else {keyPresses = 3;}}
    if (keycode == eKeyZ) {keyPressed = "Z"; pkp = 1; if(lastKeyPress == eKeyZ) {keyPresses = keyPresses + 1;} else {keyPresses = 3;}}
    if (keycode == eKeySpace) {keyPressed = " "; pkp = 1; if(lastKeyPress == eKeySpace) {keyPresses = keyPresses + 1;} else {keyPresses = 3;}}
    if (keycode == eKeyBackspace) {keyPressed = "*"; pkp = 1; if(lastKeyPress == eKeyBackspace) {keyPresses = keyPresses + 1;} else {keyPresses = 3;}}

using this:
Code: ags

char c = 65;
while (c <= 90) {
  if (keycode == c) {
    keyPressed = c;
    pkp = 1;
  }
  if (lastKeyPress == c) keyPresses++;
  else keyPresses = 3;
  c++;
}
if (keycode == eKeySpace) {keyPressed = " "; pkp = 1; if(lastKeyPress == eKeySpace) {keyPresses++;} else {keyPresses = 3;}}
if (keycode == eKeyBackspace) {keyPressed = "*"; pkp = 1; if(lastKeyPress == eKeyBackspace) {keyPresses++;} else {keyPresses = 3;}}



if you want uppercase and lowercase letters and a custom cursor, I could offer you my code:

first you need these String extenders in your global script:
Code: ags

bool uppercase;
bool keylocker;
int txt_cursor_pos;

String InsertCharAt(this String*, int index, char newChar) {
	if (index < 1 && this.Length < 1)
		return this.AppendChar(newChar);
	String a = "", b = "";
	if (index == 0) a = this.Substring(index, this.Length);
	else a = this.Substring(index, this.Length-1);
	b = this.Truncate(index);
	b = b.AppendChar(newChar);
	b = b.Append(a);
	return b;
}

String DeleteCharsAt(this String*, int index, int length) {
	if (index <= 0 && this.Length <= 0)
		return this;
	else if (index+length > this.Length)
		return this;
	String a = "", b = "";
	a = this.Substring(index+length, this.Length-1);
	b = this.Truncate(index);
	b = b.Append(a);
	return b;
}

then this in your on_key_pressed
Code: ags

if (keycode == 13) { //enter 
	ReactOnInput();
}
if (keycode == 8)  { //backspace
	if (txt_cursor_pos > 0)
	{
		lblUserInput.Text = lblUserInput.Text.DeleteCharsAt(txt_cursor_pos-1);
		txt_cursor_pos--;
	}
	return;
}
if (keycode == 383) { //del-key
	if (txt_cursor_pos < lblUserInput.Text.Length) {
		lblUserInput.Text = lblUserInput.Text.DeleteCharsAt(txt_cursor_pos);
	}
	return;
}
if (gTextCursor.X < 810) { //don't write over the border
	if (keycode == 328 && uppercase) //inverted !{
		lblUserInput.Text = lblUserInput.Text.InsertCharAt(txt_cursor_pos, 161);
		txt_cursor_pos++;
		return;
	}
	if (keycode == 361 && uppercase) //inverted ?{
		lblUserInput.Text = lblUserInput.Text.InsertCharAt(txt_cursor_pos, 191);
		txt_cursor_pos++;
		return;
	}
	if (keycode < 32 || keycode > 256) return; //ignore special codes
	if (keycode < 65 || keycode > 90 && keycode <= 256) { //special characters
		lblUserInput.Text = lblUserInput.Text.InsertCharAt(txt_cursor_pos, keycode);
		txt_cursor_pos++;
		return;
	}
	if (keycode >= 65 && keycode <= 90 && !uppercase) { //lower letters	
		short ascii = keycode + 32;
		lblUserInput.Text = lblUserInput.Text.InsertCharAt(txt_cursor_pos, ascii);
		txt_cursor_pos++;
	}
	else //upper letters	{
		lblUserInput.Text = lblUserInput.Text.InsertCharAt(txt_cursor_pos, keycode); 
		txt_cursor_pos++;
	}
}

so, now we can write but we want to see the cursor, so create a gui that you use for your text cursor and copy this in your rep_exec:
Code: ags

if (IsTimerExpired(1) && !keylocker) { //Cursor blinking animation
	if (gTextCursor.Visible)
		gTextCursor.Visible = false;
	else gTextCursor.Visible = true;
	SetTimer(1, 40);
}
if (textbox_active) //set mouse position when the textbox is activated
{
	gTextCursor.X = lblUserInput.X + GetTextWidth(lblUserInput.Text.Truncate(txt_cursor_pos), eFontUserAnswer);
}
if (IsKeyPressed(403) || IsKeyPressed(404)) uppercase = true;
if (!IsKeyPressed(403) && !IsKeyPressed(404)) uppercase = false;
if (IsKeyPressed(375) && txt_cursor_pos > 0 && !keylocker) //move cursor 1 left
{
	txt_cursor_pos--;
	Wait(5);
}
if (IsKeyPressed(377) && txt_cursor_pos < lblUserInput.Text.Length && !keylocker) //move cursor 1 right
{
	txt_cursor_pos++;
	Wait(5);
}

CapsLock is ignored in this script but you could easily add it.

reset and start the textbox with this:
Code: ags

keylocker=false;
gTextCursor.Visible=true;
txt_cursor_pos=0;
SetTimer(1, 40);

and change your labels name to lblUserInput or all the lblUserInput's in the script to your label name.  ::)
I hope you and others can use it.  :)

Pumaman

Quote from: alcitos517 on Mon 09/03/2009 01:17:22
It seems like when it passes text to a textbox that it checks the key being pressed and passes it on each game loop.  If I am extremely careful about typing the letters, I can avoid repeating a lot, but some repeating is still unavoidable, and it requires a lot of care to get that far.  Using GarageGothic's 2nd suggestion (the first didnt work out), I came up with some code to use a label within a GUI as a custom textbox and control the flow that way, and it works pretty good (not perfect).

I really wouldn't recommend trying to script around this -- it sounds like an AGS engine problem on your PC, and it would be better if we could get to the bottom of why it's happening. AGS uses DirectInput to read the keyboard; what version of DirectX have you got installed? Can you try updating it to the latest version?

alcitos517


alcitos517

#13
Good news..  I ran an updater on directX and it fixed it.. still v9.0c, but perhaps something was messed up with the installation before.  Thanks :) 

Gilbert

Well, DirectX 9.0c is updating constantly. They use to do these kinds of regular updates without changing the version number (subversion numbers might have changed but that's not every user will be aware of) so it's a good idea to update it once a while.

On an unrelated note, I've heard that for some odd reasons the DirectX9 shipped with Vista is of a quite old version, so that's one reason why stuff didn't seem to work. Someone might say that Vista uses DirectX10 which shall cover everything, but this is not the truth, as DirectX10 and DirectX9 are two different things. They are independent of one another. So, you still need DirectX9 to run programmes that use it (unless the programmes support DirectX), so it's still recommended for Vista users to update DirectX9 regularly.

Pumaman


SMF spam blocked by CleanTalk