2015-01-01 8 views
5

수정 자없이 누른 키에 대한 키 코드가 주어지면 Shift + 키를 누른 결과를 생성하려고합니다. 예 : 표준 미국 키보드의 경우 < shift> + < period> 제공>.UCKeyTranslate 사용 방법

관련 함수는 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") 

편집

나는 켄 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") 
+1

이 코드와 함께 '선언되지 않은 유형의 사용'UCKeyboardLayout '이 표시됩니다. 어떤 생각을 고칠 수 있을까요? –

+1

10.10.3의 문서에서 구조체 'UCKeyboardLayout'이 제거되었다고합니다. 대체 한 것을보아야합니다. https://developer.apple.com/library/mac/releasenotes/General/APIDiffsMacOSX10_10/3/modules/CoreServices.html – soegaard

+1

추신 : 그것을 찾으려고했지만 UCKeyboardLayout의 문서에는 Swift가 전혀 언급되어 있지 않습니다. https : //developer.apple.com/library/mac/documentation/Carbon/Reference/Unicode_Utilities_Ref/#//apple_ref/doc/c_ref/UCKeyboardLayout – soegaard

답변

5

kTISPropertyUnicodeKeyLayoutData를 들어, TISGetInputSourceProperty()CFDataRef 반환합니다. 바이트 포인터를 가져와 UCKeyboardLayout에 대한 포인터로 처리해야합니다. 나는 당신이이 라인에 무슨 일을하는지 생각하지 않습니다 :

var layout = UnsafeMutablePointer<UCKeyboardLayout>(ptrLayout) 

정말 스위프트 모르겠지만, 아마 일하는 것이 : 어쩌면

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

나 :

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

또한 kUCKeyActionDisplay은 거의 쓸모가 없습니다. 그것의 의도는 키의 레이블을 반환하는 것이지만, 그렇게하지는 않습니다. kUCKeyActionDown을 사용하고 싶을 것입니다.

수정 자에 대해서는 UCKeyTranslate()의 설명서에 표시된대로 탄소 시대비트 마스크를 오른쪽으로 8 비트 이동했습니다. shiftKey1 << 9이므로 shiftKey >> 81 << 1입니다.

옵션의 경우 간단하게 kUCKeyTranslateNoDeadKeysMask을 사용할 수 있어야합니다. 1 << kUCKeyTranslateNoDeadKeysBit과 같습니다.

예, 0은 초기 키 입력 또는 이전의 데드 - 키 상태를 적용하지 않으려는 경우에 대한 deadKeyState의 적절한 값입니다.

maxStringLength 라인을 uint32으로 주석 처리했는지 확실하지 않습니다. 이 유형은 최대 문자열 길이와 완전히 관련이 없습니다. maxStringLengthUCKeyTranslate()이 제공된 버퍼에 쓸 수있는 최대 UTF-16 코드 단위 수 (API가 잘못 "문자"라고 부르는 것)입니다. 기본적으로 버퍼 크기는 UniChar (바이트가 아님)으로 측정됩니다. 귀하의 경우에는 255 여야합니다. 또는 하나의 키 스트로크에서 255 개의 "문자"를 가져올 것으로 예상하지 않기 때문에 버퍼의 크기를 줄이고 maxStringLength을 일치시킬 수 있습니다.

str의 취급이 이상합니다.UCKeyTranslate()을 호출하기 전에 unicodeString 버퍼에서 구성하십시오. UCKeyTranslate()unicodeString의 내용을 변경하기 때문에 문자열 개체의 값이 변경되기를 기대합니까? 그렇지 않습니다. 그렇다면 NSString에서 매우 나쁜 버그가됩니다.UCKeyTranslate()이 버퍼를 성공적으로 채운 후에 버퍼 에서 NSString을 생성해야합니다. 물론 NSString을 구성 할 때 길이 매개 변수로 actualStringLength을 전달해야합니다.

+0

제안 해 주셔서 대단히 감사드립니다. 솔루션에 가까워지고 있다고 느낍니다. CFDataGetBytePtr 문제를 해결해야합니다. uint32 주석의 이유는 UCKeyTranslate에 대한 바인딩을 작성하고 기본 C 유형이 필요하기 때문입니다. 스위프트 프로그램은 FFI와 모방 할 수있는 실례를 얻는 것입니다. – soegaard

+0

철저한 답변 주셔서 감사합니다. – soegaard