Intercept Command+key with IMKit (or similar) - objective-c

I was looking to intercept Command key combinations and thought that IMKit would be a good choice. By extending IMKInputController I can intercept most keys but it seems to ignore modified ones.
I've tried overriding
-(BOOL)inputText:(NSString*)string client:(id)sender;
and (alternatively)
-(BOOL)inputText:(NSString*)string
key:(NSInteger)keyCode
modifiers:(NSUInteger)flags
client:(id)sender;
but no luck; the methods just plain aren't called when the modifiers are applied. To be more specific the command and alt key don't get caught by the methods above. Simple modifiers like shift and ctrl work (and the modifier flags variable is set in the second method). Fire up Apple's sample application NumberInput to see for yourself.
Any suggestions? Am I on totally the wrong track?

Short answer:
Use handleEvent:client: and listen to the NSFlagsChanged event.
IMKInputController implements the IMKServerInput Protocol, which provides three alternatives to handle an event.
Key binding - using inputText:client: and didCommandBySelector:client:
Text data only - using inputText:key:modifiers:client:
Handle all events - using handleEvent:client:
Seems like you've only tried the top two. You can achieve the goal with the third option.
Try the following:
override recognizedEvents: (from IMKStateSetting Protocol)
- (NSUInteger)recognizedEvents:(id)sender
{
return NSKeyDownMask | NSFlagsChangedMask;
}
and use handleEvent:client:
-(BOOL)handleEvent:(NSEvent*)event client:(id)sender
{
NSLog(#"handling event: %#", event);
return false;
}
You can see the printout on every keydown and keyup of the modifiers in Console, including command and alt.

Related

How do I require certain instance variables be provided at object creation?

Let's say I have a type of object in my game called oCharacter. All characters must have names, so I want to provide one when I construct the object. I can do that by using the _variables argument of instance_create_layer:
instance_create_layer(0, 0, "Instances", oCharacter, { name: "George" });
I could even make sure that I don't forget to do this by making a "constructor" function for characters and only instantiating them using that:
function character_create(_x, _y, _name) {
return instance_create_layer(_x, _y, "Instances", oCharacter, { name: _name });
}
But this approach has two problems.
The first is that I or another developer might forget about this convention and instantiate a character directly using instance_create_layer, forgetting to pass a name and setting up a runtime error further down the road.
The second (related) issue is that Feather doesn't know about this convention, so my Feather window is full of error messages about references to instance variables that aren't declared in the Create event - but I don't see how I can declare these variables in the Create event, as I'm expecting their value to be provided by the creator.
Is there some way of doing this that addresses these issues?
The first problem is just about setting rules about the code conventions within your team, if your team does not know about these conventions you want them to follow, then you should tell it them in a meeting.
For the second problem: Maybe you could create an empty/nullable variable in the Create Event? I'm afraid I'm not familiar with Feather
Personally I would do two things for this.
Create development standards for the team and put them in something like a Word document, wiki page, onenote, whatever makes the most sense for your team.
I would use a function to create the instance of the object (like you're doing there), and have some simple validation checks inside of the create event itself that will cancel it's creation (something like a guard clause) and output a debug message with a reminder.
It's not the most elegant solution but that should do the trick (assuming you haven't found something else by now haha)

How to enable selection between multiple BasicTextField in Kotlin Compose

As you can see here, there is a composable function available to use as a wrapper for Text functions:
SelectionContainer {
Column {
Text("test1")
Text("test2")
Text("test3")
}
}
However, it does not work with BasicTextField.
For more context,
I'm attempting to make the CodeViewer editable and I don't want to use a single BasicTextField as they did in Notepad for "simplicity".
I'm considering implementing something similar to SelectionContainer for my use case but I'm not sure if it's possible or even a good idea.
Any thoughts?

"python function decorator" for objective-c to change a method's behavior

I want to modify the behavior of some function without being the author of that function. What I control is that I can ask the author to follow some pattern, e.g. use a base class, use a certain decorator, property etc.
If in python, I would use a decorator to change the behavior of a method.
As an example, My goal: Improve code coverage by automatically testing over multiple input data.
Pseudo code:
#implementation SomeTestSuiteClass
// If in python, I would add a decorator here to change the behavior of the following method
-(void)testSample1 {
input = SpecialProvider();
output = FeatureToTest(input);
SpecialAssert(output);
}
#end
What I want: During test, the testSample1 method will be called multiple times. Each time, the SpecialProvider will emit a different input data. Same for the SpecialAssert, which can verify the output corresponding to the given input.
SpecialProvider and SpecialAssert will be API under my control/ownership (i.e. I write them).
The SomeTestSuiteClass together with the testSample1 will be written by the user (i.e. test writer).
Is there a way for Objective-C to achieve "what I want" above?
You could mock objects and/or its methods using objective-c runtime or some third party frameworks. I discourage it though. That is a sign of poor architecture choices in the 1st place. The main problem in your approach are hidden dependencies in your code directly referencing
SpecialProvider & SpecialAssert symbols directly.
A much better way to this would be like this:
-(void)testSample1:(SpecialProvider*)provider assert:(BOOL (^)(parameterTypes))assertBlock {
input = provider;
output = FeatureToTest(input);
if (assertBlock != nil) {
assertBlock(output);
}
}
Since Objective-c does not support default argument values like Swift does you could emulate it with:
-(void)testSample1 {
[self testSample1:DefaultSpecialProvider() assert:DefaultAssert()];
}
not to call the explicit -(void)testSample1:(SpecialProvider*)provider assert:(BOOL (^)(parameterTypes))assertBlock all the time, however in tests you would always use the explicit 2 argument variant to allow substituting the implementation(s) not being under test.
Further improvement idea:
Put the SpecialProvider and SpecialAssert behind protocols(i.e. equivalent of interfaces in other programming languages) so you can easily exchange the implementation.

How to access CAN signals dynamically (by string) in CAPL?

I'm trying to force CAN signals to given values using COM interface of CANalyzer. Since there is no COM method to send CAN messages, I'm implementing a workaround using CAPL:
void SendMySignal(int value) {
message MyMessage msg;
msg.MySignal = value;
output(msg);
}
This works fine, however since MyMessage and MySignal are referenced statically (by name) here, I'll have to implement N functions to be able to send N signals (or an N-way switch statement, etc). Is there a way to avoid the hassle and access signals inside a message by string? Something like this:
void SendSignal(int MessageID, char SignalName, int value)
I'm also open to alternative solutions in case I have missed something in the COM interface. If there is a solution which only works for CANoe, I can ask my boss for a license, but of course I'd prefer to do without.
there is such function, but it is restricted to be used only in test nodes
long setSignal(char signalName[], double aValue);
you can find details in:
CAPL Function Overview » Test Feature Set / Signal Access » SetSignal
Special Use Case: Signal is not known before Measurement Start
and take care about not to send for each signal a new message to avoid bus over-flooding. In my opinion it is a better style to set all signals for whole message and to send it on change only when it is not cyclic. Signal updates in cyclic messages mostly have to be sent in next cycle.

Consuming OSX mouse/trackpad events with an event tap

I'm trying to add an event trap to enable/disable event from my magic trackpad. I thought this would be straight forward, i.e. register an event trap and when required, discard the event by returning NULL. The idea is to use the pad for some specific, time consuming data entry, the applications to enter the data into are third party ones so I can't just add code to do want I want there. So i figured I'd monitor the system events and then send the desired input via a bunch of CGEventCreateKeyboardEvents.
The problem is returning null does not seem to discard the events, a bit more investigation suggests that this is not restricted to those coming from the trackpad but also my default usb mouse.
My code is below. With what is below i'd expect not to be able to move the mouse, if I change (A) to use kCGEventScrollWheel or kCGEventLeftMouseDragged then event is consumed, i.e. scrolling or left btn drag don't occur. Does this mean that not all events can be discarded? Hopefully I'm just missing something obvious here
#define case_print(a) case a: printf("%s - %d\n",#a,a); break;
CGEventRef eventOccurred(CGEventTapProxy proxy, CGEventType type, CGEventRef event, void* refcon) {
int subType = CGEventGetIntegerValueField(event, kCGMouseEventSubtype);
if (type == NSEventTypeGesture || subType == NX_SUBTYPE_MOUSE_TOUCH) {
printf("touchpad\n");
switch(type) {
case_print(kCGEventNull)
case_print(kCGEventLeftMouseDown)
case_print(kCGEventLeftMouseUp)
case_print(kCGEventRightMouseDown)
case_print(kCGEventRightMouseUp)
case_print(kCGEventMouseMoved)
case_print(kCGEventLeftMouseDragged)
case_print(kCGEventRightMouseDragged)
case_print(kCGEventScrollWheel)
case_print(kCGEventOtherMouseDown)
case_print(kCGEventOtherMouseUp)
case_print(kCGEventOtherMouseDragged)
case_print(kCGEventTapDisabledByTimeout)
case_print(kCGEventTapDisabledByUserInput)
case_print(NSEventTypeGesture)
case_print(NSEventTypeMagnify)
case_print(NSEventTypeSwipe)
case_print(NSEventTypeRotate)
case_print(NSEventTypeBeginGesture)
case_print(NSEventTypeEndGesture)
default:
printf("default: %d\n",type);
break;
}
event = NULL;
} else {
if (type == kCGEventMouseMoved) { // (A)
printf("discarding mouse event");
event = NULL;
}
}
return event;
}
CFMachPortRef createEventTap() {
CGEventMask eventMask = NSAnyEventMask;
if (!AXAPIEnabled() && !AXIsProcessTrusted()) {
printf("axapi not enabled");
}
return CGEventTapCreate(kCGHIDEventTap,
kCGHeadInsertEventTap,
kCGEventTapOptionDefault,
eventMask,
eventOccurred,
NULL);
}
int main (int argc, const char * argv[]) {
CFMachPortRef tap = createEventTap();
if (tap) {
CFRunLoopSourceRef rl = CFMachPortCreateRunLoopSource(kCFAllocatorDefault, tap, 0);
CFRunLoopAddSource(CFRunLoopGetMain(), rl, kCFRunLoopCommonModes);
CGEventTapEnable(tap, true);
CFRunLoopRun();
printf("Tap created.\n");
sleep(-1);
} else {
printf("failed!\n");
}
return 0;
}
Note, "axapi not enabled" is not output although i don't think the accessibility option affects anything but the keyboard events.
BTW, I've seen a few similar posts on how to get the events from the touch pad, just nothing applicable to discarding them (other than returning null should work).
I think atm it is not possible to simply discard these events. From the CGEventTypes.h header file:
"The event passed to the callback is
retained by the calling code, and is
released after the callback returns
and the data is passed back to the
event system. If a different event is
returned by the callback function,
then that event will be released by
the calling code along with the
original event, after the event data
has been passed back to the event
system."
I've played around with this a little and it seems after the callback returns the window server actively checks again for what you've done to the event. It only allows deletion of key events and mouse up/down events, but just as it ignores deletion of mouse moved events (well, the mouse rendering is processed elsewhere anyways, I guess) it seems to ignore deletion (i.e. your callback returning NULL) for mouse gestures.
Figures, considering tapping for gestures is not specifically explained in the documentation (no type defined at this level).
I tried returning a different event (a key press) and this one is then handled additionally to the original gesture. Releasing the event in your callback doesn't do it, either (of course), just results in an exception.
The only thing I didn't try is directly manipulating the passed CGEvent's internal data to at least make the gesture do nothing (deleting all movement and such), but that's kind of hard because there are no specific methods defined to do that. I'm pretty sure the needed information is somewhere in the various fields accessible via the CGEventSet* methods, though.
I looked down as far as IOLLEvent.h to figure out their data structure, but this was way too ugly for my taste to dig into much further. Let's hope Lion offers a little more regarding the gesture type of events on the CF level.
I can corroborate that on 10.6 neither of the following methods succeed for this purpose.
1-returning NULL
2-returning a new mouse event with the previous cursor position
3-returning the passed event with it's kCGMouseEventDelta's changed to 0
I can not speak of 10.7 but let's just say i would not get my hopes up.
There is one thing however that you could do instead of dropping the movement move it back to the previous location with CGWarpMouseCursorPosition, in effect the cursor will stop moving with only a slight change on the first one.
CGAssociateMouseAndMouseCursorPosition(FALSE);
Will prevent the mouse from functioning while your app is active.
Still exploring if I can extend that to global apps...
http://lists.apple.com/archives/quartz-dev/2007/May/msg00112.html
If your tap is passive, returning NULL will leave the event stream unaffected. From the CGEventTapCallBack reference documentation:
"If the event tap is an passive
listener, your callback function may
return the event that is passed in, or
NULL. In either case, the event stream
is not affected."
However, it looks like your tap is active. Thus your returning NULL should delete the event. Have you considered modifying the event to nullify the action?
Also note that the call CGEventTapCreate requires root user permissions to intercept all events. Is your process running as root?