如何使用UCKeyTranslate
How to use UCKeyTranslate
给定一个没有修饰符的键的键码,我想产生按下 shift+键的结果。示例:对于标准美式键盘,+ 给出 >.
相关函数是 UCKeytranslate,但我需要一些帮助才能正确了解细节。下面的代码片段是一个完整的程序,可以在 Xcode 中运行。程序的意图是 以产生字符 >。
程序的结果是:
Keyboard: <TSMInputSource 0x10051a930> KB Layout: U.S. (id=0)
Layout: 0x0000000102802000
Status: -50
UnicodeString: 97
String: a
Done
Program ended with exit code: 0
获取布局的部分似乎可以正常工作,但状态代码表明出了点问题。但是什么?
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's 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")
编辑
我已经按照 Ken Thomases 的建议重写了代码片段。
一些技巧来自:Graphite 还使用了使用键码的 Swift 程序。
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")
对于kTISPropertyUnicodeKeyLayoutData
,TISGetInputSourceProperty()
return一个CFDataRef
。您需要获取其字节指针并将其视为指向 UCKeyboardLayout
的指针。我不认为那是你用这条线做的:
var layout = UnsafeMutablePointer<UCKeyboardLayout>(ptrLayout)
我真的不知道 Swift,但它可能会像:
var layout = UnsafePointer<UCKeyboardLayout>(CFDataGetBytePtr(ptrLayout))
或者也许:
var layout = CFDataGetBytePtr(ptrLayout) as UnsafePointer<UCKeyboardLayout>
此外,kUCKeyActionDisplay
几乎没有用。它的目的是 return 键的标签,但它甚至不能可靠地做到这一点。您可能想使用 kUCKeyActionDown
.
对于修饰符,您想使用 Carbon-era shiftKey
位掩码右移 8 位(如 UCKeyTranslate()
的文档中所示)。 shiftKey
是 1 << 9
,所以 shiftKey >> 8
是 1 << 1
。
对于选项,为了简单起见,您应该可以使用 kUCKeyTranslateNoDeadKeysMask
。相当于1 << kUCKeyTranslateNoDeadKeysBit
.
是的,对于 deadKeyState
初始击键或您不想应用任何先前的死键状态的击键,0 是正确的值。
我不确定你为什么用 uint32
评论 maxStringLength
行。该类型与最大字符串长度完全无关。 maxStringLength
是 UCKeyTranslate()
应该写入提供的缓冲区的 UTF-16 代码单元的最大数量(API 错误地调用 "characters")。它基本上是缓冲区大小,以 UniChar
s(不是字节)为单位测量。在你的情况下,它应该是 255。或者,由于你可能不希望从一次击键中获得 255 "characters",你可以减小缓冲区的大小并设置 maxStringLength
以匹配它是什么.
您对 str
的处理方式很奇怪。在调用 UCKeyTranslate()
之前,您从 unicodeString
缓冲区构造它。您是否希望由于 UCKeyTranslate()
更改 unicodeString
的内容而更改字符串对象的值?它不是。如果是这样,那将是 NSString
中的一个非常严重的错误。在 UCKeyTranslate()
成功填充该缓冲区后,您应该从缓冲区 构造 NSString
。当然,在构造NSString
.
时,应该将actualStringLength
作为长度参数传入
给定一个没有修饰符的键的键码,我想产生按下 shift+键的结果。示例:对于标准美式键盘,
相关函数是 UCKeytranslate,但我需要一些帮助才能正确了解细节。下面的代码片段是一个完整的程序,可以在 Xcode 中运行。程序的意图是
程序的结果是:
Keyboard: <TSMInputSource 0x10051a930> KB Layout: U.S. (id=0)
Layout: 0x0000000102802000
Status: -50
UnicodeString: 97
String: a
Done
Program ended with exit code: 0
获取布局的部分似乎可以正常工作,但状态代码表明出了点问题。但是什么?
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's 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")
编辑
我已经按照 Ken Thomases 的建议重写了代码片段。 一些技巧来自:Graphite 还使用了使用键码的 Swift 程序。
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")
对于kTISPropertyUnicodeKeyLayoutData
,TISGetInputSourceProperty()
return一个CFDataRef
。您需要获取其字节指针并将其视为指向 UCKeyboardLayout
的指针。我不认为那是你用这条线做的:
var layout = UnsafeMutablePointer<UCKeyboardLayout>(ptrLayout)
我真的不知道 Swift,但它可能会像:
var layout = UnsafePointer<UCKeyboardLayout>(CFDataGetBytePtr(ptrLayout))
或者也许:
var layout = CFDataGetBytePtr(ptrLayout) as UnsafePointer<UCKeyboardLayout>
此外,kUCKeyActionDisplay
几乎没有用。它的目的是 return 键的标签,但它甚至不能可靠地做到这一点。您可能想使用 kUCKeyActionDown
.
对于修饰符,您想使用 Carbon-era shiftKey
位掩码右移 8 位(如 UCKeyTranslate()
的文档中所示)。 shiftKey
是 1 << 9
,所以 shiftKey >> 8
是 1 << 1
。
对于选项,为了简单起见,您应该可以使用 kUCKeyTranslateNoDeadKeysMask
。相当于1 << kUCKeyTranslateNoDeadKeysBit
.
是的,对于 deadKeyState
初始击键或您不想应用任何先前的死键状态的击键,0 是正确的值。
我不确定你为什么用 uint32
评论 maxStringLength
行。该类型与最大字符串长度完全无关。 maxStringLength
是 UCKeyTranslate()
应该写入提供的缓冲区的 UTF-16 代码单元的最大数量(API 错误地调用 "characters")。它基本上是缓冲区大小,以 UniChar
s(不是字节)为单位测量。在你的情况下,它应该是 255。或者,由于你可能不希望从一次击键中获得 255 "characters",你可以减小缓冲区的大小并设置 maxStringLength
以匹配它是什么.
您对 str
的处理方式很奇怪。在调用 UCKeyTranslate()
之前,您从 unicodeString
缓冲区构造它。您是否希望由于 UCKeyTranslate()
更改 unicodeString
的内容而更改字符串对象的值?它不是。如果是这样,那将是 NSString
中的一个非常严重的错误。在 UCKeyTranslate()
成功填充该缓冲区后,您应该从缓冲区 构造 NSString
。当然,在构造NSString
.
actualStringLength
作为长度参数传入