Onscreen keyboard with OpenGL

Member
Posts: 129
Joined: 2009.03
Post: #1
Hello,

I have some text input screens in my game (for names on highscores etc), I'd like to use the system onscreen keyboard, and I'm in landscape orientation. Is that possible to do, and mix it with my OpenGL fullscreen?

Thanks, Smile
Quote this message in a reply
Member
Posts: 241
Joined: 2008.07
Post: #2
Yes. Just use a UITextField object and conform to the UITextFieldDelegate protocol. The UI elements will draw on top of your OpenGL view.
Quote this message in a reply
Member
Posts: 129
Joined: 2009.03
Post: #3
Yep, seems to be working now, using UITextField, thanks..

One more question though, is it possible to set the maximum number of characters the text field can accept?

For example, my highscore table may have 32 characters per name (as an example), I don't want the user to enter a string longer than that, and then have to cull characters from the end etc.

So, is it possible to limit the number of characters the UITextField will accept?

Thanks,
Quote this message in a reply
Member
Posts: 241
Joined: 2008.07
Post: #4
You'll have to do that in code. In the "will return" function (or whatever it's called), check the string that belongs to the text field that comes into that function. The string is what was typed. Just do:

Code:
if([theString count] > 32)
     return NO;

I don't have any code examples open right now, so I can't be more specific, but that should give you the general idea.
Quote this message in a reply
Moderator
Posts: 3,577
Joined: 2003.06
Post: #5
bmantzey Wrote:I don't have any code examples open right now, so I can't be more specific, but that should give you the general idea.

I just happen to have one in front of me right now:

Code:
- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string
{
    if ([[textField text] length] < 15)
        return YES;
    else
        return NO;
}
Quote this message in a reply
Luminary
Posts: 5,143
Joined: 2002.04
Post: #6
which looks like it will break with pasting Wink
Quote this message in a reply
Moderator
Posts: 3,577
Joined: 2003.06
Post: #7
OneSadCookie Wrote:which looks like it will break with pasting Wink

What's wrong with it?

[edit] I should add that it works just fine for me. If you're wondering about the zero length check, I don't know if that needs to be in there anymore. I seem to recall I had to add that for earlier versions of iPhone which wouldn't allow me to dismiss the keyboard with a zero string length, which I allow for users so they can use "anonymous" instead.

[edit2] Okay, I just checked. The zero length check isn't needed anymore, so I edited that out. It didn't hurt it though.
Quote this message in a reply
Member
Posts: 129
Joined: 2009.03
Post: #8
I just tried AnotherJake's snippet of code; and it mostly works! Wink Smile

The only issue was if you enter the maximum number of characters, then try to backspace. I also only want to allow NSWindowsCP1252StringEncoding, so this was the perfect place to filter out characters I don't want.

Ended up with a slightly modified version..

Code:
- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string
{
    if ([string canBeConvertedToEncoding:NSWindowsCP1252StringEncoding])
    {
        if ([[textField text] length] < 10 || [string length] == 0)
        {
            return YES;
        }
    }
    return NO;
}
Quote this message in a reply
Moderator
Posts: 3,577
Joined: 2003.06
Post: #9
Jamie W Wrote:The only issue was if you enter the maximum number of characters, then try to backspace.

Hmm... Well, after thinking about OSC's complaint (for lack of a better way to put it), and looking at the code again, my original technique is, at the very least, a little sloppy -- even if it works to some degree.

Let me offer up another version and see if it makes a little more sense, and maybe works a little better:

Code:
- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string
{
    static const NSUInteger maxCharacters = 15;
    
    NSString *candidate = [[textField text] stringByReplacingCharactersInRange:range withString:string];
    
    if ([candidate length] <= maxCharacters)
        return YES;
    else
        return NO;
}
Quote this message in a reply
Member
Posts: 129
Joined: 2009.03
Post: #10
Cool! Thanks AnotherJake Smile

That kinda makes sense to me. I find myself becoming more and more familiar with Obj C and Cocoa (is that right? NS* stuff is Cocoa?).

In your latest sample code, would 'candidate' need to be released?

That's still a source of confusion for me, when stuff needs to be released etc (even though I've watched videos and read up on the topic).
Quote this message in a reply
Moderator
Posts: 3,577
Joined: 2003.06
Post: #11
Yes, the "NS* stuff" is Cocoa.

