How to display multiple keys or 'chords' for a MenuItem on Cocoa - objective-c

I am trying to display multiple key combinations to a MenuItem in cocoa. This is most commonly known as "chords".
For example I want to add a menu item that looks like:
"Action1 Control K, F" or "MenuItem2 K,L"
Would this be possible in Objective-C through the standard API? I've looked around and the closest thing to this on MacOS would be using custom views. Would it be the way to go for allowing this functionality?

The standard API does not support handling chords, thus it does not allow setting chords as key equivalent and thus it also cannot display a chord as a key equivalent.
If you need that functionality, you need to implement entirely yourself. Just make your own NSView object and assign it to the view property of NSMenuItem. As documented, you will then have to draw everything yourself:
A menu item with a view does not draw its title, state, font, or other
standard drawing attributes, and assigns drawing responsibility entirely
to the view. Keyboard equivalents and type-select continue to use the key
equivalent and title as normal.
Source: https://developer.apple.com/documentation/appkit/nsmenuitem/1514835-view?language=objc
Whether this is a normal NSView filled with subviews, created either programmatically or even loaded from a NIB file, or whether this is a subclass of NSView drawing everything itself is up to you, all these variations will actually work. Usually it's easiest to use a NIB file and build you menu look in interface builder and using autolayout.
Yet keep in mind that this breaks Apple Human Interface guidelines. It violates the users expectation as all his other apps don't offer anything comparable since in macOS a menu item has one key equivalent or it has none. It also breaks the ability of users to customize the key equivalent the way he is used to do this for all other applications (System Preferences > Keyboard > Shortcuts > App Shortcuts).
Generally you should not replace system standard UI with your own UI unless you really have a very good reason for doing so, as that always breaks users expectations, certain system functionality won't work as expected (e.g. accessibility features) and it destroys the uniform look and feel of the system. Also it breaks system automatic, as you can see in macOS 10.14 (Mojave) where all system standard UI automatically supports dark mode, so if you used only standard UI, your app supports dark mode without any modification, yet all custom UI needs to be customized again for dark mode.

Yes, you'll need to use a custom view. NSMenuItem only displays the first character of its keyEquivalent.

Related

NSMenuItem with Image and text

