I am trying to underline the title for NSButton in Xamarin.MacOS.
In the mutable attributed string, I use
attrString.AddAttribute(NSStringAttributeKey.UnderlineStyle, NSNumber.FromInt32((int)NSUnderlineStyle.Single), range);
It doesn't work. Suggestions in Swift is to use
let underlineAttribute = [NSAttributedString.Key.underlineStyle: NSUnderlineStyle.single.rawValue]
In Xamarin.MacOS, there is no NSUnderlineStyle.Single.RawValue. How do I get the RawValue of NSUnderlineStyle enum? Thanks.
I am adding underline like this:
str.AddAttribute(NSStringAttributeKey.UnderlineStyle, new NSNumber((int)NSUnderlineStyle.Single), new NSRange(0, str.Length));
I can confirm this works in both NSTextView and NSButton
First, a quick review. NSUnderlineStyle is an enumeration with the following values:
NSUnderlineStyleNone = 0x00,
NSUnderlineStyleSingle = 0x01,
NSUnderlineStyleThick = 0x02,
NSUnderlineStyleDouble = 0x09,
NSUnderlinePatternSolid = 0x0000,
NSUnderlinePatternDot = 0x0100,
NSUnderlinePatternDash = 0x0200,
NSUnderlinePatternDashDot = 0x0300,
NSUnderlinePatternDashDotDot = 0x0400,
NSUnderlineByWord = 0x8000
So we could check the following code
string prefixedHex = "0x01";
int intValue = Convert.ToInt32(prefixedHex, 16);
NSMutableAttributedString str = new NSMutableAttributedString();
str.AddAttribute(NSStringAttributeKey.UnderlineStyle,NSNumber.FromInt32(1),range);
button.AttributedTitle = str;
There is nothing wrong with the original code.
attrString.AddAttribute(NSStringAttributeKey.UnderlineStyle, NSNumber.FromInt32((int)NSUnderlineStyle.Single), range);
I have forgotten to set this attribute in the OnElementPropertyChanged function.
Thanks for your confirmation that it works which prompts me to re-investigate my code. I spent a few days debugging it thinking that the issue is with rawValue.
Related
I'm searching for a way to simulate keystrokes in OSX. I found another solution (Simulate keypress for system wide hotkeys) using Objective-C, but i need to do it with Swift. How can i adapt CGEventCreateKeyboardEvent?
Working with Swift 3
let src = CGEventSource(stateID: CGEventSourceStateID.hidSystemState)
let cmdd = CGEvent(keyboardEventSource: src, virtualKey: 0x38, keyDown: true)
let cmdu = CGEvent(keyboardEventSource: src, virtualKey: 0x38, keyDown: false)
let spcd = CGEvent(keyboardEventSource: src, virtualKey: 0x31, keyDown: true)
let spcu = CGEvent(keyboardEventSource: src, virtualKey: 0x31, keyDown: false)
spcd?.flags = CGEventFlags.maskCommand;
let loc = CGEventTapLocation.cghidEventTap
cmdd?.post(tap: loc)
spcd?.post(tap: loc)
spcu?.post(tap: loc)
cmdu?.post(tap: loc)
The code on that linked answer is fairly readily convertible to Swift code, however there are a handful of gotchas you will need to take care of along the way:
CGEventSourceCreate takes a CGEventSourceStateID, which is a typealiase for a UInt32, but the constants such as kCGEventSourceStateHIDSystemState are defined as Int, so you’ll have to cast them i.e. CGEventSourceStateID(kCGEventSourceStateHIDSystemState). Likewise with CGEventFlags.
CGEventSourceCreate and CGEventCreateKeyboardEvent return an Unmanaged<CGEventSource> (or Unmanaged<CGEvent>). The auto-generated Swift API for Core Graphics doesn’t know whether the returned objects need to be released by you or not so you need to check the API docs for these calls and then use takeRetainedValue() or takeUnretainedValue() accordingly on the returned value, to convert them into the underlying type you want to work with.
Finally, they return implicitly unwrapped optionals, so you’ll need to decide if you want to check for nils or just live with the excitement of runtime explosions if they ever return one.
Given all that it’s pretty simple to turn the Objective-C in that answer demonstrating pressing Cmd-Space to Swift, I just tried pasting this into a scratch app and it worked fine:
(though I haven't checked the API docs for whether the retain is the correct thing to do or not)
let src = CGEventSourceCreate(CGEventSourceStateID(kCGEventSourceStateHIDSystemState)).takeRetainedValue()
let cmdd = CGEventCreateKeyboardEvent(src, 0x38, true).takeRetainedValue()
let cmdu = CGEventCreateKeyboardEvent(src, 0x38, false).takeRetainedValue()
let spcd = CGEventCreateKeyboardEvent(src, 0x31, true).takeRetainedValue()
let spcu = CGEventCreateKeyboardEvent(src, 0x31, false).takeRetainedValue()
CGEventSetFlags(spcd, CGEventFlags(kCGEventFlagMaskCommand));
CGEventSetFlags(spcd, CGEventFlags(kCGEventFlagMaskCommand));
let loc = CGEventTapLocation(kCGHIDEventTap)
CGEventPost(loc, cmdd)
CGEventPost(loc, spcd)
CGEventPost(loc, spcu)
CGEventPost(loc, cmdu)
Swift 3
For me the hexadecimal key values like: 0x124 didn't work, but simple UInt 124 did the trick!
A nice collection of keycodes can be found here!
This copy-paste code snippet simulates a right arrow keypress. Change the key number for whatever you want to simulate:
// Simulate Right Arrow keypress
let rightArrowKeyCode: UInt16 = 124
let keyDownEvent = CGEvent(keyboardEventSource: nil, virtualKey: rightArrowKeyCode, keyDown: true)
keyDownEvent?.flags = CGEventFlags.maskCommand
keyDownEvent?.post(tap: CGEventTapLocation.cghidEventTap)
let keyUpEvent = CGEvent(keyboardEventSource: nil, virtualKey: rightArrowKeyCode, keyDown: false)
keyUpEvent?.flags = CGEventFlags.maskCommand
keyUpEvent?.post(tap: CGEventTapLocation.cghidEventTap)
Update:
For macOS Mojave and above you should allow your app to control your computer in System Preferences > Security & Privacy > Accessibility
I made this for a Swift 4 project, don't forget that App sandboxing will not allow an app to send keystrokes like this so it'll need to be turned off. This means your app would prohibited from the AppStore.
import Foundation
class FakeKey {
static func send(_ keyCode: CGKeyCode, useCommandFlag: Bool) {
let sourceRef = CGEventSource(stateID: .combinedSessionState)
if sourceRef == nil {
NSLog("FakeKey: No event source")
return
}
let keyDownEvent = CGEvent(keyboardEventSource: sourceRef,
virtualKey: keyCode,
keyDown: true)
if useCommandFlag {
keyDownEvent?.flags = .maskCommand
}
let keyUpEvent = CGEvent(keyboardEventSource: sourceRef,
virtualKey: keyCode,
keyDown: false)
keyDownEvent?.post(tap: .cghidEventTap)
keyUpEvent?.post(tap: .cghidEventTap)
}
}
A combination of the answers to stimulate a shortcut/hotkey. Swift 5.1
let source = CGEventSource(stateID: CGEventSourceStateID.hidSystemState)
let cmdKey: UInt16 = 0x38
let numberThreeKey: UInt16 = 0x14
let cmdDown = CGEvent(keyboardEventSource: source, virtualKey: cmdKey, keyDown: true)
let cmdUp = CGEvent(keyboardEventSource: source, virtualKey: cmdKey, keyDown: false)
let keyThreeDown = CGEvent(keyboardEventSource: source, virtualKey: numberThreeKey, keyDown: true)
let keyThreeUp = CGEvent(keyboardEventSource: source, virtualKey: numberThreeKey, keyDown: false)
fileprivate func testShortcut() {
let loc = CGEventTapLocation.cghidEventTap
cmdDown?.flags = CGEventFlags.maskCommand
cmdUp?.flags = CGEventFlags.maskCommand
keyThreeDown?.flags = CGEventFlags.maskCommand
keyThreeUp?.flags = CGEVentFlags.maskCommand
cmdDown?.post(tap: loc)
keyThreeDown?.post(tap: loc)
cmdUp?.post(tap: loc)
keyThreeUp?.post(tap: loc)
}
Manually written may contain mistakes.
I have problems with special characters when using JSON in xcode 6 with swift
I found these codes in Cocoa/objective C to solve some problems converting accent but could not make it work in Swift. Any suggestions for how to use it? ... best alternative suggestions would also be cool ...
Thanks
NSString *input = #"\\u5404\\u500b\\u90fd";
NSString *convertedString = [input mutableCopy];
CFStringRef transform = CFSTR("Any-Hex/Java");
CFStringTransform((__bridge CFMutableStringRef)convertedString, NULL, transform, YES);
NSLog(#"convertedString: %#", convertedString);
// prints: 各個都, tada!
It's fairly similar in Swift, though you still need to use the Foundation string classes:
let transform = "Any-Hex/Java"
let input = "\\u5404\\u500b\\u90fd" as NSString
var convertedString = input.mutableCopy() as NSMutableString
CFStringTransform(convertedString, nil, transform as NSString, 1)
println("convertedString: \(convertedString)")
// convertedString: 各個都
(The last parameter threw me for a loop until I realized that Boolean in Swift is a type alias for UInt - YES in Objective-C becomes 1 in Swift for these types of methods.)
Swift String extension:
extension String {
var unescapingUnicodeCharacters: String {
let mutableString = NSMutableString(string: self)
CFStringTransform(mutableString, nil, "Any-Hex/Java" as NSString, true)
return mutableString as String
}
}
Swift 3
let transform = "Any-Hex/Java"
let input = "\\u5404\\u500b\\u90fd" as NSString
var convertedString = input.mutableCopy() as! NSMutableString
CFStringTransform(convertedString, nil, transform as NSString, true)
print("convertedString: \(convertedString)")
// convertedString: 各個都
I have some code I've been using to get the current keyboard layout and convert a virtual key code into a string. This works great in most situations, but I'm having trouble with some specific cases. The one that brought this to light is the accent key next to the backspace key on german QWERTZ keyboards. http://en.wikipedia.org/wiki/File:KB_Germany.svg
That key generates the VK code I'd expect kVK_ANSI_Equal but when using a QWERTZ keyboard layout I get no description back. Its ending up as a dead key because its supposed to be composed with another key. Is there any way to catch these cases and do the proper conversion?
My current code is below.
TISInputSourceRef currentKeyboard = TISCopyCurrentKeyboardInputSource();
CFDataRef uchr = (CFDataRef)TISGetInputSourceProperty(currentKeyboard, kTISPropertyUnicodeKeyLayoutData);
const UCKeyboardLayout *keyboardLayout = (const UCKeyboardLayout*)CFDataGetBytePtr(uchr);
if(keyboardLayout)
{
UInt32 deadKeyState = 0;
UniCharCount maxStringLength = 255;
UniCharCount actualStringLength = 0;
UniChar unicodeString[maxStringLength];
OSStatus status = UCKeyTranslate(keyboardLayout,
keyCode, kUCKeyActionDown, 0,
LMGetKbdType(), kUCKeyTranslateNoDeadKeysBit,
&deadKeyState,
maxStringLength,
&actualStringLength, unicodeString);
if(actualStringLength > 0 && status == noErr)
return [[NSString stringWithCharacters:unicodeString length:(NSInteger)actualStringLength] uppercaseString];
}
That key is a dead key, as you can see if you try it yourself or look at the Keyboard Viewer with the German layout active.
On the Mac, the way to enter a dead key's actual character, without composing it with another character, is to press a space after it. So try that: Turn off kUCKeyTranslateNoDeadKeysBit, and if UCKeyTranslate sets the dead-key state, translate a space after it.
EDIT (added by asker)
Just for future people, here is the fixed code with the right solution.
TISInputSourceRef currentKeyboard = TISCopyCurrentKeyboardInputSource();
CFDataRef uchr = (CFDataRef)TISGetInputSourceProperty(currentKeyboard, kTISPropertyUnicodeKeyLayoutData);
const UCKeyboardLayout *keyboardLayout = (const UCKeyboardLayout*)CFDataGetBytePtr(uchr);
if(keyboardLayout)
{
UInt32 deadKeyState = 0;
UniCharCount maxStringLength = 255;
UniCharCount actualStringLength = 0;
UniChar unicodeString[maxStringLength];
OSStatus status = UCKeyTranslate(keyboardLayout,
keyCode, kUCKeyActionDown, 0,
LMGetKbdType(), 0,
&deadKeyState,
maxStringLength,
&actualStringLength, unicodeString);
if (actualStringLength == 0 && deadKeyState)
{
status = UCKeyTranslate(keyboardLayout,
kVK_Space, kUCKeyActionDown, 0,
LMGetKbdType(), 0,
&deadKeyState,
maxStringLength,
&actualStringLength, unicodeString);
}
if(actualStringLength > 0 && status == noErr)
return [[NSString stringWithCharacters:unicodeString length:(NSUInteger)actualStringLength] uppercaseString];
}
I am writing some regression tests in WatiN and needed to make a couple POST web requests. The requests are working fine but I get an annoying dialog box asking me if I want to save the file or find a program online to open it. The line of code that is causing this is:
browser.Navigate2(ref uri, ref nflags, ref ntargetFrame,
ref dataBytes, ref headers);
Is anyone familiar with the Navigate2() method? Any idea on how to get rid of this download box?
Here is my answer:
The Navigate2() method looks like this:
HRESULT Navigate2(
VARIANT *URL,
VARIANT *Flags,
VARIANT *TargetFrameName,
VARIANT *PostData,
VARIANT *Headers
);
the flags can be defined as enum BrowserNavConstants like this:
typedef enum BrowserNavConstants {
navOpenInNewWindow = 0x1,
navNoHistory = 0x2,
navNoReadFromCache = 0x4,
navNoWriteToCache = 0x8,
navAllowAutosearch = 0x10,
navBrowserBar = 0x20,
navHyperlink = 0x40,
navEnforceRestricted = 0x80,
navNewWindowsManaged = 0x0100,
navUntrustedForDownload = 0x0200,
navTrustedForActiveX = 0x0400,
navOpenInNewTab = 0x0800,
navOpenInBackgroundTab = 0x1000,
navKeepWordWheelText = 0x2000,
navVirtualTab = 0x4000,
navBlockRedirectsXDomain = 0x8000,
navOpenNewForegroundTab = 0x10000
} BrowserNavConstants;
I used navUnstrustedForDownload and it did away with the download box. Hope this helps someone somewhere
I created an "ObjectiveC.xctxtmacro" file in ~/Library/Application Support/Developer/Shared/Xcode/Specifications with the code bellow. I see "Hello" in Xcode's Edit>Insert Text Macros>Objective-C menu item but when I try to invoke it using control-dot, nothing happens. Any ideas?
(
{
Identifier = objc.hello;
BasedOn = objc;
IsMenuItem = YES;
Name = "Hello";
TextString = "Hello, Xcode!";
CompletionPrefix = "hello";
IncludeContexts = ("xcode.lang.objc");
}
)
You need to add an OnlyAtBOL specification to your macro.
Try this:
(
{
Identifier = objc.hello;
BasedOn = objc;
OnlyAtBOL = YES;
IsMenuItem = YES;
Name = "Hello";
TextString = "Hello, Xcode!";
CompletionPrefix = "hello";
IncludeContexts = ("xcode.lang.objc");
}
)
I am pretty new at text macros, but as far as i understand OnlyAtBOL means that this text macro will complete only when it is at the beggining of the line (YES) or not (NO).
It seems weird that it does not work without this specification, i don' t know if it' s a bug or feature :)
You might want to check this topic, since its probably the same thing you are trying to do:
http://forums.pragprog.com/forums/104/topics/3334