Given the key code of the pressed key without modifiers, I want to get the result of pressing the shift + key. Example: for a standard American keyboard, <shift> + <period> gives a value.
The relevant function is UCKeytranslate, but I need a little help getting the right information. Below is a snippet of the program, ready to run in Xcode. The purpose of the program is assigned <period> to create the character>.
The result of the program:
Keyboard: <TSMInputSource 0x10051a930> KB Layout: US (id=0) Layout: 0x0000000102802000 Status: -50 UnicodeString: 97 String: a Done Program ended with exit code: 0
The part that gets the layout seems to work, but the status code shows that something went wrong. But what?
import Foundation import Cocoa import Carbon import AppKit // The current text input source (read keyboard) has a layout in which // we can lookup how key-codes are resolved. // Get the a reference keyboard using the current layout. var unmanagedKeyboard = TISCopyCurrentKeyboardLayoutInputSource() var keyboard = unmanagedKeyboard.takeUnretainedValue() as TISInputSource print("Keyboard: ") ; println(keyboard) // Get the layout var ptrLayout = TISGetInputSourceProperty(keyboard, kTISPropertyUnicodeKeyLayoutData) var layout = UnsafeMutablePointer<UCKeyboardLayout>(ptrLayout) print("Layout: "); println(layout) // Let see what the result of pressing <shift> and <period> (hopefully the result is > ) var keycode = UInt16(kVK_ANSI_Period) // Keycode for <period> var keyaction = UInt16(kUCKeyActionDisplay) // The user is requesting information for key display var modifierKeyState = UInt32(1 << 17) // Shift var keyboardType = UInt32(LMGetKbdType()) var keyTranslateOptions = UInt32(1 << kUCKeyTranslateNoDeadKeysBit) var deadKeyState = UnsafeMutablePointer<UInt32>(bitPattern: 0) // Is 0 the correct value? var maxStringLength = UniCharCount(4) // uint32 var actualStringLength = UnsafeMutablePointer<UniCharCount>.alloc(1) // actualStringLength[0]=16 var unicodeString = UnsafeMutablePointer<UniChar>.alloc(255) unicodeString[0] = 97 // a (this value is meant to be overwritten by UCKeyTranslate) var str = NSString(characters: unicodeString, length: 1) var result = UCKeyTranslate(layout, keycode, keyaction, modifierKeyState, keyboardType, keyTranslateOptions, deadKeyState, maxStringLength, actualStringLength, unicodeString) // Print the results print("Status: "); println(result) var unichar = unicodeString[0]; print("UnicodeString: "); println(String(unichar)) print("String: "); println(str) println("Done")
EDIT
I rewrote the snippet after Ken Thomases suggestions. A few tricks: Graphite used the Swift program using key codes.
import Foundation import Cocoa import Carbon import AppKit // The current text input source (read keyboard) has a layout in which // we can lookup how key-codes are resolved. // Get the a reference keyboard using the current layout. let keyboard = TISCopyCurrentKeyboardInputSource().takeRetainedValue() let rawLayoutData = TISGetInputSourceProperty(keyboard, kTISPropertyUnicodeKeyLayoutData) print("Keyboard: ") ; println(keyboard) // Get the layout var layoutData = unsafeBitCast(rawLayoutData, CFDataRef.self) var layout: UnsafePointer<UCKeyboardLayout> = unsafeBitCast(CFDataGetBytePtr(layoutData), UnsafePointer<UCKeyboardLayout>.self) print("Layout: "); println(layout) print("KbdType "); println(LMGetKbdType()) // Sanity check (prints 44) var keycode = UInt16(kVK_ANSI_Period) // Keycode for a var keyaction = UInt16(kUCKeyActionDisplay) var modifierKeyState = UInt32(1 << 1) // Shift var keyboardType = UInt32(LMGetKbdType()) var keyTranslateOptions = OptionBits(kUCKeyTranslateNoDeadKeysBit) var deadKeyState = UInt32(0) // Is 0 the correct value? var maxStringLength = UniCharCount(4) // uint32 var chars: [UniChar] = [0,0,0,0] var actualStringLength = UniCharCount(1) var result = UCKeyTranslate(layout, keycode, keyaction, modifierKeyState, keyboardType, keyTranslateOptions, &deadKeyState, maxStringLength, &actualStringLength, &chars) // Print the results print("Status: "); println(result) print("Out:"); println(UnicodeScalar(chars[0])) println("Done")