I have a question regarding NSMenuItems.
What I'm trying to do is replicate a java GUI using native OS X components, therefore the language I am using is Cocoa. What I am trying to do is to get every menu item to have an image and then, beside it, some text.
I have already done some research into it and my first port of call (as always it seems lol) was the apple docs which had this handy example which illustrates how to embed views inside menuitems:
https://developer.apple.com/library/mac/#samplecode/MenuItemView/Listings/MyWindowController_m.html#//apple_ref/doc/uid/DTS10004136-MyWindowController_m-DontLinkElementID_8
Being relatively new to cocoa, I was thinking I would have to override one of the drawing methods from NSMenuItem. Not really sure though.
Another idea that I was toying with was creating a custom view that held a image and some text.
Any other ideas/validation or discussion would be most appreciated.
Thanks all!
Oh and the GUI creation is being done by hand no interface builder.
Okay, so I now have menu items with icons beside them. For anyone who is interested here it is ( i've not done a leak analysis on it or anything).
First things first, put all of the images you want into the "Resources" folder (thats what its called in xcode 3.1.4).
Now, for example, after we have all the images, we want to use images called "eraser.png" and "eraser_on.png" and I want to attach these to the 3rd menu item. In order to achieve this we do the following :
The code below will get the menu item at position 3 in the menu
NSMenuItem *item = [ nameOfPopUpButton itemAtIndex:2];
The code below will set the image for the menu item to be "eraser.png"
[ item setImage: [ NSImage imageNamed:#"eraser"] ];
That's you set the image for the menu item (which will be on the left hand side of the text aka before the text).
If you want different images for the different states, eg when the user presses it, use this method (not tested myself but its sounds sensible :D and the function is straight out the api)
[item setOnStateImage: [ NSImage imageNamed:#"eraser_on" ] ]
You can however leave it nil or not set it at all and it will go the default color
Hope this helps someone.
Pieced this together from: https://developer.apple.com/library/mac/#samplecode/MenuMadness/Listings/Controller_m.html#//apple_ref/doc/uid/DTS40008870-Controller_m-DontLinkElementID_4
Thanks :)
If you need to do this you have the right idea in creating a view with image and label subviews.
BUT: don't do this. Creating a "native" application is not primarily about your choice of language (which is Objective-C, btw, not Cocoa; the latter is a collection of development frameworks implemented in Objective-C). It's about conforming to the platform.
On OS X (and iOS), more than probably any other platform, consistency in UI design is paramount. Users know when an application looks strange, and having icons next to each menu item (something I certainly have seen in Java apps) is definitely strange and unnatural on OS X. Users will be irritated at best, confused at worst.
So my advice is to either follow the Human Interface Guidelines (and save yourself a lot of work as a nice side effect) or just stick with your existing Java application.
If you want to provide quick iconic access to common functions, the recommended approach on OS X is to use a toolbar.

How hard would it be to create a customisable GUI for mac?

What I mean by this is, how much work would be involved in rewriting/extending default AppKit controls in a way that would allow for both a standard OS X appearance and custom appearance (loaded from image files) if the user so wishes? (Think of WinAmp or Windows Media Player.) Has anyone tried to bring this to the Mac?
I understand how to redraw an NSWindow or a button cell but that's all hard coded. I want something the user can add to themselves. What are my options?
Well, it would really involved redrawing all the custom components you'd need from scratch, whether in code, or using images. AppKit wasn't meant to be customized as it strictly follows Apple's Human Interface Guidelines; Apple wants to create one consistent UI metaphor across all native applications.
What that means in practice is that you're going to have to do a lot of custom drawing to theme your app. Using images makes things easier, but not by too much. If you want a custom button, you'll have to create a subclass of NSButton and NSButtonCell to load the images you want and draw (take a look at NSDrawThreePartImage() and NSDrawNinePartImage() for how to more easily draw resizable buttons). To theme NSWindow, you'll have to subclass NSThemeFrame, a semi-private class that draws the standard OS X window look.
Essentially, you'll just need to do a lot of subclassing to get the appearance you want. Is it possible? Absolutely. Is it recommended or easy to do? Not so much.
Of course, you have to ask if this is really necessary. The point of the HIG is to try to create one standard look across OS X. If not done expertly, a themed look can be tacky, and possibly even confusing for users who are used to the default OS X look. If you want to include UI theming, there usually needs to be a good reason for it (either to maintain cross-platform compatibility, but in that case, all HIG rules are out the window; or to achieve a specific look, a là game UI), but I really wouldn't recommend doing it, let alone letting users customize your UI themselves.
Yes this fully possible. But are you shure that you want to do this using AppKit? Maybe better use crossplatform solution like QT that support skinning through CSS?

How can I tell if a process has a graphical interface on OSX?

Is there anyway, we can identify if the process has user interface? Anything which deals with drawing on screen.
I looked at this question, but it does not give proper answer. I am inside the process. Is there some api where i can query, or some technique?
EDIT: I am inside the process, I am doing code injection. I want to behave different for non gui apps than gui ones. I cannot use CFBundleGetValueForInfoDictionaryKey() or NSApplicationMain as I want to keep injection module light and thus I cannot link against these frameworks.
This depends heavily on what you mean by "has a graphical interface." Do you mean, "is displaying a window?" Or "has a dock icon?" Or "has access to the Aqua context such that it could display a window if it wanted to?" Or "is linked with AppKit?"
An app bundle that does not have a dock icon will have the Info.plist key LSUIElement set to "1". You can fetch this using CFBundleGetValueForInfoDictionaryKey() (or the NSBundle equivalent if you're in Objective-C). This does not mean the application has no GUI, but does mean it won't show up in the dock. Many LSUIElement apps have a status item UI.
You can also check that you actually have an Info.plist at all using CFBundleCopyBundleURL() or the like. If you don't have an Info.plist, then you're not going to be a "GUI-like" program in all likelihood. (Though again, it's possible to generate GUIs without this).
You can use weak linking to test for AppKit:
if (NSApplicationMain != NULL) {
// We're linked with AppKit
}
That's a fairly good indicator that you're going to have a UI. But it won't catch older Carbon apps.
Some more background on what you mean by "I am inside the process" would be helpful. I assume you're a framework and want to behave differently for GUI apps than for non-GUI apps?
To detect an application capable of drawing on the screen, I would check for whether CoreGraphics is linked. That'll only work for programs built since 10.3, but should be fairly accurate (I believe that old QuickDraw apps still link Core Graphics in 10.3+, but I don't have one handy to check). Probably the best way is to do a weak linking check against CGColorCreate() since it's been around for a long time and is unlikely to ever go away:
extern CGColorRef CGColorCreate(CGColorSpaceRef space, const CGFloat components[])
__attribute__((weak_import));
...
if (CGColorCreate != NULL) {
// Linked with CoreGraphics. Probably a GUI
Of course things can link with CoreGraphics and be capable of drawing on the screen, but never actually draw on the screen. They might link with CoreGraphics in order to do image processing. It might be more accurate by looking for ApplicationServices. You could test ApplicationServicesVersionNumber against NULL, but that's not documented.
This will not catch X apps, since they don't technically draw on the screen. They send commands to X11.app, which is a GUI. Do you consider /usr/X11/bin/xterm a GUI for this purpose? /usr/X11/bin/xeyes?
There is no particular flag I'm aware of in any app that says unambiguously "I draw on the screen." Drawing on the screen is not something you need to pre-declare. Apps that draw on the screen don't have to do so every time they run. Apps that are generally invisible might optionally or occasionally create a status item. It's hard to come up with a single description that includes GrowlHelperApp.app, Pages.app, and /usr/X11/bin/xeyes.

Keyboard shortcuts in iOS?

Is it possible to capture command-key sequences in 3rd party iPad/iPhone apps?
Long version:
On my excellent journey of discovery vis-a-vis my new iPad with it's gleaming keyboard dock, I discovered, much to my joy, that when editing text in standard issue text views; commands ranging from ⌘C/⌘P for copy-paste and ^A, ^B, ^E and friends for line and character jumping works.
So far so good, yeah? Problem is, this enthralling behaviour seems limited to text fields, and more specifically, standard issue text fields. What I would really like is to capture events like these for my own use.
An issue I often find with a lot of apps is that they tend to either be close to useless, or at least cumbersome, without the keyboard dock (e.g. the iWork Suite), or close to useless, or at least cumbersome, with the keyboard dock (most other applications that don't rely heavily on text input, but rather touch gestures [that is to say, most other applications period]).
Many games, for instance Civilization Revolutions, and similar, would benefit massively from just the simple addition of the ability to use the arrow keys to move units and the enter key to end turn.
So the question, then, as stated above: Is there a way to capture and respond to these events in order to offer an alternative to touch commands for those that desire this and have the hardware?
Disclaimer: I have no intention of developing applications that rely exclusively on keyboard input, of course, and nor should anyone else. The touch interface is paramount. It's just not always completely practical.
The only way (that I know of) to get input from the keyboard in iOS is using the UITextInput protocol. Unfortunately, the protocol doesn't give you the raw keys that were pressed, and instead sends you messages like "insert this string" and "move the caret to this position." So in order to know that an arrow key was pressed would require you to do some digging.
As for shortcuts with modifier keys, like copy/paste or undo/redo, Apple only seems to support the basics, and doesn't allow you to create custom ones. They use methods in UIResponder: –canPerformAction:withSender: and undoManager.
So if I were writing a game and wanted to take advantage of the keyboard I would subclass UIResponder and have it conform to the UITextInput protocol. And then make it the first responder. This however will probably bring up the software keyboard if a physical one is not present.
My own disclaimer: I haven't done all the hard work to use UITextInput in a way it wasn't meant to be used, so I don't know how feasible it would be to actually get it working. And I don't really want to. Rather, let's all file bug reports to get Apple to create an API that allows us to get more precise input from the keyboard.
In iOS 7, the UIResponder property keyCommands and the class UIKeyCommand were added to support shortcuts. Simply override keyCommands to return an array of UIKeyCommand and you should be good to go.
Worth mentioning: Though the details are currently under NDA, Apple is adding support for keyboard shortcuts/events in iOS 7.
I suspect it will work similarly to how it works on Mac OS X, which is briefly described in this answer to a similar question.

How do I programmatically change keyboard layout with Cocoa?

How can I programmatically change the keyboard layout in Cocoa?
Assume I have, say, two active ones "Estonian" and "U.S." in the System Preferences (i.e. those two layouts visible in the keyboard layout menu bar).
So how would I read that those two are available, and how would I programmatically change between them?
Use Text Input Source Services if you're on 10.5 or higher. It's based on CoreFoundation, so don't worry it's inside Carbon framework. If you need to support 10.4 or older, you need to use Keyboard Layout Services. I only know the former, so let me explain just that.
You use
CFArrayRef sourceList= TISCreateInputSourceList (NULL,false);
to get the array of TISInputSourceRef corresponding to all the enabled keyboard types. Then you can use other functions to examine them. To select/deselect one, you can use TISSelectInputSource and TISDeselectInputSource, etc.
Don't forget to CFRelease the array you got, though, even in the garbage collected environment, because the garbage-collection of CF objects are not automatic!