Jamie W Wrote:In your latest sample code, would 'candidate' need to be released?

That's still a source of confusion for me, when stuff needs to be released etc (even though I've watched videos and read up on the topic).

Yeah, it's definitely confusing to pick up. I still screw it up myself. Wink

Here are the "loose" rules of thumb:

- if you call "alloc" on something (e.g. [[myObj alloc] init], it comes back with a retain count of +1 and you'll need to release it yourself when you don't want it anymore
- if you don't see an alloc then it's coming back from the method that created it with a retain count of +1, but it is set to be autoreleased, so you shouldn't release it yourself

So that means that in this case:
Code:
[[textField text] stringByReplacingCharactersInRange:range withString:string];

you see no "alloc", which means the string we're getting back is set to be autoreleased, and thus should not release it ourselves.

A little extra info to add to the confusion if you're interested: This is fine in this case because it's not something that uses up a huge amount of memory on the spot, but if you were doing something in a loop that created a lot of strings this way, you'd probably be better off using a technique which uses an alloc, so you can release it right there when you're done with it. Confused yet?
Quote this message in a reply
Member
Posts: 129
Joined: 2009.03
Post: #12
Yep, think I'm getting there thanks..

I've just done some code to setup the initial NSString 'text' that's in my UITextField. Looks like:

Code:
NSString*    nss;

nss    =    [[NSString alloc]initWithBytes:ps length:length encoding:NSWindowsCP1252StringEncoding];
myTextField.text    =    nss;
[nss release];

So the alloc, will actually allocate the memory for the object, which I'm then responsible for (and need to release), and the init<whatever> actually initialises the memory that's just been allocated.

My understanding with the 'myTextField.text = nss;' bit, is that is just copies the data from one object to the other, rather than just set a pointer to the nss object I've just instantiated (which if that was the case, I guess would increase the retain count by one).

Is that correct?

It's certainly a bit confusing, and I don't really understand what's going on 'under the hood'.

The concern I have, is that I'm not creating lots of objects, that I don't release, when I should, and thereby causing memory leaks etc.
Quote this message in a reply
Moderator
Posts: 3,577
Joined: 2003.06
Post: #13
Jamie W Wrote:My understanding with the 'myTextField.text = nss;' bit, is that is just copies the data from one object to the other, rather than just set a pointer to the nss object I've just instantiated (which if that was the case, I guess would increase the retain count by one).

It looks like you got everything right except this part (if I'm reading it correctly). The text field should just take the pointer to the object you just created and increase the retain count by one. IOW, you're handing off ownership of nss to myTextField. That's why you need to release it if you don't need it for anything else. Then, when you remove myTextField from the view, it should release nss and then nss will finally be destroyed. This way you don't have to continue to keep track of nss yourself, and data doesn't need to be copied around.

So yes, glancing at your code, it looks correct.

Be sure to use Instruments to measure memory usage, leaks and other stuff.
Quote this message in a reply
Member
Posts: 43
Joined: 2009.10
Post: #14
AnotherJake Wrote:A little extra info to add to the confusion if you're interested: This is fine in this case because it's not something that uses up a huge amount of memory on the spot, but if you were doing something in a loop that created a lot of strings this way, you'd probably be better off using a technique which uses an alloc, so you can release it right there when you're done with it. Confused yet?

Actually I'm not sure you'd gain anything switching to alloc in that case Rasp If you are still receiving the initial string from some method, then you can certainly alloc your own string with a copy constructor init and release it when you're done. The problem is you're still dealing with the autorelease pool every time you call the method that you're sending to your copy constructor. So that same memory is still going to hang around until the autorelease pool is drained as much as it would if you never used alloc with a copy constructor.

Unless of course you're referring to a different situation where you don't need to receive from some other method?
Quote this message in a reply
Post Reply 

Possibly Related Threads...
Thread: Author Replies: Views: Last Post
  on-screen keyboard help Merax 1 1,736 Jul 26, 2010 08:21 AM
Last Post: ThemsAllTook
  iPhone keyboard bmantzey 15 6,802 Feb 28, 2009 08:03 AM
Last Post: AnotherJake