簡體   English   中英

如何使用 UCKeyTranslate

[英]How to use UCKeyTranslate

給定一個沒有修飾符的按鍵的鍵碼,我想產生按下 shift+ 鍵的結果。 示例:對於標准的美式鍵盤,<shift>+<period> 給出 >。

相關功能是 UCKeytranslate,但我需要一些幫助才能正確了解細節。 下面的代碼片段是一個可以在 Xcode 中運行的完整程序。 程序的意圖被賦予 <period> 來產生字符 >。

程序的結果是:

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")

對於kTISPropertyUnicodeKeyLayoutDataTISGetInputSourceProperty()返回一個CFDataRef 您需要獲取其字節指針並將其視為指向UCKeyboardLayout的指針。 我不認為這就是你對這條線所做的:

var layout = UnsafeMutablePointer<UCKeyboardLayout>(ptrLayout)

我不太了解 Swift,但它可能會用作:

var layout = UnsafePointer<UCKeyboardLayout>(CFDataGetBytePtr(ptrLayout))

或者可能:

var layout = CFDataGetBytePtr(ptrLayout) as UnsafePointer<UCKeyboardLayout>

此外, kUCKeyActionDisplay大多沒用。 它的目的是返回密鑰的標簽,但它甚至不能可靠地做到這一點。 您可能想使用kUCKeyActionDown

對於修飾符,您希望使用碳時代的shiftKey位掩碼右移 8 位(如UCKeyTranslate()的文檔中所示)。 shiftKey1 << 9 ,所以shiftKey >> 81 << 1

對於選項,為了簡單起見,您應該能夠使用kUCKeyTranslateNoDeadKeysMask 它相當於1 << kUCKeyTranslateNoDeadKeysBit

是的,0 是用於初始擊鍵或您不想應用任何先前死鍵狀態的deadKeyState的正確值。

我不確定你為什么用uint32評論maxStringLength行。 該類型與最大字符串長度完全無關。 maxStringLengthUCKeyTranslate()應寫入提供的緩沖區的最大 UTF-16 代碼單元數(API 錯誤地稱之為“字符”)。 它基本上是緩沖區大小,以UniChar s(而不是字節)為單位。 在您的情況下,它應該是 255。或者,由於您可能不希望從一次擊鍵中獲得 255 個“字符”,您可以減少緩沖區的大小並設置maxStringLength以匹配它是什么。

你對str處理很奇怪。 您在調用UCKeyTranslate()之前從unicodeString緩沖區構造它。 您是否希望因為UCKeyTranslate()更改unicodeString的內容而更改字符串對象的值? 它不是。 如果確實如此,那將是NSString一個非常糟糕的錯誤。 UCKeyTranslate()成功填充該緩沖區后,您應該從緩沖區構造NSString 當然,在構造NSString時,您應該將actualStringLength作為長度參數傳遞。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM