Recognize if user has pressed arrow key while editing NSTextField swift - macos

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.)

Related

How can I send an NSString to the currently focused UIElement of another application?

I have a menubar application without a dock icon or global menu, it's just a StatusItem and a Window.
I've got it wired up to a hotkey which activates the window and upon deactivating the window I am able to send focus back to the previously active application.
How can I send an NSString to the active textarea in the other application, as if the user had typed it directly?
I think it might be possible using accessibility features. I'd like to avoid using AppleScript if at all possible.
From the focused UI element, you'll need to get two things:
Its value.
Its selected text range.
Now, the straightforward approach would be to just get those two attributes, but that's actually the wrong solution.
The problem is that the value of the value attribute is a plain string. If the element is a rich text view, you'll lose any formatting or embedded objects that the user might have. That would be bad.
So the correct way to get the value is to get the element's number of characters, construct a range starting at zero with that number as its length, and then get the attributed string for that range. If that fails, then you get the plain value.
Once you have both the value (as either an attributed string or a plain string) and the selected range, replace the selected text range within the value with the text you want to insert. If the user has nothing selected, the range will be an empty range (length zero) at the position of the insertion point, and the replacement will effectively be an insertion.
Then, set the element's value to your amended string. (I can only hope that setting it to an attributed string will work.)
I ended up using the pasteboard and CGEventCreateKeyboardEvent() to mimic the [cmd+v] keyboard shortcut for pasting.
Before activating my window, I record the previous application:
_previousApplication = [[notification userInfo] objectForKey:NSWorkspaceApplicationKey];
After I dismiss my window, I activate the previous application:
[_previousApplication activateWithOptions:NSApplicationActivateIgnoringOtherApps];
Then paste the NSString:
#define KEY_CODE_v ((CGKeyCode)9)
void DCPostCommandAndKey(CGKeyCode key) {
CGEventSourceRef source = CGEventSourceCreate(kCGEventSourceStateCombinedSessionState);
CGEventRef keyDown = CGEventCreateKeyboardEvent(source, key, TRUE);
CGEventSetFlags(keyDown, kCGEventFlagMaskCommand);
CGEventRef keyUp = CGEventCreateKeyboardEvent(source, key, FALSE);
CGEventPost(kCGAnnotatedSessionEventTap, keyDown);
CGEventPost(kCGAnnotatedSessionEventTap, keyUp);
CFRelease(keyUp);
CFRelease(keyDown);
CFRelease(source);
}
DCPostCommandAndKey(KEY_CODE_v);

uitextfield problem - retrieving

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.

Change cell content in NSTableView before editing

I have an NSTableView that allows inline editing on one of its cells (NSTextFieldCell). This actually works well, but I want to manipulate the content for the editing session.
Imagine having a string with a path (say: "folder/subfolder/myfile.txt") as the content of such a cell. But when the user enters edit mode for this cell (e.g. by double clicking) I want only the string "myfile.txt" to be editable (i.e. to appear in the editor). How can I achieve this?
You could create a custom NSFormatter that does this. Override the method stringForObjectValue: to return the full string and editingStringForObjectValue: to return only the part you want to edit. You also need to write a method getObjectValue:forString:errorDescription: to transform the edited string back to the complete string. How to exactly do this depends on the rest of your program. You somehow need to get back the part of the string you removed for editing.

Make NSFormatter validate NSTextFieldCell continuously

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

cocoa + what ui element should i use?

I am developing an app which has a text field box. so when i am entering text, it should search the database and give me suggestions just like google search. like if i have entered letter 'a', it should have a box like thing below text field with all names starting with letter 'a'. then if i have entered letter 'b', it should resize the box and give names that start with 'ab' and so on.
I was planning to use a table view below the text field which reloads itself as and when new thing is entered into text field. but i dont know how to resize the table view depending on number of suggestions. So is there any other ui element which suits this kind of situations?
Also how do i detect a new alphabet or number entered into text field so that i can filter out suggestions like is there any such notification? what i mean to say is say i entered letter 'a' so now the string value of text field is 'a' and now i entered say 'b'. so now the string value changed to 'ab'. how do i detect this? i think textDidChange notification will do this for me.
Thanks
You can use an NSComboBox for auto-completing lists like you describe. NSComboBox is a subclass of NSControl so you can use the -controlTextDidChange: delegate method to detect changes in the text that the user types. Make sure you set the control to "continuous" in Interface Builder or call [comboBox setContinuous:YES].
If, for whatever reason, you find that a combo box is inappropriate for your situation, you can implement the list of completions as a child window of the control's window, with a headerless table view in it. Then you would programmatically resize that window as the number of possible completions changes.

Resources