2013-08-02 3 views
0

함수 CGEventKeyboardSetUnicodeString은 UniCharCount 및 const UniChar unicodeString []을 사용합니다. pyobjc를 사용하여 파이썬에서 이것을 어떻게 호출 할 수 있는지 알아 내는데 어려움이 있습니다. 이상적으로, 나는 파이썬 유니 코드 문자열을 전달할 수 있기를 원합니다. 이 기능을위한 메타 데이터를 수정할 수있는 방법이 있나요? 또는 파이썬 유니 코드 문자열을 유니 코드 배열과 pyobjc 배열로 변환하는 방법이 있습니까?파이썬에서 CGEventKeyboardSetUnicodeString을 어떻게 호출 할 수 있습니까?

가 명확히하기 위해 : 나는

CGEventKeyboardSetUnicodeString의 메타 데이터 pyobjc의 버전 2.5.1을 사용하고

: 나는 시도했다

>>> pprint(CGEventKeyboardSetUnicodeString.__metadata__()) 
{'arguments': ({'already_cfretained': False, 
      'already_retained': False, 
      'null_accepted': True, 
      'type': '^{__CGEvent=}'}, 
      {'already_cfretained': False, 
      'already_retained': False, 
      'type': 'L'}, 
      {'already_cfretained': False, 
      'already_retained': False, 
      'null_accepted': True, 
      'type': '^T'}), 
'retval': {'already_cfretained': False, 
     'already_retained': False, 
     'type': 'v'}, 
'variadic': False} 

을 다음

>>> CGEventKeyboardSetUnicodeString(event, 1, 'a') 
Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
ValueError: depythonifying 'pointer', got 'str' 

>>> CGEventKeyboardSetUnicodeString(event, 1, u'a') 
Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
ValueError: depythonifying 'pointer', got 'unicode' 

>>> CGEventKeyboardSetUnicodeString(event, 1, [ord('a')]) 
Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
ValueError: depythonifying 'pointer', got 'list' 

>>> Quartz.CGEventKeyboardSetUnicodeString(event, 1, struct.unpack('>{}H'.format(1), u'a'.encode('utf-16-le'))) 
Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
ValueError: depythonifying 'pointer', got 'tuple' 
+0

OK, 그것은 (최신 애플 릴리스 2.3.2a0이기 때문에, 당신은 수동으로 설치해야합니다) PyObjC 2.5.1처럼 보이는 내가 얘기 한 수정 프로그램이 ... 분명히 올바른 해결책이 아닙니다. 내가 한번 보자. – abarnert

+0

Python 3.3.0 또는 2.7.5를 사용하여 2.4.0 또는 최상위 PyObjC에서이를 테스트 할 때 인수에 대해 서로 다른 정확한 메타 데이터를 얻습니다. 타입은'n^T'이며'c_array_length_in_arg = 1'을가집니다. 그리고 파이썬'unicode' 객체를 전달하면 잘 동작합니다. 당신은'CoreGraphics'가 아닌'Quartz'에서 함수를 사용하고 있습니다, 그렇죠? – abarnert

+0

더보기 ... PyObjC 2.4.0이이 기능을 수정 한 것처럼 보입니다. 2.5.0이 (다른 방식으로) 다시 손상되었을 수 있으며, 2.6.0이 다시 수정 될 수 있습니다. 확실하지는 않지만, 내가 테스트 할 수있는 모든 버전을 설치하고, 내가 알 때 다시보고 할 것이다. 내가 옳다면 가장 좋은 해결 방법은 2.6 bridgesupport 파일을 2.5.1로 복사하는 것일 수도 있고 그렇지 않을 수도 있습니다 ...하지만 다시 한 번 알려 드리겠습니다. – abarnert

답변

2

UniChar * 문자열을 사용하는 함수는 결코 쉽게 호출 할 수 없지만 해결 방법이 있습니다. 불행하게도, 2.5의 경우, 처음으로 또 다른 문제를 해결하지 않으면 그 해결 방법이 작동하지 않습니다. 먼저 이전 버전의 해결 방법에 대해 설명하고 2.5로 돌아갑니다.

