Intercepting key presses / Obscuring text on input

Started by Ultra Magnus, Sun 03/04/2011 06:21:22

Previous topic - Next topic

Ultra Magnus

Hi.
I have a password input text box and would like it to replace all the characters as typed with asterisks.
My question is: how does AGS process key presses, how can I stop it, and how can I simulate it?
i.e. How do I make it ignore a key that has been pressed, and register a different key that hasn't?

I have tried doing a straight swap with
Code: ags
if (keycode>='A' && keycode<='Z') keycode=42;

but the text box just displays what was typed.

I also tried maybe swapping the chars after the fact with
Code: ags
tempstring.AppendChar(42); txtPassword.Text=tempstring;

but that does absolutely nothing. The text still displays as normal.

I have no idea what else I can try. Any ideas?
Thanks in advance.
I don't mean to sound bitter, cold, or cruel, but I am, so that's how it comes out.

I'm tired of pretending I'm not bitchin', a total frickin' rock star from Mars.

Khris

Textbox behavior is hardcoded, you have to do everything manually.

monkey0506

Basically, you'd want to do something in rep_exec_always:

Code: ags
String password;

function repeatedly_execute_always()
{
  if (txtPassword.Enabled)
  {
    char c = 'A';
    while (c <= 'Z')
    {
      if (IsKeyPressed(c))
      {
        if (password == null) password = "";
        password = password.AppendChar(c);
        c = 'Z';
      }
      c++; // hah! :)
    }
    if (IsKeyPressed(eKeyBackspace)) password = password.Truncate(password.Length - 1);
    txtPassword.Text = "";
    int i = 0;
    while (i < password.Length)
    {
      txtPassword.Text = txtPassword.Text.AppendChar(42);
      i++;
    }
  }
}


..to be honest, I haven't actually tested that, so you also might not be able to use TextBox.Enabled, and might have to code that as well (store it in a global bool, use it in place of txtPassword.Enabled, and then in rep_exec append a '_' if it is enabled).
     

Ultra Magnus

#3
Ugh. I keep forgetting that string.Append and string.Truncate are passive. I think it's because they're present-tense verbs, so it implies they actually do something.

Also, I didn't know you could directly use GUIControl.Text.Append, hence the tempstring.

Anyway, I'm going to keep it simple for now.
Code: ags
function repeatedly_execute {
  if (txtPassword.Enabled)
  {
    if (txtPassword.Text.Length!=0) {
      txtPassword.Text=txtPassword.Text.Truncate(txtPassword.Text.Length-1);
      txtPassword.Text=txtPassword.Text.AppendChar(42);
    }
  }
}


It's basically what I was trying before, but in rep_exec instead of hoping it would trigger via on_key_press like I had it.
Downside is that the last letter typed is visible for a loop before becoming an asterisk, so I'll probably swap txtPassword for a regular label that just mimics a text box at some point, but this works well enough for the time being.

Thanks guys.
I don't mean to sound bitter, cold, or cruel, but I am, so that's how it comes out.

I'm tired of pretending I'm not bitchin', a total frickin' rock star from Mars.

monkey0506

Well glad you got that working for you, but at the very least shouldn't you be storing the raw text into a separate String so you can actually read it? Otherwise at the end you'd just have a bunch of asterisks with no way of telling which characters were originally typed in. For that you'd need to also add an additional check (probably just comparing the length against the last loop) otherwise you'd be repeatedly adding the last character to the String.

Oh, and when it comes to String functions, you have to keep in mind that the storage used internally is read-only. So if you're changing the text of a String in any way, you have to reassign the pointer to the newly created String.

Ultra Magnus

#5
Quote from: monkey_05_06 on Sun 03/04/2011 16:00:00
Well glad you got that working for you, but at the very least shouldn't you be storing the raw text into a separate String so you can actually read it?
That's where our old friend tempstring returns.

Here's the complete working code so far. I've now hidden txtPassword and replaced it with lblPass.
Code: ags

function repeatedly_execute {
  int place=txtPassword.Text.Length-1;
  if (txtPassword.Enabled) {
    if (txtPassword.Text.Length!=0) {
      if (txtPassword.Text.Chars[place]!=42) {
        tempstring=tempstring.AppendChar(txtPassword.Text.Chars[place]);
        txtPassword.Text=txtPassword.Text.ReplaceCharAt(place, 42);
        lblPass.Text=txtPassword.Text.AppendChar(95);
      }
      if (tempstring.Length-1>place) {
        tempstring=tempstring.Truncate(place+1);
        lblPass.Text=txtPassword.Text.AppendChar(95);
      }
      if (lblPass.Text.Chars[place+1]!=95) lblPass.Text=lblPass.Text.AppendChar(95);
    }
    else {
      tempstring="";
      lblPass.Text="_";
    }
  }
  else if (lblPass.Text.Chars[place+1]==95) lblPass.Text=lblPass.Text.Truncate(place+1);
}


I still have two issues, though...
1) Is there a way to further simplify this at all? In particular, I'm pretty sure I don't need the AppendChar(95) bit in three different places (four including lblPass.Text="_"), or to check lblPass.Text.Chars[place+1] twice.
2) The regular underscore on the label looks really thin and weedy next to one used in the real text box. Is there a way to beef it up at all? I use text boxes elsewhere in the game, and I'd rather not have to replace them all with labels just to make them match. Or to have to base my choice of font entirely around that one character.

EDIT:
New approach, a lot simpler. I realised that only lblPass.Text needs to be obscured, and as long as txtPassword is hidden it can be left clean, which also means that tempstring is once again unnecessary.
Code: ags

function repeatedly_execute {
  int place=lblPass.Text.Length-1;
  if (txtPassword.Enabled) {
    if (lblPass.Text.Chars[place]!=95) lblPass.Text=lblPass.Text.AppendChar(95);
    else {
      if (txtPassword.Text.Length>place) {
        if (lblPass.Text.Chars[place]==95) lblPass.Text=lblPass.Text.Truncate(place);
        lblPass.Text=lblPass.Text.AppendChar(42);
      }
      else if (txtPassword.Text.Length<place) {
        lblPass.Text=lblPass.Text.Truncate(place-1);
      }
    }
  }
  else if (lblPass.Text.Chars[place]==95) lblPass.Text=lblPass.Text.Truncate(place);
}


Issue 2 still applies, though. Any ideas?
Thanks again.
I don't mean to sound bitter, cold, or cruel, but I am, so that's how it comes out.

I'm tired of pretending I'm not bitchin', a total frickin' rock star from Mars.

Khris

I didn't read the whole thread, but a quick test revealed the underscore to look exactly alike on a label and in a textbox. Are you talking about the textbox cursor?
And you can always edit the font and make the underscore bigger.

SMF spam blocked by CleanTalk