2015-01-01 2 views
5

Учитывая код клавиши для нажатия клавиши без модификаторов, я хочу получить результат нажатия клавиши shift +. Пример: для стандартной американской клавиатуры < shift> + < период> дает>.Как использовать 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") 

EDIT

Я переписан сниппет следующие предложения Кена Томасов. Несколько трюков от: 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

Я получаю сообщение об ошибке «Использование Uneclared типа UCKeyboardLayout» с этим кодом. Любая идея, как это исправить? –

+1

В документах для 10.10.3 указано, что структура 'UCKeyboardLayout' была удалена. Вам нужно посмотреть, что заменило его. https://developer.apple.com/library/mac/releasenotes/General/APIDiffsMacOSX10_10_3/modules/CoreServices.html – soegaard

+1

PS: Я пробовал искать его, но в документах для 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) 

Я действительно не знаю, Swift, но это вероятно, будет работать как:

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

или, может быть:

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

Также kUCKeyActionDisplay в основном бесполезен. Его цель - вернуть ярлык ключа, но он даже не делает этого надежно. Возможно, вы захотите использовать kUCKeyActionDown.

Для модификаторов вы хотите использовать битовую матрицу Carbon-era shiftKey, сдвинутую вправо 8 бит (как показано в документации для UCKeyTranslate()). shiftKey есть 1 << 9, поэтому shiftKey >> 8 есть 1 << 1.

Для удобства вы можете использовать kUCKeyTranslateNoDeadKeysMask для простоты. Это эквивалентно 1 << kUCKeyTranslateNoDeadKeysBit.

Да, 0 - правильное значение для deadKeyState для начального нажатия клавиши или для тех случаев, когда вы не хотите применять предыдущее состояние мертвой зоны.

Я не уверен, почему вы прокомментировали строку maxStringLength с uint32. Этот тип полностью не связан с максимальной длиной строки. maxStringLength - это максимальное количество кодовых блоков UTF-16 (что неверно называют API-символы), UCKeyTranslate() должен записывать в предоставленный буфер. Это в основном размер буфера, измеренный в UniChar s (а не байтах). В вашем случае это должно быть 255. Или, поскольку вы, вероятно, не ожидаете получить 255 «символов» из одного нажатия клавиши, вы можете уменьшить размер буфера и установить maxStringLength в соответствии с тем, что он есть.

Ваше отношение к str странно.Вы создаете его из буфера unicodeString перед вызовом UCKeyTranslate(). Вы ожидаете, что значение строкового объекта будет изменено, потому что UCKeyTranslate() изменяет содержимое unicodeString? Это не. Если бы это было так, это было бы очень плохой ошибкой в ​​NSString. Вы должны построить NSString из буфера после того, какUCKeyTranslate() успешно заполнил этот буфер. Конечно, вы должны передать actualStringLength в качестве параметра длины при построении NSString.

+0

Большое спасибо за ваши предложения. Я чувствую, что приближаюсь к решению - мне просто нужно взломать проблему CFDataGetBytePtr. Причиной для комментария uint32 является то, что я пишу привязки для UCKeyTranslate и нуждаюсь в базовом типе C. Программа Swift - получить рабочий пример, который я могу имитировать с помощью FFI. – soegaard

+0

Спасибо за ваш тщательный ответ. – soegaard

Смежные вопросы