PyObjC의 이전 버전에서 UniChar *을 취하는 함수의 매개 변수 유형은 unsigned short * (메타 데이터에 '^S')으로 선언되었습니다. 이후 버전에서는 올바르게 UniChar * (즉, '^T')입니다. 그러나 PyObjC는 이것을 문자열 유형으로 보지 않으며 0-65535의 정수 시퀀스로 간주합니다. 그래서, 당신이 그것을 통과해야합니다.


당신이 unicode 모든 그 문자 BMP 영역에, * 그 그냥 ord 문자열의 각 문자의의의 가지고있어. 어느 쉽게 다음 Get 기능은 또한 우리에게 짧은 INT의 순서가 아닌 unicode을 반환

>>> s = u'abc' 
>>> e = Quartz.CGEventCreateKeyboardEvent(None, 0, True) 
>>> Quartz.CGEventKeyboardSetUnicodeString(e, len(s), map(ord, s)) 
>>> slen, swords = Quartz.CGEventKeyboardGetUnicodeString(e, 100, None, None) 
>>> slen 
3 
>>> u''.join(map(unichr, swords)) 
u'abc' 

하는 것으로.


하지만 BMP가 아닌 문자가 있거나있을 수 있습니다. UniChar *은 유니 코드 문자 시퀀스가 ​​아닌 일련의 UTF-16 코드 포인트이므로 UTF-16으로 인코딩해야합니다. 명시 적으로 (그리고 나서 struct.unpack 값을 얻으려면 H 값 목록을 얻습니다), 더 쉬운 방법이 있습니다 : CFString 또는 NSString UTF-16 코드 포인트 시퀀스입니다. 방금 대신 unicodeNSString으로하지만, 원래의 코드를 사용한다면, 그것은 작동합니다

>>> s = u'abc\U00010000d' 
>>> nss = Foundation.NSString.stringWithString_(s) 
>>> len(s), len(nss) 
(5, 6, 6) 
>>> Quartz.CGEventKeyboardSetUnicodeString(e, len(nss), map(ord, nss)) 

자신이 많은이 일을 찾아내는 경우에, 당신은 아마 간단한 래퍼를 작성하려면 :

def to_unichr(s): 
    nss = Foundation.NSStringWithString_(s) 
    return len(nss), map(ord, nss) 

그래서 당신은이 작업을 수행 할 수 있습니다

Quartz.CGEventKeyboardSetUnicodeString(e, *to_unichr(s)) 

위의 모든 것은 Python 2 용입니다.x를 사용할 수 있지만 3.x에서는 동일한 프리픽스 (3.2 및 이전 버전)를 삭제하고 map(…) 대신 list(map(…))을 사용하는 한 3.x에서 동일하게 작동해야합니다.


한편 PyObjC 2.5는 브리지 지원 메타 데이터가 선언되는 방식을 변경하고 많은 메타 데이터의 세부 사항을 변경했습니다. 내가 알 수있는 한 2.5.0 또는 2.5.1로이 함수를 호출하는 것은 사실상 불가능합니다. 자세한 내용은 issue #64을 참조하십시오.

_C_IN ('n') 유형 수정자가 삭제 된 것 같습니다. 입력 인수 포인터를 예상하는 함수에 시퀀스를 전달할 수 있으며 PyObjC는 자동으로 적절하게 변환하지만 출력, 인 아웃 또는 지정되지 않은 포인터에서는 작동하지 않는 명백한 이유로 인해 시퀀스를 전달할 수 있습니다.

메타 데이터를 직접 수정하여이 문제를 해결할 수 있습니다. 2.5.1에서는 파일 Quartz/CoreGraphics/_metadata.py에서 29 행의 문자 1351 (또는 간단히 CGEventKeyboardSetUnicodeString을 검색)에서이를 확인할 수 있습니다. 두 개의 값을 튜플에 추가해야합니다. 대신이의 :

