I have many NSTextFields and I want to know, if the user has pressed one of the arrow keys while editing one of them. The function
override func keyDown(theEvent: NSEvent) {
switch theEvent.character {
case NSRightArrowFunctionKey:
println(1)
moveGor(NSRightArrowFunctionKey)
case NSLeftArrowFunctionKey:
moveGor(NSLeftArrowFunctionKey)
case NSUpArrowFunctionKey:
moveVert(NSUpArrowFunctionKey)
case NSDownArrowFunctionKey:
moveVert(NSDownArrowFunctionKey)
default:
super.keyDown(theEvent)
}
}
doesn't seem to work. Is there any other way to do that in swift?
EDIT:
I have the extension for NSEvent:
extension NSEvent {
var character: Int {
let str = charactersIgnoringModifiers!.utf16
return Int(str[str.startIndex])
}
}
that I used in previous function
When text fields have the focus, they actually don't. Instead, a text view is added to the window on top of the text field and that text view is the first responder and handles all of the input and editing behaviors. The text view is known as the "field editor". The text field does not receive key down events; the text view does.
You could substitute a custom text view as the first responder for the text field and have that text view handle the key down events specially. However, it's probably easier to take advantage of the fact that the text field is the delegate for the text view. Depending on exactly what you're trying to achieve, you might implement -textView:willChangeSelectionFromCharacterRange:toCharacterRange:, but that's not exclusively about arrow keys.
A more promising method might be -textView:doCommandBySelector:. That's also not really about the arrow keys, but in some ways it's better. The arrow keys, and all other standard editing keys, operate by being translated through the key bindings system into command selectors. The command selectors represent the semantic operation being performed, like -moveUp:. They are changed by modifier flags, so that Shift-up-arrow might generate -moveUpAndModifySelection:.
Anyway, in -textView:doCommandBySelector:, you can execute code based on the selector and either tell the text view not to do anything else (by returning YES) or let the text view do its normal thing in addition (by returning NO). (Obviously, return NO for anything that you don't care about.)
So I've set up an NSPopUpButton menu and populated it with the menu items and set all the key equivalents to what I want. The problem I'm having is that it automatically displays the key equivalent in the menu items next to the title of the item and I don't want it to. Is there any way to prevent it? I've searched the documentation and Google but can't seem to find anything about it.
the two ways that would come to mind would be to subclass NSMenuItemCell and do the following:
(untested, but seems like it should work)
- (NSRect)keyEquivalentRectForBounds:(NSRect)cellFrame
{
return NSZeroRect;
}
- (CGFloat)keyEquivalentWidth
{
return 0.0f;
}
or number 2 to remove the key equivalents and handle the events manually.
I have a 3 text fields and a button. I want to press on the first uitextfield, press on the button and hello world to be pasted, and same goes to the others. I know how to do this, but my method is too basic and I need to keep the same pasting code .. (so I guess in a way what im asking is, how can I retrieve the uitextfield that the user presses so I can alter it)
this is what i do:
if ( textfield1.isEditing ) {
textfield1.text = ...
}
Is there a way I can get rid of the variable textfield1, because if I have 1000 textfields I will have to write 1000 lines .. I can do loops but I want to retrieve the value somehow maybe using the sender? (new to xcode).
I think if you implement the textFieldDidBeginEditing function:
-(void)textFieldDidBeginEditing:(UITextField *)textField {
// process text
}
and set the delegate of your text fields to the viewcontroller that contains this function. The input parameter textField should be the textfield that you are currently editing. This way you wont have to do the 1000 lines of code you mentioned.
In Cocoa, I have an NSOutlineView where the cells are NSTextFieldCell. The cell displays values which are strings that are formatted according to certain rules (such as floats or pairs of floats with a space in between). I have made a custom NSFormatter to validate the text, and this seems to work with no problem.
However, the cell (or the outline view, I'm unsure what is causing this) only seems to use the formatter at the moment my editing would end. If I type some alphabetic characters into the text field (which violates the formatting rules), these characters show up -- the only way I notice the formatter doing its job is that I'm now prevented from moving keyboard focus away from this cell. If I return the contents of the cell to a valid form, then I can move focus away.
I have set both the cell and the outline view to be "continuous".
It would be better if I was unable to enter text into the cell in the first place. Is it possible to make it like that, and if so, how?
Answering my own question because I found the solution. There is an optional method to override on NSFormatter, and this solves the problem. The optional method is:
- (BOOL) isPartialStringValid: (NSString*) partialString
newEditingString: (NSString**) newString
errorDescription: (NSString**) error
Here one can simply return NO if the partialString is invalid. One can return a fixed string by reference in newString if one wants.
There is another method which could also have been used, but it is more complex:
- (BOOL) isPartialStringValid: (NSString**) partialStringPtr
proposedSelectedRange: (NSRangePointer) proposedSelRangePtr
originalString: (NSString*) origString
originalSelectedRange: (NSRange) origSelRange
errorDescription: (NSString**) error
I have an application in which I'm trying to capture the shift key modifier to perform an action, however when I run the program and press and normal key without the shift key modifier I get a beep and the modifier and key are not sent to my keyDown event. The relevant code is:
NSString* eventChars = [theEvent charactersIgnoringModifiers];
if ([eventChars isEqualTo:#"w"]) {
newPlayerRow++;
direction = eUp;
} else if ([eventChars isEqualTo:#"x"]) {
newPlayerRow--;
direction = eDown;
} else if ([eventChars isEqualTo:#"a"]) {
newPlayerCol--;
direction = eLeft;
} else if ([eventChars isEqualTo:#"d"]) {
newPlayerCol++;
direction = eRight;
} else {
[super keyDown:theEvent];
return;
}
// handle the player firing a bullet
if (([theEvent modifierFlags] & (NSShiftKeyMask | NSAlphaShiftKeyMask)) != 0) {
NSLog(#"Shift key");
[self fireBulletAtColumn:newPlayerCol row:newPlayerRow inDirection:direction];
[self setNeedsDisplay:YES];
} else {
...
}
I'm not sure what is causing this, but I'd like to be able to capture shift key presses. Thanks in advance for any help with this problem.
EDIT: Also I'm using a MacBook keyboard if that makes any difference.
EDIT: This is definitely a shift-centric problem as changing (NSShiftKeyMask | NSAlphaShiftKeyMask) to NSControlKeyMask does have the desired effect.
First, -charactersIgnoringModifiers doesn't ignore the shift key, so you will still get shifted characters (i.e UPPERCASE and !%#$%^&*) returned from it. What's probably happening in your function is: You press shift-w, your -isEqualTo: returns false because you're comparing a lowercase 'w' and an uppercase 'W', and so you return before getting to the shift-detection code at the bottom. The simplest solution is to just check for both.
However, if you want, for example, Arabic keyboardists to be able to easily use your app, you really shouldn't hardcode characters that may not even appear on the user's keyboard. The value returned by -keyCode refers to a key's position on the keyboard, not the represented character. For starters, the constants beginning in 'kVK_ANSI_' and 'kVK_' in Events.h (you may have to link to Carbon.framework and #include <Carbon/Carbon.h> to use those constants) can be compared to what -keyCode returns, and they refer to the key positions a QWERTY-using USian expects. So you can be (pretty) sure that, regardless of keyboard layout, the keycodes for 'wasd' (kVK_ANSI_W, kVK_ANSI_A, etc.) will refer to that triangle in the top left of your user's keyboard.
If you just want to be notified of modifier key presses without a character key you should be overriding the NSResponder method flagsChanged.
- (void)flagsChanged:(NSEvent *)theEvent
Have you tried logging the values of eventChars and modifierFlags using NSLog? Perhaps it's something other than what you expected it to be. If the log statement doesn't show up in your output, then this code is not running at all and you have a problem somewhere else.
NSLog(#"Chars: %#, modifier flags: 0x%x", eventChars, [theEvent modifierFlags]);
Some other things worth noting:
isEqualTo: is the AppleScript equality operator. It should work, but won't be as efficient because it goes through compare:. The proper method is either isEqualToString: or the more-generic isEqual:, either of which may do a straight equality comparison.
The traditional set of movement keys in the QWERTY letter region is wsad, not wxad. This uses the inverted-T arrangement. You may also want to support the arrow keys, as many of us do have keyboards with their arrows in the inverted T arrangement.
Furthermore, you should make these configurable by the user, and you should respond to key codes rather than letters because different layouts (French, Dvorak, etc.) will generate different letters. I have a table of key codes, adapted from Inside Macintosh, on my website. Use characters only for display purposes.
Shouldn't it be “fireBulletFromColumn:row:inDirection:”? I don't know about you, but saying that the method fires a bullet at a cell tells me (and will tell you, after you haven't looked at the code for a year) that it fires the bullet toward that cell; replacing “At” with “From” avoids this moment of confusion.
From your code it looks like the code that checks for the modifier is never reached.
Anything that is not "w,x,a,d" is sent to the superclass (see the else branch).
You probably want to move "[super keyDown:theEvent]; return;" at the end of your keyDown method.
Solving the immediate problem:
Building on what Boaz said, the -charactersIgnoringModifiers does not include the Shift key (read the documentation) and will return capitalized characters when the Shift key is down. That is why the Control key worked and the Shift key didn't. Switch the string to lowercase before you test it:
eventChars = [[theEvent charactersIgnoringModifiers] lowercaseString];
After that, (as Peter suggested) change all the isEqualTo:'s to isEqualToString: (besides being correct, it's also documented as being faster).
However:
If you are planning on releasing this app to other people, you should really be using key codes (as Peter and Boaz suggested) so it will work on as many different keyboards and setups as possible.
Create a view in your preferences with an input for each command you have and record the key code for the key the user presses. Store these in your NSUserDefaults and check against those instead of your hard coded strings. You can create a default set for your current "wasd" keys.
See projects like Shortcut Recorder for examples of how to do that (or search your friend).