NSDatePicker action method not firing - macos

Scenario:
The user is entering a date in an NSDatePicker in its textual form with no stepper (on OS X), and when they hit return on the keyboard, I'd like a message to be sent to the controller.
In an NSTextField, I would just hook the action up in Interface Builder, or set it from code, and when the user hits enter, the action message is sent to the target.
The date picker allows to set an action message and a target, but I can't get the action to fire. When I hit enter in the date picker, the action message does not get called.
Am I doing something wrong, or is there a workaround that I have to use? I would not be adverse to subclassing any of the classes involved, if that is what it takes.

An NSDatePicker will not handle or forward key events triggered by the Return or Enter key.
The solution is to subclass NSDatePicker to get the desired behavior in keyDown:
#import "datePickerClass.h"
#implementation datePickerClass
- (void)keyDown:(NSEvent *)theEvent{
unsigned short n = [theEvent keyCode];
if (n == 36 || n == 76) {
NSLog(#"Return key or Enter key");
// do your action
//
} else {
[super keyDown:theEvent];// normal behavior
}
}
#end
That's it.
Edit : also you can use NSCarriageReturnCharacter and NSEnterCharacter
NSString* const s = [theEvent charactersIgnoringModifiers];
unichar const key = [s characterAtIndex:0];
if (key == NSCarriageReturnCharacter || key == NSEnterCharacter) {

Related

Detecting NSKeyUp of the Shift key

I am using this to detect keystrokes on my app...
[NSEvent addLocalMonitorForEventsMatchingMask:NSEventMaskKeyDown
handler:^NSEvent * (NSEvent * theEvent)
OK I can use theEvent to know what characters were typed and know if a shift was pressed using this:
NSString *typedKey = theEvent.charactersIgnoringModifiers;
BOOL shiftDetected = [theEvent modifierFlags] & NSShiftKeyMask;
My App has an interface displayed with some buttons and I am allowing the keyboard to be used instead of clicking on the buttons. This interface has 3 buttons in particular that has a second function.
For example: the first button has 2 functions, A and B but just the A label is displayed on that button. Lets say I specify that the letter Q is the keyboard shortcut for that button. If the user presses Q function A is executed. If the user presses Shift Q then function B is executed.
But this is the problem. I need to detect all presses or releases of the Shift, because the moment the user presses Shift I have to change the label of that button from A to B, so the user knows that now that button will lead to the execution of function B instead of A. Like a keyboard that will change from lowercase to uppercase while Shift is being hold and change back to lowercase the moment Shift is released.
How do I do that?
I created a simple project using addLocalMonitorForEvents function. Please check my code, it is Swift code but I think it should be as same as objective c.
func applicationDidFinishLaunching(_ aNotification: Notification) {
// Insert code here to initialize your application
NSEvent.addLocalMonitorForEvents(matching: [.flagsChanged, .keyDown]) { (theEvent) -> NSEvent? in
if theEvent.modifierFlags.contains(.shift) {
if theEvent.keyCode == 56 { // this is Shif key
print("Shift START!")
}
else {
print("Shift pressed with keycode \(theEvent.keyCode)")
}
}
else {
if theEvent.keyCode == 56 { // this is Shif key
print("Shift END!")
}
else {
print("Normal keycode \(theEvent.keyCode)")
}
}
return theEvent
}
}
This is Objective c:
[NSEvent addLocalMonitorForEventsMatchingMask:NSEventMaskFlagsChanged|NSEventMaskKeyDown handler:^NSEvent * (NSEvent * theEvent) {
if ([theEvent modifierFlags] & NSEventModifierFlagShift) {
if (theEvent.keyCode == 56) { // this is Shif key
NSLog(#"Shift START");
}
else {
NSLog(#"Shift pressed with keycode %d", theEvent.keyCode);
}
}
else {
if (theEvent.keyCode == 56) { // this is Shif key
NSLog(#"Shift END");
}
else {
NSLog(#"Normal keycode %d", theEvent.keyCode);
}
}
return theEvent;
}];
Just copy and paste this part to your AppDelegate for quick testing.

button available only when label is not nil

How can I force the user to insert data to the UITEXTFILED that otherwise the button will not work for him.
I thought about:
-(IBAction) signup:(id)sender{
if text.text==nil
///// return?? /////
?
tnx all
I would do like this, first in my ViewDidLoad():
editButton.enabled=NO;
[_myTextFieldaddTarget:self
action:#selector(textFieldDidChange:)
forControlEvents:UIControlEventEditingChanged];
Then i would add an event handler:
-(void) textFieldDidChange{
if (_myTextField.length == 0){
editbutton.enabled=NO;
}else{
editbutton.enabled=YES;
}
}
You can show an UIAlertView when the user push the button if the UITextField is empty :
if (_myTextField.lenght == 0)
// Display Alert

Any mouse movement pattern recognizer for Cocoa?

I need some kind of mouse movement pattern recognizer for Cocoa. What I specifically need is to recognize a mouse "shake" or some kind of circular movement. I've read about Protractor but I would like to know if there is some kind of library already implemented.
I'm currently setting a global event monitor to track mouse movements system wide but I need to be able to recognize specific patterns like circular movement, shake, and similar ones.
_eventMonitor = [NSEvent addGlobalMonitorForEventsMatchingMask:NSMouseMovedMask handler:^(NSEvent *eventoEntrada) {
NSLog(#"Movement detected");
NSPoint loc = [NSEvent mouseLocation];
NSLog(#"x:%.2f y:%.2f",loc.x, loc.y);
}];
Is there any library out there to achieve this task?
Thank you!
You can use the Quartz library in mac OS X
1- define the mouse event mask in your applicationDidFinishLaunching method like that
CFMachPortRef mouseEventTap;
CGEventMask mouseEventMask;
CFRunLoopSourceRef runLoopMouseSource;
// Create an event tap. We are interested in key presses.
mouseEventMask = (1 << kCGEventMouseMoved) ;
mouseEventTap = CGEventTapCreate(kCGSessionEventTap, kCGTailAppendEventTap, 0,
mouseEventMask, mouseCGEventCallback, NULL);
if (!mouseEventTap) {
fprintf(stderr, "failed to create event tap\n");
exit(1);
}
// Create a run loop source.
runLoopMouseSource = CFMachPortCreateRunLoopSource(
kCFAllocatorDefault, mouseEventTap, 0);
// Add to the current run loop.
CFRunLoopAddSource(CFRunLoopGetCurrent(), runLoopMouseSource,
kCFRunLoopCommonModes);
// Enable the event tap.
CGEventTapEnable(mouseEventTap, true);
Then implement the call back function mouseCGEventCallback like this
CGEventRef mouseCGEventCallback(CGEventTapProxy proxy, CGEventType type,
CGEventRef event, void *refcon)
{
if (type == kCGEventMouseMoved)
{
//here you can detect any information you need from the event field key
return event;
}
}
For more information about the event field check this
https://developer.apple.com/library/mac/#documentation/Carbon/Reference/QuartzEventServicesRef/Reference/reference.html#//apple_ref/c/tdef/CGEventField
Hope to be helpful for you

Binding selected radiobox to enabling checkbox in Cocoa

I haven't worked with Cocoa bindings a lot before, so I would need a little help here.
I have a radio button group ( NSMatrix ) with three buttons and one checkbox.
I want the checkbox to be enabled only when the last radio button is selected.
Found a tutorial online which advised to bind the selected tag property of the radio button group to the enabled property of the checkbox. The last radiobutton needs to have a tag of 1, the others would need to have a tag of 0.
This works great.
The problem is, that if the checkbox is checked and the radiobutton selection is changed, it stays checked although it isn't enabled. I would want that the box gets unchecked when it changes to the disabled state.
Any advise would be appreciated!
Thanks in advance!
Any way to achieve this without any code?
I doubt it's possible to do this without code.
I handle this in the model, using KVO. Code looks something like this:
-(void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context {
if ([#"checkWithInProcess" isEqualToString:keyPath]) {
NSNumber *oldValue = [change objectForKey:NSKeyValueChangeOldKey];
NSNumber *newValue = [change objectForKey:NSKeyValueChangeNewKey];
BOOL oldValueAsBool = (oldValue != (id)[NSNull null]) && oldValue.boolValue;
BOOL newValueAsBool = (newValue != (id)[NSNull null]) && newValue.boolValue;
if (oldValueAsBool && !newValueAsBool) {
// Save the value
savedRecordValueWithInProcess = self.recordValueWithInProcess;
self.recordValueWithInProcess = nil;
} else if (!oldValueAsBool && newValueAsBool) {
// Restore the value or set it to the default
if (savedRecordValueWithInProcess)
self.recordValueWithInProcess = savedRecordValueWithInProcess;
else
self.recordValueWithInProcess = [NSNumber numberWithBool:NO];
savedRecordValueWithInProcess = nil;
}
}
}
And during initialization:
[self addObserver:self
forKeyPath:#"checkWithInProcess"
options:NSKeyValueObservingOptionOld | NSKeyValueObservingOptionNew
context:[Characteristic class]];

How to Capture / Post system-wide Keyboard / Mouse events under Mac OS X?

For a scripting utility I need to be able to record a series of keyboard and mouse events that occur when an application has focus. The second part is being able to later send those events to the active window.
I do not need to worry about menus or tracking the identifier of which window receives input.
I know how to do this under Windows but have no idea about Mac OS X.
The first thing i will tell you is that you CAN'T do this without the user enabling support for assitive devices in the accessability control panel. It's some kind of security built into OSX.
Here is a code snippit I am using in one of my applications to do this:
//this method calls a carbon method to attach a global event handler
- (void)attachEventHandlers
{
//create our event type spec for the keyup
EventTypeSpec eventType;
eventType.eventClass = kEventClassKeyboard;
eventType.eventKind = kEventRawKeyUp;
//create a callback for our event to fire in
EventHandlerUPP handlerFunction = NewEventHandlerUPP(globalKeyPress);
//install the event handler
OSStatus err = InstallEventHandler(GetEventMonitorTarget(), handlerFunction, 1, &eventType, self, NULL);
//error checking
if( err )
{
//TODO: need an alert sheet here
NSLog(#"Error registering keyboard handler...%d", err);
}
//create our event type spec for the mouse events
EventTypeSpec eventTypeM;
eventTypeM.eventClass = kEventClassMouse;
eventTypeM.eventKind = kEventMouseUp;
//create a callback for our event to fire in
EventHandlerUPP handlerFunctionM = NewEventHandlerUPP(globalMousePress);
//install the event handler
OSStatus errM = InstallEventHandler(GetEventMonitorTarget(), handlerFunctionM, 1, &eventTypeM, self, NULL);
//error checking
if( errM )
{
//TODO: need an alert sheet here
NSLog(#"Error registering mouse handler...%d", err);
}
}
Here is an example of the callback method i am using:
OSStatus globalKeyPress(EventHandlerCallRef nextHandler, EventRef theEvent, void *userData)
{
NSEvent *anEvent = [NSEvent eventWithEventRef:theEvent];
NSEventType type = [anEvent type];
WarStrokerApplication *application = (WarStrokerApplication*)userData;
//is it a key up event?
if( type == NSKeyUp)
{
//which key is it?
switch( [anEvent keyCode] )
{
case NUMERIC_KEYPAD_PLUS:
//this is the character we are using for our toggle
//call the handler function
[application toggleKeyPressed];
break;
//Comment this line back in to figure out the keykode for a particular character
default:
NSLog(#"Keypressed: %d, **%#**", [anEvent keyCode], [anEvent characters]);
break;
}
}
return CallNextEventHandler(nextHandler, theEvent);
}
For the latter part, posting events, use the CGEvent methods provided in ApplicationServices/ApplicationServices.h
Here's an example function to move the mouse to a specified absolute location:
#include <ApplicationServices/ApplicationServices.h>
int to(int x, int y)
{
CGPoint newloc;
CGEventRef eventRef;
newloc.x = x;
newloc.y = y;
eventRef = CGEventCreateMouseEvent(NULL, kCGEventMouseMoved, newloc,
kCGMouseButtonCenter);
//Apparently, a bug in xcode requires this next line
CGEventSetType(eventRef, kCGEventMouseMoved);
CGEventPost(kCGSessionEventTap, eventRef);
CFRelease(eventRef);
return 0;
}
For tapping mouse events, see Link
I haven't checked this under 10.5 Leopard but on 10.4 it works.

Resources