'CGEventKeyboardSetUnicodeString': (sel32or64(b'v^{__CGEvent=}L^T', b'v^{__CGEvent=}Q^T'),) 

당신이 필요합니다 그 변화와 함께

'CGEventKeyboardSetUnicodeString': (sel32or64(b'v^{__CGEvent=}L^T', b'v^{__CGEvent=}Q^T'), '', {'arguments': {2: {'type_modifier': 'n'}}}) 

을 해결 방법은 위의 2.5.0 또는 2.5.1와 함께 작동합니다.


*이 또한 ASCII 문자가있는 str/bytes 객체와 작동하지만 그렇게하지 않습니다.

+0

@abarnet 응답 해 주셔서 감사합니다. 위의 모든 옵션을 시도했지만 안타깝게도 pyobjc 버전에서 작동하지 않았습니다. 반바지 나 NSString의 목록을 전달할 때 : 'ValueError :'포인터 '를 depythonifying하고'list '또는'ValueError : 포인터를 depythonifying ','objc.pyobjc_unicode '를 가져 왔습니다. 마지막으로 타입을'^ T'로 바꾸라고 제안했으나 이미 그런 식으로 보입니다.세 번째 인수에 대한 –

+0

메타 데이터는 다음과 같습니다 '{ 'already_cfretained'거짓, 는 'already_retained'거짓, 는 'null_accepted': 사실, '유형': '^ T'}' –

+0

이 댓글이 매우 제한 공간의 양 때문에 위의 질문을 업데이트했습니다. –

0

나는 전화를 걸기 위해 ctypes를 사용할 수 있고 pyobjc로도 잘 작동한다는 것을 알았습니다. 그러나 누군가 pyobjc로이 작업을 수행하는 방법을 알고 있다면 그 답을 기꺼이 받아 들일 것입니다.

내 솔루션은 다음과 같습니다

import ctypes 
import ctypes.util 
import objc 
import Quartz 
import sys 

event = Quartz.CGEventCreateKeyboardEvent(None, 0, True) 
cf = ctypes.cdll.LoadLibrary(ctypes.util.find_library('ApplicationServices')) 
cf.CGEventKeyboardSetUnicodeString.restype = None 
event_id = objc.pyobjc_id(event) 
s = u'\U0001F600' 
utf16_native = 'utf-16-le' if sys.byteorder == 'little' else 'utf-16-be' 
buf = s.encode(utf16_native) 
cf.CGEventKeyboardSetUnicodeString(event_id, len(buf)/2, buf) 
Quartz.CGEventPost(Quartz.kCGSessionEventTap, event) 
+0

pyobjc의 결핍으로 인해 필요한 경우 실제로는 필요하지 않습니다.) 실제로는 올바르지 않습니다. OS X'wchar_t '는 4 바이트 타입이며,'UniChar '는 2 바이트 타입입니다. 효과적으로 UTF-32로 변환 한 다음 UTF-16이 필요한 코드로 전달합니다. 물론이 테스트 케이스에서는'a' 다음에'\ u0000'이 표시 될 것이기 때문에 복수형 문자열 (또는 BMP에없는 단일 문자)의 경우에는 그렇지 않습니다. – abarnert

+0

감사! BMP 외부의 캐릭터와는 작동하지 않는다는 것을 알았지 만 그 이유를 알지 못했습니다. 예를 업데이트했습니다. –

+0

그래, 내가 문제를 찾은 것 같아요, 당신은 기능 메타 데이터를 수정하고자하는 경우 해결 방법을 가지고 있고, 나는 버그를 제기했습니다. 과거의 역사에 근거하여 Ronald Oussoren은 곧 고칠 것이고, 종종 그렇듯이 내가 잘못한 것을 설명하고 그것을 고칠 필요가없는 이유를 설명 할 것입니다. 그것은 나에게도 충분합니다. 그러나 2.5.x로 작업해야하는 경우 몇 가지 해결 방법이 필요합니다. – abarnert

관련 문제