git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@54115 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
This commit is contained in:
Stefan Csomor
2008-06-11 16:26:59 +00:00
parent 82e7574281
commit 9acbdb4313
8 changed files with 3488 additions and 0 deletions

732
src/mac/core/cfstring.cpp Normal file
View File

@@ -0,0 +1,732 @@
/////////////////////////////////////////////////////////////////////////////
// Name: src/mac/corefoundation/cfstring.cpp
// Purpose: wxCFStringHolder and other string functions
// Author: Stefan Csomor
// Modified by:
// Created: 2004-10-29 (from code in src/mac/carbon/utils.cpp)
// RCS-ID: $Id$
// Copyright: (c) Stefan Csomor
// Licence: wxWindows licence
// Usage: Darwin (base library)
/////////////////////////////////////////////////////////////////////////////
#include "wx/wxprec.h"
#ifndef WX_PRECOMP
#include "wx/string.h"
#include "wx/intl.h"
#if wxUSE_GUI
#include "wx/font.h"
#endif
#endif
#include "wx/mac/corefoundation/cfstring.h"
#include <CoreFoundation/CoreFoundation.h>
void wxMacConvertNewlines13To10( char * data )
{
char * buf = data ;
while( (buf=strchr(buf,0x0d)) != NULL )
{
*buf = 0x0a ;
buf++ ;
}
}
void wxMacConvertNewlines10To13( char * data )
{
char * buf = data ;
while( (buf=strchr(buf,0x0a)) != NULL )
{
*buf = 0x0d ;
buf++ ;
}
}
const wxString sCR((wxChar)13);
const wxString sLF((wxChar)10);
void wxMacConvertNewlines13To10( wxString * data )
{
data->Replace( sCR,sLF);
}
void wxMacConvertNewlines10To13( wxString * data )
{
data->Replace( sLF,sCR);
}
wxUint32 wxMacGetSystemEncFromFontEnc(wxFontEncoding encoding)
{
CFStringEncoding enc = 0 ;
if ( encoding == wxFONTENCODING_DEFAULT )
{
#if wxUSE_GUI
encoding = wxFont::GetDefaultEncoding() ;
#else
encoding = wxFONTENCODING_SYSTEM; // to be set below
#endif
}
if ( encoding == wxFONTENCODING_SYSTEM )
{
enc = CFStringGetSystemEncoding();
}
switch( encoding)
{
case wxFONTENCODING_ISO8859_1 :
enc = kCFStringEncodingISOLatin1 ;
break ;
case wxFONTENCODING_ISO8859_2 :
enc = kCFStringEncodingISOLatin2;
break ;
case wxFONTENCODING_ISO8859_3 :
enc = kCFStringEncodingISOLatin3 ;
break ;
case wxFONTENCODING_ISO8859_4 :
enc = kCFStringEncodingISOLatin4;
break ;
case wxFONTENCODING_ISO8859_5 :
enc = kCFStringEncodingISOLatinCyrillic;
break ;
case wxFONTENCODING_ISO8859_6 :
enc = kCFStringEncodingISOLatinArabic;
break ;
case wxFONTENCODING_ISO8859_7 :
enc = kCFStringEncodingISOLatinGreek;
break ;
case wxFONTENCODING_ISO8859_8 :
enc = kCFStringEncodingISOLatinHebrew;
break ;
case wxFONTENCODING_ISO8859_9 :
enc = kCFStringEncodingISOLatin5;
break ;
case wxFONTENCODING_ISO8859_10 :
enc = kCFStringEncodingISOLatin6;
break ;
case wxFONTENCODING_ISO8859_13 :
enc = kCFStringEncodingISOLatin7;
break ;
case wxFONTENCODING_ISO8859_14 :
enc = kCFStringEncodingISOLatin8;
break ;
case wxFONTENCODING_ISO8859_15 :
enc = kCFStringEncodingISOLatin9;
break ;
case wxFONTENCODING_KOI8 :
enc = kCFStringEncodingKOI8_R;
break ;
case wxFONTENCODING_ALTERNATIVE : // MS-DOS CP866
enc = kCFStringEncodingDOSRussian;
break ;
/*
case wxFONTENCODING_BULGARIAN :
enc = ;
break ;
*/
case wxFONTENCODING_CP437 :
enc =kCFStringEncodingDOSLatinUS ;
break ;
case wxFONTENCODING_CP850 :
enc = kCFStringEncodingDOSLatin1;
break ;
case wxFONTENCODING_CP852 :
enc = kCFStringEncodingDOSLatin2;
break ;
case wxFONTENCODING_CP855 :
enc = kCFStringEncodingDOSCyrillic;
break ;
case wxFONTENCODING_CP866 :
enc =kCFStringEncodingDOSRussian ;
break ;
case wxFONTENCODING_CP874 :
enc = kCFStringEncodingDOSThai;
break ;
case wxFONTENCODING_CP932 :
enc = kCFStringEncodingDOSJapanese;
break ;
case wxFONTENCODING_CP936 :
enc = kCFStringEncodingDOSChineseSimplif ;
break ;
case wxFONTENCODING_CP949 :
enc = kCFStringEncodingDOSKorean;
break ;
case wxFONTENCODING_CP950 :
enc = kCFStringEncodingDOSChineseTrad;
break ;
case wxFONTENCODING_CP1250 :
enc = kCFStringEncodingWindowsLatin2;
break ;
case wxFONTENCODING_CP1251 :
enc =kCFStringEncodingWindowsCyrillic ;
break ;
case wxFONTENCODING_CP1252 :
enc =kCFStringEncodingWindowsLatin1 ;
break ;
case wxFONTENCODING_CP1253 :
enc = kCFStringEncodingWindowsGreek;
break ;
case wxFONTENCODING_CP1254 :
enc = kCFStringEncodingWindowsLatin5;
break ;
case wxFONTENCODING_CP1255 :
enc =kCFStringEncodingWindowsHebrew ;
break ;
case wxFONTENCODING_CP1256 :
enc =kCFStringEncodingWindowsArabic ;
break ;
case wxFONTENCODING_CP1257 :
enc = kCFStringEncodingWindowsBalticRim;
break ;
#if 0
case wxFONTENCODING_UTF7 :
enc = CreateTextEncoding(kCFStringEncodingUnicodeDefault,0,kUnicodeUTF7Format) ;
#endif
break ;
case wxFONTENCODING_UTF8 :
enc = kCFStringEncodingUTF8;
break ;
case wxFONTENCODING_EUC_JP :
enc = kCFStringEncodingEUC_JP;
break ;
case wxFONTENCODING_UTF16BE :
enc = kCFStringEncodingUTF16BE;
break ;
case wxFONTENCODING_UTF16LE :
enc = kCFStringEncodingUTF16LE;
break ;
case wxFONTENCODING_UTF32BE :
enc = kCFStringEncodingUTF32BE;
break ;
case wxFONTENCODING_UTF32LE :
enc = kCFStringEncodingUTF32LE;
break ;
case wxFONTENCODING_MACROMAN :
enc = kCFStringEncodingMacRoman ;
break ;
case wxFONTENCODING_MACJAPANESE :
enc = kCFStringEncodingMacJapanese ;
break ;
case wxFONTENCODING_MACCHINESETRAD :
enc = kCFStringEncodingMacChineseTrad ;
break ;
case wxFONTENCODING_MACKOREAN :
enc = kCFStringEncodingMacKorean ;
break ;
case wxFONTENCODING_MACARABIC :
enc = kCFStringEncodingMacArabic ;
break ;
case wxFONTENCODING_MACHEBREW :
enc = kCFStringEncodingMacHebrew ;
break ;
case wxFONTENCODING_MACGREEK :
enc = kCFStringEncodingMacGreek ;
break ;
case wxFONTENCODING_MACCYRILLIC :
enc = kCFStringEncodingMacCyrillic ;
break ;
case wxFONTENCODING_MACDEVANAGARI :
enc = kCFStringEncodingMacDevanagari ;
break ;
case wxFONTENCODING_MACGURMUKHI :
enc = kCFStringEncodingMacGurmukhi ;
break ;
case wxFONTENCODING_MACGUJARATI :
enc = kCFStringEncodingMacGujarati ;
break ;
case wxFONTENCODING_MACORIYA :
enc = kCFStringEncodingMacOriya ;
break ;
case wxFONTENCODING_MACBENGALI :
enc = kCFStringEncodingMacBengali ;
break ;
case wxFONTENCODING_MACTAMIL :
enc = kCFStringEncodingMacTamil ;
break ;
case wxFONTENCODING_MACTELUGU :
enc = kCFStringEncodingMacTelugu ;
break ;
case wxFONTENCODING_MACKANNADA :
enc = kCFStringEncodingMacKannada ;
break ;
case wxFONTENCODING_MACMALAJALAM :
enc = kCFStringEncodingMacMalayalam ;
break ;
case wxFONTENCODING_MACSINHALESE :
enc = kCFStringEncodingMacSinhalese ;
break ;
case wxFONTENCODING_MACBURMESE :
enc = kCFStringEncodingMacBurmese ;
break ;
case wxFONTENCODING_MACKHMER :
enc = kCFStringEncodingMacKhmer ;
break ;
case wxFONTENCODING_MACTHAI :
enc = kCFStringEncodingMacThai ;
break ;
case wxFONTENCODING_MACLAOTIAN :
enc = kCFStringEncodingMacLaotian ;
break ;
case wxFONTENCODING_MACGEORGIAN :
enc = kCFStringEncodingMacGeorgian ;
break ;
case wxFONTENCODING_MACARMENIAN :
enc = kCFStringEncodingMacArmenian ;
break ;
case wxFONTENCODING_MACCHINESESIMP :
enc = kCFStringEncodingMacChineseSimp ;
break ;
case wxFONTENCODING_MACTIBETAN :
enc = kCFStringEncodingMacTibetan ;
break ;
case wxFONTENCODING_MACMONGOLIAN :
enc = kCFStringEncodingMacMongolian ;
break ;
case wxFONTENCODING_MACETHIOPIC :
enc = kCFStringEncodingMacEthiopic ;
break ;
case wxFONTENCODING_MACCENTRALEUR :
enc = kCFStringEncodingMacCentralEurRoman ;
break ;
case wxFONTENCODING_MACVIATNAMESE :
enc = kCFStringEncodingMacVietnamese ;
break ;
case wxFONTENCODING_MACARABICEXT :
enc = kCFStringEncodingMacExtArabic ;
break ;
case wxFONTENCODING_MACSYMBOL :
enc = kCFStringEncodingMacSymbol ;
break ;
case wxFONTENCODING_MACDINGBATS :
enc = kCFStringEncodingMacDingbats ;
break ;
case wxFONTENCODING_MACTURKISH :
enc = kCFStringEncodingMacTurkish ;
break ;
case wxFONTENCODING_MACCROATIAN :
enc = kCFStringEncodingMacCroatian ;
break ;
case wxFONTENCODING_MACICELANDIC :
enc = kCFStringEncodingMacIcelandic ;
break ;
case wxFONTENCODING_MACROMANIAN :
enc = kCFStringEncodingMacRomanian ;
break ;
case wxFONTENCODING_MACCELTIC :
enc = kCFStringEncodingMacCeltic ;
break ;
case wxFONTENCODING_MACGAELIC :
enc = kCFStringEncodingMacGaelic ;
break ;
case wxFONTENCODING_MACKEYBOARD :
enc = 41; /* kTextEncodingMacKeyboardGlyphs ; */
break ;
default : // to make gcc happy
break ;
};
return enc ;
}
wxFontEncoding wxMacGetFontEncFromSystemEnc(wxUint32 encoding)
{
wxFontEncoding enc = wxFONTENCODING_DEFAULT ;
switch( encoding)
{
case kCFStringEncodingISOLatin1 :
enc = wxFONTENCODING_ISO8859_1 ;
break ;
case kCFStringEncodingISOLatin2 :
enc = wxFONTENCODING_ISO8859_2;
break ;
case kCFStringEncodingISOLatin3 :
enc = wxFONTENCODING_ISO8859_3 ;
break ;
case kCFStringEncodingISOLatin4 :
enc = wxFONTENCODING_ISO8859_4;
break ;
case kCFStringEncodingISOLatinCyrillic :
enc = wxFONTENCODING_ISO8859_5;
break ;
case kCFStringEncodingISOLatinArabic :
enc = wxFONTENCODING_ISO8859_6;
break ;
case kCFStringEncodingISOLatinGreek :
enc = wxFONTENCODING_ISO8859_7;
break ;
case kCFStringEncodingISOLatinHebrew :
enc = wxFONTENCODING_ISO8859_8;
break ;
case kCFStringEncodingISOLatin5 :
enc = wxFONTENCODING_ISO8859_9;
break ;
case kCFStringEncodingISOLatin6 :
enc = wxFONTENCODING_ISO8859_10;
break ;
case kCFStringEncodingISOLatin7 :
enc = wxFONTENCODING_ISO8859_13;
break ;
case kCFStringEncodingISOLatin8 :
enc = wxFONTENCODING_ISO8859_14;
break ;
case kCFStringEncodingISOLatin9 :
enc =wxFONTENCODING_ISO8859_15 ;
break ;
case kCFStringEncodingKOI8_R :
enc = wxFONTENCODING_KOI8;
break ;
/*
case :
enc = wxFONTENCODING_BULGARIAN;
break ;
*/
case kCFStringEncodingDOSLatinUS :
enc = wxFONTENCODING_CP437;
break ;
case kCFStringEncodingDOSLatin1 :
enc = wxFONTENCODING_CP850;
break ;
case kCFStringEncodingDOSLatin2 :
enc =wxFONTENCODING_CP852 ;
break ;
case kCFStringEncodingDOSCyrillic :
enc = wxFONTENCODING_CP855;
break ;
case kCFStringEncodingDOSRussian :
enc = wxFONTENCODING_CP866;
break ;
case kCFStringEncodingDOSThai :
enc =wxFONTENCODING_CP874 ;
break ;
case kCFStringEncodingDOSJapanese :
enc = wxFONTENCODING_CP932;
break ;
case kCFStringEncodingDOSChineseSimplif :
enc = wxFONTENCODING_CP936;
break ;
case kCFStringEncodingDOSKorean :
enc = wxFONTENCODING_CP949;
break ;
case kCFStringEncodingDOSChineseTrad :
enc = wxFONTENCODING_CP950;
break ;
case kCFStringEncodingWindowsLatin2 :
enc = wxFONTENCODING_CP1250;
break ;
case kCFStringEncodingWindowsCyrillic :
enc = wxFONTENCODING_CP1251;
break ;
case kCFStringEncodingWindowsLatin1 :
enc = wxFONTENCODING_CP1252;
break ;
case kCFStringEncodingWindowsGreek :
enc = wxFONTENCODING_CP1253;
break ;
case kCFStringEncodingWindowsLatin5 :
enc = wxFONTENCODING_CP1254;
break ;
case kCFStringEncodingWindowsHebrew :
enc = wxFONTENCODING_CP1255;
break ;
case kCFStringEncodingWindowsArabic :
enc = wxFONTENCODING_CP1256;
break ;
case kCFStringEncodingWindowsBalticRim :
enc =wxFONTENCODING_CP1257 ;
break ;
case kCFStringEncodingEUC_JP :
enc = wxFONTENCODING_EUC_JP;
break ;
case kCFStringEncodingUTF8 :
enc = wxFONTENCODING_UTF8;
break ;
case kCFStringEncodingUTF16BE :
enc = wxFONTENCODING_UTF16BE;
break ;
case kCFStringEncodingUTF16LE :
enc = wxFONTENCODING_UTF16LE;
break ;
case kCFStringEncodingUTF32BE :
enc = wxFONTENCODING_UTF32BE;
break ;
case kCFStringEncodingUTF32LE :
enc = wxFONTENCODING_UTF32LE;
break ;
#if 0
case wxFONTENCODING_UTF7 :
enc = CreateTextEncoding(kCFStringEncodingUnicodeDefault,0,kUnicodeUTF7Format) ;
break ;
#endif
case kCFStringEncodingMacRoman :
enc = wxFONTENCODING_MACROMAN ;
break ;
case kCFStringEncodingMacJapanese :
enc = wxFONTENCODING_MACJAPANESE ;
break ;
case kCFStringEncodingMacChineseTrad :
enc = wxFONTENCODING_MACCHINESETRAD ;
break ;
case kCFStringEncodingMacKorean :
enc = wxFONTENCODING_MACKOREAN ;
break ;
case kCFStringEncodingMacArabic :
enc =wxFONTENCODING_MACARABIC ;
break ;
case kCFStringEncodingMacHebrew :
enc = wxFONTENCODING_MACHEBREW ;
break ;
case kCFStringEncodingMacGreek :
enc = wxFONTENCODING_MACGREEK ;
break ;
case kCFStringEncodingMacCyrillic :
enc = wxFONTENCODING_MACCYRILLIC ;
break ;
case kCFStringEncodingMacDevanagari :
enc = wxFONTENCODING_MACDEVANAGARI ;
break ;
case kCFStringEncodingMacGurmukhi :
enc = wxFONTENCODING_MACGURMUKHI ;
break ;
case kCFStringEncodingMacGujarati :
enc = wxFONTENCODING_MACGUJARATI ;
break ;
case kCFStringEncodingMacOriya :
enc =wxFONTENCODING_MACORIYA ;
break ;
case kCFStringEncodingMacBengali :
enc =wxFONTENCODING_MACBENGALI ;
break ;
case kCFStringEncodingMacTamil :
enc = wxFONTENCODING_MACTAMIL ;
break ;
case kCFStringEncodingMacTelugu :
enc = wxFONTENCODING_MACTELUGU ;
break ;
case kCFStringEncodingMacKannada :
enc = wxFONTENCODING_MACKANNADA ;
break ;
case kCFStringEncodingMacMalayalam :
enc = wxFONTENCODING_MACMALAJALAM ;
break ;
case kCFStringEncodingMacSinhalese :
enc = wxFONTENCODING_MACSINHALESE ;
break ;
case kCFStringEncodingMacBurmese :
enc = wxFONTENCODING_MACBURMESE ;
break ;
case kCFStringEncodingMacKhmer :
enc = wxFONTENCODING_MACKHMER ;
break ;
case kCFStringEncodingMacThai :
enc = wxFONTENCODING_MACTHAI ;
break ;
case kCFStringEncodingMacLaotian :
enc = wxFONTENCODING_MACLAOTIAN ;
break ;
case kCFStringEncodingMacGeorgian :
enc = wxFONTENCODING_MACGEORGIAN ;
break ;
case kCFStringEncodingMacArmenian :
enc = wxFONTENCODING_MACARMENIAN ;
break ;
case kCFStringEncodingMacChineseSimp :
enc = wxFONTENCODING_MACCHINESESIMP ;
break ;
case kCFStringEncodingMacTibetan :
enc = wxFONTENCODING_MACTIBETAN ;
break ;
case kCFStringEncodingMacMongolian :
enc = wxFONTENCODING_MACMONGOLIAN ;
break ;
case kCFStringEncodingMacEthiopic :
enc = wxFONTENCODING_MACETHIOPIC ;
break ;
case kCFStringEncodingMacCentralEurRoman:
enc = wxFONTENCODING_MACCENTRALEUR ;
break ;
case kCFStringEncodingMacVietnamese:
enc = wxFONTENCODING_MACVIATNAMESE ;
break ;
case kCFStringEncodingMacExtArabic :
enc = wxFONTENCODING_MACARABICEXT ;
break ;
case kCFStringEncodingMacSymbol :
enc = wxFONTENCODING_MACSYMBOL ;
break ;
case kCFStringEncodingMacDingbats :
enc = wxFONTENCODING_MACDINGBATS ;
break ;
case kCFStringEncodingMacTurkish :
enc = wxFONTENCODING_MACTURKISH ;
break ;
case kCFStringEncodingMacCroatian :
enc = wxFONTENCODING_MACCROATIAN ;
break ;
case kCFStringEncodingMacIcelandic :
enc = wxFONTENCODING_MACICELANDIC ;
break ;
case kCFStringEncodingMacRomanian :
enc = wxFONTENCODING_MACROMANIAN ;
break ;
case kCFStringEncodingMacCeltic :
enc = wxFONTENCODING_MACCELTIC ;
break ;
case kCFStringEncodingMacGaelic :
enc = wxFONTENCODING_MACGAELIC ;
break ;
case 41 /* kTextEncodingMacKeyboardGlyphs */ :
enc = wxFONTENCODING_MACKEYBOARD ;
break ;
} ;
return enc ;
}
//
// CFStringRefs
//
// converts this string into a core foundation string with optional pc 2 mac encoding
wxCFStringRef::wxCFStringRef( const wxString &st , wxFontEncoding WXUNUSED_IN_UNICODE(encoding) )
{
if (st.IsEmpty())
{
reset( wxCFRetain( CFSTR("") ) );
}
else
{
wxString str = st ;
wxMacConvertNewlines13To10( &str ) ;
#if wxUSE_UNICODE
#if SIZEOF_WCHAR_T == 2
reset( CFStringCreateWithCharacters( kCFAllocatorDefault,
(UniChar*)str.wc_str() , str.Len() ) );
#else
wxMBConvUTF16 converter ;
size_t unicharbytes = converter.FromWChar( NULL , 0 , str.wc_str() , str.Length() ) ;
wxASSERT( unicharbytes != wxCONV_FAILED );
if ( unicharbytes == wxCONV_FAILED )
{
// create an empty string
reset( wxCFRetain( CFSTR("") ) );
}
else
{
// unicharbytes: number of bytes needed for UTF-16 encoded string (without terminating null)
// unichars: number of UTF-16 characters (without terminating null)
size_t unichars = unicharbytes / sizeof(UniChar) ;
UniChar *unibuf = new UniChar[ unichars ] ;
converter.FromWChar( (char*)unibuf , unicharbytes , str.wc_str() , str.Length() ) ;
reset( CFStringCreateWithCharacters( kCFAllocatorDefault , unibuf , unichars ) ) ;
delete[] unibuf ;
}
#endif
#else // not wxUSE_UNICODE
reset( CFStringCreateWithCString( kCFAllocatorSystemDefault , str.c_str() ,
wxMacGetSystemEncFromFontEnc( encoding ) ) );
#endif
}
}
wxString wxCFStringRef::AsString(wxFontEncoding WXUNUSED_IN_UNICODE(encoding))
{
if ( !get() )
return wxEmptyString ;
Size cflen = CFStringGetLength( get() ) ;
size_t noChars ;
wxChar* buf = NULL ;
#if wxUSE_UNICODE
#if SIZEOF_WCHAR_T == 2
buf = new wxChar[ cflen + 1 ] ;
CFStringGetCharacters( get() , CFRangeMake( 0 , cflen ) , (UniChar*) buf ) ;
noChars = cflen ;
#else
UniChar* unibuf = new UniChar[ cflen + 1 ] ;
CFStringGetCharacters( get() , CFRangeMake( 0 , cflen ) , (UniChar*) unibuf ) ;
unibuf[cflen] = 0 ;
wxMBConvUTF16 converter ;
noChars = converter.MB2WC( NULL , (const char*)unibuf , 0 ) ;
wxASSERT_MSG( noChars != wxCONV_FAILED, _T("Unable to count the number of characters in this string!") );
buf = new wxChar[ noChars + 1 ] ;
noChars = converter.MB2WC( buf , (const char*)unibuf , noChars + 1 ) ;
wxASSERT_MSG( noChars != wxCONV_FAILED, _T("Conversion of string failed!") );
delete[] unibuf ;
#endif
#else
CFIndex cStrLen ;
CFStringGetBytes( get() , CFRangeMake(0, cflen) , wxMacGetSystemEncFromFontEnc( encoding ) ,
'?' , false , NULL , 0 , &cStrLen ) ;
buf = new wxChar[ cStrLen + 1 ] ;
CFStringGetBytes( get() , CFRangeMake(0, cflen) , wxMacGetSystemEncFromFontEnc( encoding ) ,
'?' , false , (unsigned char*) buf , cStrLen , &cStrLen) ;
noChars = cStrLen ;
#endif
buf[noChars] = 0 ;
wxString result(buf) ;
delete[] buf ;
wxMacConvertNewlines10To13( &result);
return result ;
}
//
// wxMacUniCharBuffer
//
wxMacUniCharBuffer::wxMacUniCharBuffer( const wxString &str )
{
m_chars = str.length() ;
m_ubuf = NULL ;
#if SIZEOF_WCHAR_T == 4
wxMBConvUTF16 converter ;
#if wxUSE_UNICODE
size_t unicharlen = converter.WC2MB( NULL , str.wc_str() , 0 ) ;
m_ubuf = (UniChar*) malloc( unicharlen + 2 ) ;
converter.WC2MB( (char*) m_ubuf , str.wc_str(), unicharlen + 2 ) ;
#else
const wxWCharBuffer wchar = str.wc_str( wxConvLocal ) ;
size_t unicharlen = converter.WC2MB( NULL , wchar.data() , 0 ) ;
m_ubuf = (UniChar*) malloc( unicharlen + 2 ) ;
converter.WC2MB( (char*) m_ubuf , wchar.data() , unicharlen + 2 ) ;
#endif
m_chars = unicharlen / 2 ;
#else // SIZEOF_WCHAR_T is then 2
#if wxUSE_UNICODE
m_ubuf = malloc( m_chars * 2 + 2 ) ;
memcpy( m_ubuf , (UniChar*) str.wc_str() , m_chars * 2 + 2 ) ;
#else
wxWCharBuffer wchar = str.wc_str( wxConvLocal ) ;
m_chars = wxWcslen( wchar.data() ) ;
m_ubuf = malloc( m_chars * 2 + 2 ) ;
memcpy( m_ubuf , (UniChar*) wchar.data() , m_chars * 2 + 2 ) ;
#endif
#endif
}
wxMacUniCharBuffer::~wxMacUniCharBuffer()
{
free( m_ubuf ) ;
}
UniCharPtr wxMacUniCharBuffer::GetBuffer()
{
return m_ubuf ;
}
UniCharCount wxMacUniCharBuffer::GetChars()
{
return m_chars ;
}

318
src/mac/core/gsockosx.cpp Normal file
View File

@@ -0,0 +1,318 @@
/* -------------------------------------------------------------------------
* Project: GSocket (Generic Socket) for WX
* Name: src/mac/corefoundation/gsockosx.c
* Purpose: GSocket: Mac OS X mach-o part
* CVSID: $Id$
* Mac code by Brian Victor, February 2002. Email comments to bhv1@psu.edu
* ------------------------------------------------------------------------- */
#include "wx/wxprec.h"
#if wxUSE_SOCKETS
#include "wx/gsocket.h"
#include "wx/apptrait.h"
#include <CoreFoundation/CoreFoundation.h>
// ----------------------------------------------------------------------------
// Mac-specific data associated with each socket by GSocketCFManager
// ----------------------------------------------------------------------------
class MacGSocketData
{
public:
// default ctor creates the object in uninitialized state, use Initialize()
// later to make it usable
MacGSocketData()
{
m_socket = NULL;
m_source = NULL;
}
// initialize the data associated with the given socket
bool Initialize(GSocket *socket)
{
wxASSERT_MSG( !IsInitialized(), "shouldn't be called twice" );
// we need a valid Unix socket to create a CFSocket
if ( socket->m_fd < 0 )
return false;
CFSocketContext cont;
cont.version = 0; // this currently must be 0
cont.info = socket; // pointer passed to our callback
cont.retain = NULL; // no need to retain/release/copy the
cont.release = NULL; // socket pointer, so all callbacks
cont.copyDescription = NULL; // can be left NULL
m_socket = CFSocketCreateWithNative
(
NULL, // default allocator
socket->m_fd,
kCFSocketReadCallBack |
kCFSocketWriteCallBack |
kCFSocketConnectCallBack,
SocketCallback,
&cont
);
if ( !m_socket )
return false;
m_source = CFSocketCreateRunLoopSource(NULL, m_socket, 0);
return m_source != NULL;
}
// free the objects created by Initialize()
~MacGSocketData()
{
if ( m_source )
CFRelease(m_source);
if ( m_socket )
CFRelease(m_socket);
}
// return true if Initialize() had already been called successfully
bool IsInitialized() const { return m_source && m_socket; }
// accessors: should only be called if IsInitialized()
CFSocketRef GetSocket() const
{
wxASSERT( IsInitialized() );
return m_socket;
}
CFRunLoopSourceRef GetSource() const
{
wxASSERT( IsInitialized() );
return m_source;
}
private:
static void SocketCallback(CFSocketRef WXUNUSED(s),
CFSocketCallBackType callbackType,
CFDataRef WXUNUSED(address),
const void* data,
void* info)
{
GSocket * const socket = wx_static_cast(GSocket *, info);
MacGSocketData * const
macdata = wx_static_cast(MacGSocketData *, socket->m_gui_dependent);
if ( !macdata )
return;
switch (callbackType)
{
case kCFSocketConnectCallBack:
wxASSERT(!socket->m_server);
// KH: If data is non-NULL, the connect failed, do not call Detected_Write,
// which will only end up creating a spurious connect event because the
// call to getsocketopt SO_ERROR inexplicably returns no error.
// The change in behavior cannot be traced to any particular commit or
// timeframe so I'm not sure what to think, but after so many hours,
// this seems to address the issue and it's time to move on.
if (data == NULL)
socket->Detected_Write();
break;
case kCFSocketReadCallBack:
socket->Detected_Read();
break;
case kCFSocketWriteCallBack:
socket->Detected_Write();
break;
default:
wxFAIL_MSG( "unexpected socket callback" );
}
}
CFSocketRef m_socket;
CFRunLoopSourceRef m_source;
DECLARE_NO_COPY_CLASS(MacGSocketData);
};
// ----------------------------------------------------------------------------
// CoreFoundation implementation of GSocketManager
// ----------------------------------------------------------------------------
class GSocketCFManager : public GSocketManager
{
public:
virtual bool OnInit();
virtual void OnExit();
virtual bool Init_Socket(GSocket *socket);
virtual void Destroy_Socket(GSocket *socket);
virtual void Install_Callback(GSocket *socket, GSocketEvent event);
virtual void Uninstall_Callback(GSocket *socket, GSocketEvent event);
virtual void Enable_Events(GSocket *socket);
virtual void Disable_Events(GSocket *socket);
private:
// retrieve our custom data associated with the given socket
//
// this is a low level function, use GetInitializedData() instead if the
// data pointer should also be correctly initialized if it hadn't been done
// yet
//
// may return NULL if we hadn't created the data for this socket yet
MacGSocketData *GetData(GSocket *socket) const
{
return wx_static_cast(MacGSocketData *, socket->m_gui_dependent);
}
// return the custom data pointer initializing it if it hadn't been done
// yet
//
// may return NULL if there is no associated data
MacGSocketData *GetInitializedData(GSocket *socket) const
{
MacGSocketData * const data = GetData(socket);
if ( data && !data->IsInitialized() )
{
if ( !data->Initialize(socket) )
return NULL;
}
return data;
}
// return CFSocket callback mask corresponding to the given event (the
// socket parameter is needed because some events are interpreted
// differently depending on whether they happen on a server or on a client
// socket)
static int GetCFCallback(GSocket *socket, GSocketEvent event);
// Sockets must use the event loop on the main thread so we store a
// reference to the main loop here in OnInit()
static CFRunLoopRef ms_mainRunLoop;
};
CFRunLoopRef GSocketCFManager::ms_mainRunLoop = NULL;
bool GSocketCFManager::OnInit()
{
// No need to store the main loop again
if (ms_mainRunLoop != NULL)
return true;
// Get the loop for the main thread so our events will actually fire.
// The common socket.cpp code will assert if initialize is called from a
// secondary thread, otherwise Mac would have the same problems as MSW
ms_mainRunLoop = CFRunLoopGetCurrent();
if ( !ms_mainRunLoop )
return false;
CFRetain(ms_mainRunLoop);
return true;
}
void GSocketCFManager::OnExit()
{
// Release the reference count, and set the reference back to NULL
CFRelease(ms_mainRunLoop);
ms_mainRunLoop = NULL;
}
bool GSocketCFManager::Init_Socket(GSocket *socket)
{
socket->m_gui_dependent = new MacGSocketData;
return true;
}
void GSocketCFManager::Destroy_Socket(GSocket *socket)
{
MacGSocketData * const data = GetData(socket);
if ( data )
{
delete data;
socket->m_gui_dependent = NULL;
}
}
/* static */
int GSocketCFManager::GetCFCallback(GSocket *socket, GSocketEvent event)
{
switch ( event )
{
case GSOCK_CONNECTION:
return socket->m_server ? kCFSocketReadCallBack
: kCFSocketConnectCallBack;
case GSOCK_LOST:
case GSOCK_INPUT:
return kCFSocketReadCallBack;
case GSOCK_OUTPUT:
return kCFSocketWriteCallBack;
case GSOCK_MAX_EVENT:
wxFAIL_MSG( "invalid GSocketEvent" );
return 0;
default:
wxFAIL_MSG( "unknown GSocketEvent" );
return 0;
}
}
void GSocketCFManager::Install_Callback(GSocket *socket, GSocketEvent event)
{
const MacGSocketData * const data = GetInitializedData(socket);
if ( !data )
return;
CFSocketEnableCallBacks(data->GetSocket(), GetCFCallback(socket, event));
}
void GSocketCFManager::Uninstall_Callback(GSocket *socket, GSocketEvent event)
{
const MacGSocketData * const data = GetInitializedData(socket);
if ( !data )
return;
CFSocketDisableCallBacks(data->GetSocket(), GetCFCallback(socket, event));
}
void GSocketCFManager::Enable_Events(GSocket *socket)
{
const MacGSocketData * const data = GetInitializedData(socket);
if ( !data )
return;
CFRunLoopAddSource(ms_mainRunLoop, data->GetSource(), kCFRunLoopCommonModes);
}
void GSocketCFManager::Disable_Events(GSocket *socket)
{
const MacGSocketData * const data = GetInitializedData(socket);
if ( !data )
return;
// CFSocketInvalidate does CFRunLoopRemoveSource anyway
CFRunLoopRemoveSource(ms_mainRunLoop, data->GetSource(), kCFRunLoopCommonModes);
CFSocketInvalidate(data->GetSocket());
// CFSocketInvalidate has closed the socket so we want to make sure GSocket knows this
socket->m_fd = -1;
}
GSocketManager *wxAppTraits::GetSocketManager()
{
static GSocketCFManager s_manager;
return &s_manager;
};
#endif // wxUSE_SOCKETS

741
src/mac/core/hid.cpp Normal file
View File

@@ -0,0 +1,741 @@
/////////////////////////////////////////////////////////////////////////////
// Name: src/mac/corefoundation/hid.cpp
// Purpose: DARWIN HID layer for WX Implementation
// Author: Ryan Norton
// Modified by:
// Created: 11/11/2003
// RCS-ID: $Id$
// Copyright: (c) Ryan Norton
// Licence: wxWindows licence
/////////////////////////////////////////////////////////////////////////////
// ===========================================================================
// declarations
// ===========================================================================
// ---------------------------------------------------------------------------
// headers
// ---------------------------------------------------------------------------
// For compilers that support precompilation, includes "wx.h".
#include "wx/wxprec.h"
#ifdef __BORLANDC__
#pragma hdrstop
#endif
//DARWIN _ONLY_
#ifdef __DARWIN__
#include "wx/mac/corefoundation/hid.h"
#ifndef WX_PRECOMP
#include "wx/dynarray.h"
#include "wx/string.h"
#include "wx/log.h"
#include "wx/utils.h"
#include "wx/module.h"
#endif
#include "wx/mac/corefoundation/cfstring.h"
// ============================================================================
// implementation
// ============================================================================
// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
//
// wxHIDDevice
//
// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
// ----------------------------------------------------------------------------
// wxHIDDevice::Create
//
// nClass is the HID Page such as
// kHIDPage_GenericDesktop
// nType is the HID Usage such as
// kHIDUsage_GD_Joystick,kHIDUsage_GD_Mouse,kHIDUsage_GD_Keyboard
// nDev is the device number to use
//
// ----------------------------------------------------------------------------
bool wxHIDDevice::Create (int nClass, int nType, int nDev)
{
//Create the mach port
if(IOMasterPort(bootstrap_port, &m_pPort) != kIOReturnSuccess)
{
wxLogSysError(wxT("Could not create mach port"));
return false;
}
//Dictionary that will hold first
//the matching dictionary for determining which kind of devices we want,
//then later some registry properties from an iterator (see below)
//
//The call to IOServiceMatching filters down the
//the services we want to hid services (and also eats the
//dictionary up for us (consumes one reference))
CFMutableDictionaryRef pDictionary = IOServiceMatching(kIOHIDDeviceKey);
if(pDictionary == NULL)
{
wxLogSysError( _T("IOServiceMatching(kIOHIDDeviceKey) failed") );
return false;
}
//Here we'll filter down the services to what we want
if (nType != -1)
{
CFNumberRef pType = CFNumberCreate(kCFAllocatorDefault,
kCFNumberIntType, &nType);
CFDictionarySetValue(pDictionary, CFSTR(kIOHIDPrimaryUsageKey), pType);
CFRelease(pType);
}
if (nClass != -1)
{
CFNumberRef pClass = CFNumberCreate(kCFAllocatorDefault,
kCFNumberIntType, &nClass);
CFDictionarySetValue(pDictionary, CFSTR(kIOHIDPrimaryUsagePageKey), pClass);
CFRelease(pClass);
}
//Now get the maching services
io_iterator_t pIterator;
if( IOServiceGetMatchingServices(m_pPort,
pDictionary, &pIterator) != kIOReturnSuccess )
{
wxLogSysError(_T("No Matching HID Services"));
return false;
}
//Were there any devices matched?
if(pIterator == 0)
return false; // No devices found
//Now we iterate through them
io_object_t pObject;
while ( (pObject = IOIteratorNext(pIterator)) != 0)
{
if(--nDev != 0)
{
IOObjectRelease(pObject);
continue;
}
if ( IORegistryEntryCreateCFProperties
(
pObject,
&pDictionary,
kCFAllocatorDefault,
kNilOptions
) != KERN_SUCCESS )
{
wxLogDebug(_T("IORegistryEntryCreateCFProperties failed"));
}
//
// Now we get the attributes of each "product" in the iterator
//
//Get [product] name
CFStringRef cfsProduct = (CFStringRef)
CFDictionaryGetValue(pDictionary, CFSTR(kIOHIDProductKey));
m_szProductName =
wxCFStringRef( wxCFRetain(cfsProduct)
).AsString();
//Get the Product ID Key
CFNumberRef cfnProductId = (CFNumberRef)
CFDictionaryGetValue(pDictionary, CFSTR(kIOHIDProductIDKey));
if (cfnProductId)
{
CFNumberGetValue(cfnProductId, kCFNumberIntType, &m_nProductId);
}
//Get the Vendor ID Key
CFNumberRef cfnVendorId = (CFNumberRef)
CFDictionaryGetValue(pDictionary, CFSTR(kIOHIDVendorIDKey));
if (cfnVendorId)
{
CFNumberGetValue(cfnVendorId, kCFNumberIntType, &m_nManufacturerId);
}
//
// End attribute getting
//
//Create the interface (good grief - long function names!)
SInt32 nScore;
IOCFPlugInInterface** ppPlugin;
if(IOCreatePlugInInterfaceForService(pObject,
kIOHIDDeviceUserClientTypeID,
kIOCFPlugInInterfaceID, &ppPlugin,
&nScore) != kIOReturnSuccess)
{
wxLogSysError(wxT("Could not create HID Interface for product"));
return false;
}
//Now, the final thing we can check before we fall back to asserts
//(because the dtor only checks if the device is ok, so if anything
//fails from now on the dtor will delete the device anyway, so we can't break from this).
//Get the HID interface from the plugin to the mach port
if((*ppPlugin)->QueryInterface(ppPlugin,
CFUUIDGetUUIDBytes(kIOHIDDeviceInterfaceID),
(void**) &m_ppDevice) != S_OK)
{
wxLogSysError(wxT("Could not get device interface from HID interface"));
return false;
}
//release the plugin
(*ppPlugin)->Release(ppPlugin);
//open the HID interface...
if ( (*m_ppDevice)->open(m_ppDevice, 0) != S_OK )
wxLogDebug(_T("HID device: open failed"));
//
//Now the hard part - in order to scan things we need "cookies"
//
CFArrayRef cfaCookies = (CFArrayRef)CFDictionaryGetValue(pDictionary,
CFSTR(kIOHIDElementKey));
BuildCookies(cfaCookies);
//cleanup
CFRelease(pDictionary);
IOObjectRelease(pObject);
//iterator cleanup
IOObjectRelease(pIterator);
return true;
}
//iterator cleanup
IOObjectRelease(pIterator);
return false; //no device
}//end Create()
// ----------------------------------------------------------------------------
// wxHIDDevice::GetCount [static]
//
// Obtains the number of devices on a system for a given HID Page (nClass)
// and HID Usage (nType).
// ----------------------------------------------------------------------------
size_t wxHIDDevice::GetCount (int nClass, int nType)
{
//Create the mach port
mach_port_t pPort;
if(IOMasterPort(bootstrap_port, &pPort) != kIOReturnSuccess)
{
wxLogSysError(wxT("Could not create mach port"));
return false;
}
//Dictionary that will hold first
//the matching dictionary for determining which kind of devices we want,
//then later some registry properties from an iterator (see below)
CFMutableDictionaryRef pDictionary = IOServiceMatching(kIOHIDDeviceKey);
if(pDictionary == NULL)
{
wxLogSysError( _T("IOServiceMatching(kIOHIDDeviceKey) failed") );
return false;
}
//Here we'll filter down the services to what we want
if (nType != -1)
{
CFNumberRef pType = CFNumberCreate(kCFAllocatorDefault,
kCFNumberIntType, &nType);
CFDictionarySetValue(pDictionary, CFSTR(kIOHIDPrimaryUsageKey), pType);
CFRelease(pType);
}
if (nClass != -1)
{
CFNumberRef pClass = CFNumberCreate(kCFAllocatorDefault,
kCFNumberIntType, &nClass);
CFDictionarySetValue(pDictionary, CFSTR(kIOHIDPrimaryUsagePageKey), pClass);
CFRelease(pClass);
}
//Now get the maching services
io_iterator_t pIterator;
if( IOServiceGetMatchingServices(pPort,
pDictionary, &pIterator) != kIOReturnSuccess )
{
wxLogSysError(_T("No Matching HID Services"));
return false;
}
//If the iterator doesn't exist there are no devices :)
if ( !pIterator )
return 0;
//Now we iterate through them
size_t nCount = 0;
io_object_t pObject;
while ( (pObject = IOIteratorNext(pIterator)) != 0)
{
++nCount;
IOObjectRelease(pObject);
}
//cleanup
IOObjectRelease(pIterator);
mach_port_deallocate(mach_task_self(), pPort);
return nCount;
}//end Create()
// ----------------------------------------------------------------------------
// wxHIDDevice::AddCookie
//
// Adds a cookie to the internal cookie array from a CFType
// ----------------------------------------------------------------------------
void wxHIDDevice::AddCookie(CFTypeRef Data, int i)
{
CFNumberGetValue(
(CFNumberRef) CFDictionaryGetValue ( (CFDictionaryRef) Data
, CFSTR(kIOHIDElementCookieKey)
),
kCFNumberIntType,
&m_pCookies[i]
);
}
// ----------------------------------------------------------------------------
// wxHIDDevice::AddCookieInQueue
//
// Adds a cookie to the internal cookie array from a CFType and additionally
// adds it to the internal HID Queue
// ----------------------------------------------------------------------------
void wxHIDDevice::AddCookieInQueue(CFTypeRef Data, int i)
{
//3rd Param flags (none yet)
AddCookie(Data, i);
if ( (*m_ppQueue)->addElement(m_ppQueue, m_pCookies[i], 0) != S_OK )
wxLogDebug(_T("HID device: adding element failed"));
}
// ----------------------------------------------------------------------------
// wxHIDDevice::InitCookies
//
// Create the internal cookie array, optionally creating a HID Queue
// ----------------------------------------------------------------------------
void wxHIDDevice::InitCookies(size_t dwSize, bool bQueue)
{
m_pCookies = new IOHIDElementCookie[dwSize];
if (bQueue)
{
wxASSERT( m_ppQueue == NULL);
m_ppQueue = (*m_ppDevice)->allocQueue(m_ppDevice);
if ( !m_ppQueue )
{
wxLogDebug(_T("HID device: allocQueue failed"));
return;
}
//Param 2, flags, none yet
if ( (*m_ppQueue)->create(m_ppQueue, 0, 512) != S_OK )
{
wxLogDebug(_T("HID device: create failed"));
}
}
//make sure that cookie array is clear
memset(m_pCookies, 0, sizeof(*m_pCookies) * dwSize);
}
// ----------------------------------------------------------------------------
// wxHIDDevice::IsActive
//
// Returns true if a cookie of the device is active - for example if a key is
// held down, joystick button pressed, caps lock active, etc..
// ----------------------------------------------------------------------------
bool wxHIDDevice::IsActive(int nIndex)
{
if(!HasElement(nIndex))
{
//cookie at index does not exist - getElementValue
//could return true which would be incorrect so we
//check here
return false;
}
IOHIDEventStruct Event;
(*m_ppDevice)->getElementValue(m_ppDevice, m_pCookies[nIndex], &Event);
return !!Event.value;
}
// ----------------------------------------------------------------------------
// wxHIDDevice::HasElement
//
// Returns true if the element in the internal cookie array exists
// ----------------------------------------------------------------------------
bool wxHIDDevice::HasElement(int nIndex)
{
return m_pCookies[nIndex] != NULL;
}
// ----------------------------------------------------------------------------
// wxHIDDevice Destructor
//
// Frees all memory and objects from the structure
// ----------------------------------------------------------------------------
wxHIDDevice::~wxHIDDevice()
{
if (m_ppDevice != NULL)
{
if (m_ppQueue != NULL)
{
(*m_ppQueue)->stop(m_ppQueue);
(*m_ppQueue)->dispose(m_ppQueue);
(*m_ppQueue)->Release(m_ppQueue);
}
(*m_ppDevice)->close(m_ppDevice);
(*m_ppDevice)->Release(m_ppDevice);
mach_port_deallocate(mach_task_self(), m_pPort);
}
if (m_pCookies != NULL)
{
delete [] m_pCookies;
}
}
// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
//
// wxHIDKeyboard
//
// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
//There are no right shift, alt etc. in the wx headers yet so just sort
//of "define our own" for now
enum
{
WXK_RSHIFT = 400,
WXK_RALT,
WXK_RCONTROL,
WXK_RMENU
};
// ----------------------------------------------------------------------------
// wxHIDKeyboard::GetCount [static]
//
// Get number of HID keyboards available
// ----------------------------------------------------------------------------
int wxHIDKeyboard::GetCount()
{
return wxHIDDevice::GetCount(kHIDPage_GenericDesktop,
kHIDUsage_GD_Keyboard);
}
// ----------------------------------------------------------------------------
// wxHIDKeyboard::Create
//
// Create the HID Keyboard
// ----------------------------------------------------------------------------
bool wxHIDKeyboard::Create(int nDev /* = 1*/)
{
return wxHIDDevice::Create(kHIDPage_GenericDesktop,
kHIDUsage_GD_Keyboard,
nDev);
}
// ----------------------------------------------------------------------------
// wxHIDKeyboard::AddCookie
//
// Overloaded version of wxHIDDevice::AddCookie that simply does not
// add a cookie if a duplicate is found
// ----------------------------------------------------------------------------
void wxHIDKeyboard::AddCookie(CFTypeRef Data, int i)
{
if(!HasElement(i))
wxHIDDevice::AddCookie(Data, i);
}
// ----------------------------------------------------------------------------
// wxHIDKeyboard::BuildCookies
//
// Callback from Create() to build the HID cookies for the internal cookie
// array
// ----------------------------------------------------------------------------
void wxHIDKeyboard::BuildCookies(CFArrayRef Array)
{
//Create internal cookie array
InitCookies(500);
//Begin recursing in array
DoBuildCookies(Array);
}
void wxHIDKeyboard::DoBuildCookies(CFArrayRef Array)
{
//Now go through each possible cookie
int i,
nUsage;
// bool bEOTriggered = false;
for (i = 0; i < CFArrayGetCount(Array); ++i)
{
const void* ref = CFDictionaryGetValue(
(CFDictionaryRef)CFArrayGetValueAtIndex(Array, i),
CFSTR(kIOHIDElementKey)
);
if (ref != NULL)
{
DoBuildCookies((CFArrayRef) ref);
}
else
{
//
// Get the usage #
//
CFNumberGetValue(
(CFNumberRef)
CFDictionaryGetValue((CFDictionaryRef)
CFArrayGetValueAtIndex(Array, i),
CFSTR(kIOHIDElementUsageKey)
),
kCFNumberLongType,
&nUsage);
//
// Now translate the usage # into a wx keycode
//
//
// OK, this is strange - basically this kind of strange -
// Starting from 0xEO these elements (like shift) appear twice in
// the array! The ones at the end are bogus I guess - the funny part
// is that besides the fact that the ones at the front have a Unit
// and UnitExponent key with a value of 0 and a different cookie value,
// there is no discernable difference between the two...
//
// Will the real shift please stand up?
//
// Something to spend a support request on, if I had one, LOL.
//
//if(nUsage == 0xE0)
//{
// if(bEOTriggered)
// break;
// bEOTriggered = true;
//}
//Instead of that though we now just don't add duplicate keys
if (nUsage >= kHIDUsage_KeyboardA && nUsage <= kHIDUsage_KeyboardZ)
AddCookie(CFArrayGetValueAtIndex(Array, i), 'A' + (nUsage - kHIDUsage_KeyboardA) );
else if (nUsage >= kHIDUsage_Keyboard1 && nUsage <= kHIDUsage_Keyboard9)
AddCookie(CFArrayGetValueAtIndex(Array, i), '1' + (nUsage - kHIDUsage_Keyboard1) );
else if (nUsage >= kHIDUsage_KeyboardF1 && nUsage <= kHIDUsage_KeyboardF12)
AddCookie(CFArrayGetValueAtIndex(Array, i), WXK_F1 + (nUsage - kHIDUsage_KeyboardF1) );
else if (nUsage >= kHIDUsage_KeyboardF13 && nUsage <= kHIDUsage_KeyboardF24)
AddCookie(CFArrayGetValueAtIndex(Array, i), WXK_F13 + (nUsage - kHIDUsage_KeyboardF13) );
else if (nUsage >= kHIDUsage_Keypad1 && nUsage <= kHIDUsage_Keypad9)
AddCookie(CFArrayGetValueAtIndex(Array, i), WXK_NUMPAD1 + (nUsage - kHIDUsage_Keypad1) );
else switch (nUsage)
{
//0's (wx & ascii go 0-9, but HID goes 1-0)
case kHIDUsage_Keyboard0:
AddCookie(CFArrayGetValueAtIndex(Array, i), '0');
break;
case kHIDUsage_Keypad0:
AddCookie(CFArrayGetValueAtIndex(Array, i), WXK_NUMPAD0);
break;
//Basic
case kHIDUsage_KeyboardReturnOrEnter:
AddCookie(CFArrayGetValueAtIndex(Array, i), WXK_RETURN);
break;
case kHIDUsage_KeyboardEscape:
AddCookie(CFArrayGetValueAtIndex(Array, i), WXK_ESCAPE);
break;
case kHIDUsage_KeyboardDeleteOrBackspace:
AddCookie(CFArrayGetValueAtIndex(Array, i), WXK_BACK);
break;
case kHIDUsage_KeyboardTab:
AddCookie(CFArrayGetValueAtIndex(Array, i), WXK_TAB);
break;
case kHIDUsage_KeyboardSpacebar:
AddCookie(CFArrayGetValueAtIndex(Array, i), WXK_SPACE);
break;
case kHIDUsage_KeyboardPageUp:
AddCookie(CFArrayGetValueAtIndex(Array, i), WXK_PAGEUP);
break;
case kHIDUsage_KeyboardEnd:
AddCookie(CFArrayGetValueAtIndex(Array, i), WXK_END);
break;
case kHIDUsage_KeyboardPageDown:
AddCookie(CFArrayGetValueAtIndex(Array, i), WXK_PAGEDOWN);
break;
case kHIDUsage_KeyboardRightArrow:
AddCookie(CFArrayGetValueAtIndex(Array, i), WXK_RIGHT);
break;
case kHIDUsage_KeyboardLeftArrow:
AddCookie(CFArrayGetValueAtIndex(Array, i), WXK_LEFT);
break;
case kHIDUsage_KeyboardDownArrow:
AddCookie(CFArrayGetValueAtIndex(Array, i), WXK_DOWN);
break;
case kHIDUsage_KeyboardUpArrow:
AddCookie(CFArrayGetValueAtIndex(Array, i), WXK_UP);
break;
//LEDS
case kHIDUsage_KeyboardCapsLock:
AddCookie(CFArrayGetValueAtIndex(Array, i),WXK_CAPITAL);
break;
case kHIDUsage_KeypadNumLock:
AddCookie(CFArrayGetValueAtIndex(Array, i),WXK_NUMLOCK);
break;
case kHIDUsage_KeyboardScrollLock:
AddCookie(CFArrayGetValueAtIndex(Array, i),WXK_SCROLL);
break;
//Menu keys, Shift, other specials
case kHIDUsage_KeyboardLeftControl:
AddCookie(CFArrayGetValueAtIndex(Array, i),WXK_CONTROL);
break;
case kHIDUsage_KeyboardLeftShift:
AddCookie(CFArrayGetValueAtIndex(Array, i),WXK_SHIFT);
break;
case kHIDUsage_KeyboardLeftAlt:
AddCookie(CFArrayGetValueAtIndex(Array, i),WXK_ALT);
break;
case kHIDUsage_KeyboardLeftGUI:
AddCookie(CFArrayGetValueAtIndex(Array, i),WXK_MENU);
break;
case kHIDUsage_KeyboardRightControl:
AddCookie(CFArrayGetValueAtIndex(Array, i),WXK_RCONTROL);
break;
case kHIDUsage_KeyboardRightShift:
AddCookie(CFArrayGetValueAtIndex(Array, i),WXK_RSHIFT);
break;
case kHIDUsage_KeyboardRightAlt:
AddCookie(CFArrayGetValueAtIndex(Array, i),WXK_RALT);
break;
case kHIDUsage_KeyboardRightGUI:
AddCookie(CFArrayGetValueAtIndex(Array, i),WXK_RMENU);
break;
//Default
default:
//not in wx keycodes - do nothing....
break;
} //end mightly long switch
} //end if the current element is not an array...
} //end for loop for Array
}//end buildcookies
// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
//
// wxHIDModule
//
// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
class wxHIDModule : public wxModule
{
DECLARE_DYNAMIC_CLASS(wxHIDModule)
public:
static wxArrayPtrVoid sm_keyboards;
virtual bool OnInit()
{
return true;
}
virtual void OnExit()
{
for(size_t i = 0; i < sm_keyboards.GetCount(); ++i)
delete (wxHIDKeyboard*) sm_keyboards[i];
}
};
IMPLEMENT_DYNAMIC_CLASS(wxHIDModule, wxModule)
wxArrayPtrVoid wxHIDModule::sm_keyboards;
// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
//
// wxGetKeyState()
//
// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
bool wxGetKeyState (wxKeyCode key)
{
wxASSERT_MSG(key != WXK_LBUTTON && key != WXK_RBUTTON && key !=
WXK_MBUTTON, wxT("can't use wxGetKeyState() for mouse buttons"));
if (wxHIDModule::sm_keyboards.GetCount() == 0)
{
int nKeyboards = wxHIDKeyboard::GetCount();
for(int i = 1; i <= nKeyboards; ++i)
{
wxHIDKeyboard* keyboard = new wxHIDKeyboard();
if(keyboard->Create(i))
{
wxHIDModule::sm_keyboards.Add(keyboard);
}
else
{
delete keyboard;
break;
}
}
wxASSERT_MSG(wxHIDModule::sm_keyboards.GetCount() != 0,
wxT("No keyboards found!"));
}
for(size_t i = 0; i < wxHIDModule::sm_keyboards.GetCount(); ++i)
{
wxHIDKeyboard* keyboard = (wxHIDKeyboard*)
wxHIDModule::sm_keyboards[i];
switch(key)
{
case WXK_SHIFT:
if( keyboard->IsActive(WXK_SHIFT) ||
keyboard->IsActive(WXK_RSHIFT) )
{
return true;
}
break;
case WXK_ALT:
if( keyboard->IsActive(WXK_ALT) ||
keyboard->IsActive(WXK_RALT) )
{
return true;
}
break;
case WXK_CONTROL:
if( keyboard->IsActive(WXK_CONTROL) ||
keyboard->IsActive(WXK_RCONTROL) )
{
return true;
}
break;
case WXK_MENU:
if( keyboard->IsActive(WXK_MENU) ||
keyboard->IsActive(WXK_RMENU) )
{
return true;
}
break;
default:
if( keyboard->IsActive(key) )
{
return true;
}
break;
}
}
return false; //not down/error
}
#endif //__DARWIN__

View File

@@ -0,0 +1,905 @@
/////////////////////////////////////////////////////////////////////////////
// Name: src/mac/corefoundation/joystick.cpp
// Purpose: wxJoystick class
// Author: Ryan Norton
// Modified by:
// Created: 2/13/2005
// RCS-ID: $Id$
// Copyright: (c) Ryan Norton
// Licence: wxWindows licence
/////////////////////////////////////////////////////////////////////////////
//===========================================================================
// DECLARATIONS
//===========================================================================
//---------------------------------------------------------------------------
// Pre-compiled header stuff
//---------------------------------------------------------------------------
// For compilers that support precompilation, includes "wx.h".
#include "wx/wxprec.h"
//---------------------------------------------------------------------------
// Guard
//---------------------------------------------------------------------------
//we only support HID on OSX (DARWIN), since it requires DARWIN...
#if wxUSE_JOYSTICK && wxUSE_THREADS
//---------------------------------------------------------------------------
// Includes
//---------------------------------------------------------------------------
#ifndef WX_PRECOMP
#include "wx/log.h"
#include "wx/event.h" //joystick wxEvents
#include "wx/window.h" //for wxWindow to "capture" joystick
#endif
#include "wx/joystick.h" //...
#include "wx/thread.h" //wxThread for polling thread/ wxCriticalSection
//private headers
#include "wx/mac/corefoundation/hid.h" //private mac hid stuff
//mac headers
#include <CoreServices/CoreServices.h>
#include <mach/mach.h>
#include <mach/mach_time.h>
#include <unistd.h>
//---------------------------------------------------------------------------
// Definitions/Enumerations
//---------------------------------------------------------------------------
#define wxJS_MAX_AXES 10 /*max number of axes*/
#define wxJS_MAX_BUTTONS 40 /*max number of buttons*/
enum
{
//These are positions within the cookie array
//in wxHIDJoystick that the cookies that store the axis' are
wxJS_AXIS_X = 40,
wxJS_AXIS_Y,
wxJS_AXIS_Z,
wxJS_AXIS_RUDDER,
wxJS_AXIS_U,
wxJS_AXIS_V,
};
//---------------------------------------------------------------------------
// wxHIDJoystick
//---------------------------------------------------------------------------
class wxHIDJoystick : public wxHIDDevice
{
public:
wxHIDJoystick();
virtual ~wxHIDJoystick();
bool Create(int nWhich);
virtual void BuildCookies(CFArrayRef Array);
void MakeCookies(CFArrayRef Array);
IOHIDElementCookie* GetCookies();
IOHIDQueueInterface** GetQueue();
int m_nXMax, m_nYMax, m_nZMax, m_nRudderMax, m_nUMax, m_nVMax,
m_nXMin, m_nYMin, m_nZMin, m_nRudderMin, m_nUMin, m_nVMin;
friend class wxJoystick;
};
//---------------------------------------------------------------------------
// wxJoystickThread
//---------------------------------------------------------------------------
class wxJoystickThread : public wxThread
{
public:
wxJoystickThread(wxHIDJoystick* hid, int joystick);
void* Entry();
static void HIDCallback(void* target, IOReturn res, void* context, void* sender);
private:
wxHIDJoystick* m_hid;
int m_joystick;
wxPoint m_lastposition;
int m_axe[wxJS_MAX_AXES];
int m_buttons;
wxWindow* m_catchwin;
int m_polling;
friend class wxJoystick;
};
//===========================================================================
// IMPLEMENTATION
//===========================================================================
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
// wxGetIntFromCFDictionary
//
// Helper function that gets a integer from a dictionary key
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
void wxGetIntFromCFDictionary(CFTypeRef cfDict, CFStringRef key, int* pOut)
{
CFNumberGetValue(
(CFNumberRef) CFDictionaryGetValue((CFDictionaryRef) cfDict,
key),
kCFNumberIntType, pOut);
}
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
//
// wxJoystick
//
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
IMPLEMENT_DYNAMIC_CLASS(wxJoystick, wxObject)
//---------------------------------------------------------------------------
// wxJoystick Constructor
//
// 1) Initializes member variables
// 2) Attempts to create the native HID joystick implementation - if none
// could be found (no joysticks, etc.) then it sets it to NULL
//---------------------------------------------------------------------------
wxJoystick::wxJoystick(int joystick)
: m_joystick(joystick),
m_thread(NULL)
{
m_hid = new wxHIDJoystick();
if (m_hid->Create(m_joystick+1)) //wxHIDDevice is 1-based while this is 0
{
m_thread = new wxJoystickThread(m_hid, m_joystick);
m_thread->Create();
m_thread->Run();
}
else
{
delete m_hid;
m_hid = NULL;
}
}
//---------------------------------------------------------------------------
// wxJoystick Destructor
//
// Releases the capture of the thread, deletes it, and deletes
// the native implementation.
//---------------------------------------------------------------------------
wxJoystick::~wxJoystick()
{
ReleaseCapture();
if (m_thread)
m_thread->Delete(); // It's detached so it will delete itself
if (m_hid)
delete m_hid;
}
//---------------------------------------------------------------------------
// wxJoystick::Get[XXX]Position
//
// Returns the value of an axis that was polled from the thread. In the
// case of GetPosition returns the X and Y values in a wxPoint
//---------------------------------------------------------------------------
wxPoint wxJoystick::GetPosition() const
{
wxPoint pos(wxDefaultPosition);
if (m_thread) pos = m_thread->m_lastposition;
return pos;
}
int wxJoystick::GetZPosition() const
{
if (m_thread)
return m_thread->m_axe[wxJS_AXIS_Z];
return 0;
}
int wxJoystick::GetRudderPosition() const
{
if (m_thread)
return m_thread->m_axe[wxJS_AXIS_RUDDER];
return 0;
}
int wxJoystick::GetUPosition() const
{
if (m_thread)
return m_thread->m_axe[wxJS_AXIS_U];
return 0;
}
int wxJoystick::GetVPosition() const
{
if (m_thread)
return m_thread->m_axe[wxJS_AXIS_V];
return 0;
}
//---------------------------------------------------------------------------
// wxJoystick::GetButtonState
//
// Returns the state of the buttons in a bitmask as dictated by the
// wx manual (the real work takes place in the thread, as always)
//---------------------------------------------------------------------------
int wxJoystick::GetButtonState() const
{
if (m_thread)
return m_thread->m_buttons;
return 0;
}
//---------------------------------------------------------------------------
// wxJoystick::IsOk
//
// Returns whether the joystick initialized successfully - in this case
// if the native implementation doesn't exist (in constructor)
//---------------------------------------------------------------------------
bool wxJoystick::IsOk() const
{
return m_hid != NULL;
}
//---------------------------------------------------------------------------
// wxJoystick::Get[XXX](Id/Name)
//
// Simple accessors to the native HID implementation
//---------------------------------------------------------------------------
int wxJoystick::GetManufacturerId() const
{
return m_hid->m_nManufacturerId;
}
int wxJoystick::GetProductId() const
{
return m_hid->m_nProductId;
}
wxString wxJoystick::GetProductName() const
{
return m_hid->m_szProductName;
}
//---------------------------------------------------------------------------
// wxJoystick::GetNumberButtons
// wxJoystick::GetNumberAxes
//
// Queries the joystick for an active number of buttons/axes.
//
// In the native HID implementation, the cookies:
// 0-40 are the buttons of the joystick
// 40-50 are the axes of the joystick
//
// These just query the native HID implementation as above.
//---------------------------------------------------------------------------
int wxJoystick::GetNumberButtons() const
{
int nCount = 0;
for(int nIndex = 0; nIndex < 40; ++nIndex)
{
if(m_hid->HasElement(nIndex))
++nCount;
}
return nCount;
}
int wxJoystick::GetNumberAxes() const
{
int nCount = 0;
for(int nIndex = 40; nIndex < 50; ++nIndex)
{
if(m_hid->HasElement(nIndex))
++nCount;
}
return nCount;
}
//---------------------------------------------------------------------------
// wxJoystick::GetNumberJoysticks
//
// Gets the number of joysticks on the system. In HID that
// is all devices with the kHIDUsage_GD_Joystick or kHIDUsage_GD_GamePad
// identifiers.
//---------------------------------------------------------------------------
int wxJoystick::GetNumberJoysticks()
{
return
wxHIDDevice::GetCount(kHIDPage_GenericDesktop, kHIDUsage_GD_Joystick) +
wxHIDDevice::GetCount(kHIDPage_GenericDesktop, kHIDUsage_GD_GamePad);
}
//---------------------------------------------------------------------------
// wxJoystick::SetCapture
//
// Stops sending events from the thread to the window set in
// SetCapture and stops polling the joystick
//---------------------------------------------------------------------------
bool wxJoystick::SetCapture(wxWindow* win, int pollingFreq)
{
if (m_thread)
{
m_thread->m_catchwin = win;
m_thread->m_polling = pollingFreq;
return true;
}
return false;
}
//---------------------------------------------------------------------------
// wxJoystick::ReleaseCapture
//
// Stops sending events from the thread to the window set in
// SetCapture and stops polling the joystick
//---------------------------------------------------------------------------
bool wxJoystick::ReleaseCapture()
{
if (m_thread)
{
m_thread->m_catchwin = NULL;
m_thread->m_polling = 0;
return true;
}
return false;
}
//---------------------------------------------------------------------------
// wxJoystick::Get[XXX]
//
// Gets the minimum and maximum values for each axis, returning 0 if the
// axis doesn't exist.
//---------------------------------------------------------------------------
int wxJoystick::GetXMin() const
{
return m_hid->m_nXMin;
}
int wxJoystick::GetYMin() const
{
return m_hid->m_nYMin;
}
int wxJoystick::GetZMin() const
{
return m_hid->m_nZMin;
}
int wxJoystick::GetRudderMin() const
{
return m_hid->m_nRudderMin;
}
int wxJoystick::GetUMin() const
{
return m_hid->m_nUMin;
}
int wxJoystick::GetVMin() const
{
return m_hid->m_nVMin;
}
int wxJoystick::GetXMax() const
{
return m_hid->m_nXMax;
}
int wxJoystick::GetYMax() const
{
return m_hid->m_nYMax;
}
int wxJoystick::GetZMax() const
{
return m_hid->m_nZMax;
}
int wxJoystick::GetRudderMax() const
{
return m_hid->m_nRudderMax;
}
int wxJoystick::GetUMax() const
{
return m_hid->m_nUMax;
}
int wxJoystick::GetVMax() const
{
return m_hid->m_nVMax;
}
//---------------------------------------------------------------------------
// wxJoystick::Get[XXX]
//
// Min/Max values for buttons, axes, etc.. Polling in this case is just
// what the linux port has.
//---------------------------------------------------------------------------
int wxJoystick::GetMaxButtons() const
{
return wxJS_MAX_BUTTONS;
}
int wxJoystick::GetMaxAxes() const
{
return wxJS_MAX_AXES;
}
int wxJoystick::GetPollingMin() const
{
return 10;
}
int wxJoystick::GetPollingMax() const
{
return 1000;
}
//---------------------------------------------------------------------------
// wxJoystick::Has[XXX]
//
// Just queries the native hid implementation if the cookie was found
// when enumerating the cookies of the joystick device
//---------------------------------------------------------------------------
bool wxJoystick::HasZ() const
{
return m_hid->HasElement(wxJS_AXIS_Z);
}
bool wxJoystick::HasRudder() const
{
return m_hid->HasElement(wxJS_AXIS_RUDDER);
}
bool wxJoystick::HasU() const
{
return m_hid->HasElement(wxJS_AXIS_U);
}
bool wxJoystick::HasV() const
{
return m_hid->HasElement(wxJS_AXIS_V);
}
//---------------------------------------------------------------------------
// UNSUPPORTED
//---------------------------------------------------------------------------
int wxJoystick::GetPOVPosition() const
{
return -1;
}
int wxJoystick::GetPOVCTSPosition() const
{
return -1;
}
int wxJoystick::GetMovementThreshold() const
{
return 0;
}
void wxJoystick::SetMovementThreshold(int WXUNUSED(threshold))
{
}
bool wxJoystick::HasPOV() const
{
return false;
}
bool wxJoystick::HasPOV4Dir() const
{
return false;
}
bool wxJoystick::HasPOVCTS() const
{
return false;
}
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
//
// wxHIDJoystick
//
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
//---------------------------------------------------------------------------
// wxHIDJoystick ctor
//
// Initializes the min/max members
//---------------------------------------------------------------------------
wxHIDJoystick::wxHIDJoystick() :
m_nXMax(0), m_nYMax(0), m_nZMax(0), m_nRudderMax(0), m_nUMax(0), m_nVMax(0),
m_nXMin(0), m_nYMin(0), m_nZMin(0), m_nRudderMin(0), m_nUMin(0), m_nVMin(0)
{
}
//---------------------------------------------------------------------------
// wxHIDJoystick dtor
//
// Nothing...
//---------------------------------------------------------------------------
wxHIDJoystick::~wxHIDJoystick()
{
}
//---------------------------------------------------------------------------
// wxHIDJoystick::Create
//
// Creates the native HID device (joysticks are of either
// kHIDUsage_GD_Joystick or kHIDUsage_GD_GamePad)
//---------------------------------------------------------------------------
bool wxHIDJoystick::Create(int nWhich)
{
int nJoysticks = GetCount(kHIDPage_GenericDesktop, kHIDUsage_GD_Joystick);
if (nWhich <= nJoysticks)
return wxHIDDevice::Create(kHIDPage_GenericDesktop,
kHIDUsage_GD_Joystick,
nWhich);
else
nWhich -= nJoysticks;
int nGamePads = GetCount(kHIDPage_GenericDesktop, kHIDUsage_GD_GamePad);
if (nWhich <= nGamePads)
return wxHIDDevice::Create(kHIDPage_GenericDesktop,
kHIDUsage_GD_GamePad,
nWhich);
else
return false;
}
//---------------------------------------------------------------------------
// wxHIDJoystick::BuildCookies
// wxHIDJoystick::MakeCookies
//
// Sets up the cookies for the HID device (called from Create) - as
// mentioned 0-40 are the buttons and 40-50 are the axes.
//
// MakeCookies is just a recursive function for each array within
// BuildCookies.
//---------------------------------------------------------------------------
void wxHIDJoystick::BuildCookies(CFArrayRef Array)
{
InitCookies(50, true);
//
// I wasted two hours of my life on this line :(
// accidently removed it during some source cleaning...
//
MakeCookies(Array);
//paranoid debugging stuff
#if 0
for(int i = 0; i < 50; ++i)
wxPrintf(wxT("\nVAL #%i:[%i]"), i, m_pCookies[i]);
#endif
}//end buildcookies
void wxHIDJoystick::MakeCookies(CFArrayRef Array)
{
int i, nUsage, nPage;
for (i = 0; i < CFArrayGetCount(Array); ++i)
{
const void* ref = CFDictionaryGetValue(
(CFDictionaryRef)CFArrayGetValueAtIndex(Array, i),
CFSTR(kIOHIDElementKey)
);
if (ref != NULL)
{
MakeCookies((CFArrayRef) ref);
}
else
{
CFNumberGetValue(
(CFNumberRef)
CFDictionaryGetValue(
(CFDictionaryRef) CFArrayGetValueAtIndex(Array, i),
CFSTR(kIOHIDElementUsageKey)
),
kCFNumberIntType,
&nUsage );
CFNumberGetValue(
(CFNumberRef)
CFDictionaryGetValue(
(CFDictionaryRef) CFArrayGetValueAtIndex(Array, i),
CFSTR(kIOHIDElementUsagePageKey)
),
kCFNumberIntType,
&nPage );
#if 0
wxLogSysError(wxT("[%i][%i]"), nUsage, nPage);
#endif
if (nPage == kHIDPage_Button && nUsage <= 40)
AddCookieInQueue(CFArrayGetValueAtIndex(Array, i), nUsage-1 );
else if (nPage == kHIDPage_GenericDesktop)
{
//axis...
switch(nUsage)
{
case kHIDUsage_GD_X:
AddCookieInQueue(CFArrayGetValueAtIndex(Array, i), wxJS_AXIS_X);
wxGetIntFromCFDictionary(CFArrayGetValueAtIndex(Array, i),
CFSTR(kIOHIDElementMaxKey),
&m_nXMax);
wxGetIntFromCFDictionary(CFArrayGetValueAtIndex(Array, i),
CFSTR(kIOHIDElementMinKey),
&m_nXMin);
break;
case kHIDUsage_GD_Y:
AddCookieInQueue(CFArrayGetValueAtIndex(Array, i), wxJS_AXIS_Y);
wxGetIntFromCFDictionary(CFArrayGetValueAtIndex(Array, i),
CFSTR(kIOHIDElementMaxKey),
&m_nYMax);
wxGetIntFromCFDictionary(CFArrayGetValueAtIndex(Array, i),
CFSTR(kIOHIDElementMinKey),
&m_nYMin);
break;
case kHIDUsage_GD_Z:
AddCookieInQueue(CFArrayGetValueAtIndex(Array, i), wxJS_AXIS_Z);
wxGetIntFromCFDictionary(CFArrayGetValueAtIndex(Array, i),
CFSTR(kIOHIDElementMaxKey),
&m_nZMax);
wxGetIntFromCFDictionary(CFArrayGetValueAtIndex(Array, i),
CFSTR(kIOHIDElementMinKey),
&m_nZMin);
break;
default:
break;
}
}
else if (nPage == kHIDPage_Simulation && nUsage == kHIDUsage_Sim_Rudder)
{
//rudder...
AddCookieInQueue(CFArrayGetValueAtIndex(Array, i), wxJS_AXIS_RUDDER );
wxGetIntFromCFDictionary(CFArrayGetValueAtIndex(Array, i),
CFSTR(kIOHIDElementMaxKey),
&m_nRudderMax);
wxGetIntFromCFDictionary(CFArrayGetValueAtIndex(Array, i),
CFSTR(kIOHIDElementMinKey),
&m_nRudderMin);
}
}
}
}
//---------------------------------------------------------------------------
// wxHIDJoystick::Get[XXX]
//
// Simple accessors so that the HID callback and the thread procedure
// can access members from wxHIDDevice (our parent here).
//---------------------------------------------------------------------------
IOHIDElementCookie* wxHIDJoystick::GetCookies()
{ return m_pCookies; }
IOHIDQueueInterface** wxHIDJoystick::GetQueue()
{ return m_ppQueue; }
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
//
// wxJoystickThread
//
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
//---------------------------------------------------------------------------
// wxJoystickThread Constructor
//
// Just initializes members
//---------------------------------------------------------------------------
wxJoystickThread::wxJoystickThread(wxHIDJoystick* hid, int joystick)
: m_hid(hid),
m_joystick(joystick),
m_lastposition(127,127),
m_buttons(0),
m_catchwin(NULL),
m_polling(0)
{
memset(m_axe, 0, sizeof(int) * wxJS_MAX_AXES);
}
//---------------------------------------------------------------------------
// wxJoystickThread::Entry
//
// Thread procedure
//
// Runs a CFRunLoop for polling. Basically, it sets the HID queue to
// call wxJoystickThread::HIDCallback in the context of this thread
// when something changes on the device. It polls as long as the user
// wants, or a certain amount if the user wants to "block". Note that
// we don't actually block here since this is in a secondary thread.
//---------------------------------------------------------------------------
void* wxJoystickThread::Entry()
{
CFRunLoopSourceRef pRLSource = NULL;
if ((*m_hid->GetQueue())->createAsyncEventSource(
m_hid->GetQueue(), &pRLSource) != kIOReturnSuccess )
{
wxLogSysError(wxT("Couldn't create async event source"));
return NULL;
}
wxASSERT(pRLSource != NULL);
//attach runloop source to main run loop in thread
CFRunLoopRef pRL = CFRunLoopGetCurrent();
CFRunLoopAddSource(pRL, pRLSource, kCFRunLoopDefaultMode);
wxASSERT( CFRunLoopContainsSource(pRL, pRLSource, kCFRunLoopDefaultMode) );
if( (*m_hid->GetQueue())->setEventCallout(m_hid->GetQueue(),
wxJoystickThread::HIDCallback, this, this) != kIOReturnSuccess )
{
wxLogSysError(wxT("Could not set event callout for queue"));
return NULL;
}
if( (*m_hid->GetQueue())->start(m_hid->GetQueue()) != kIOReturnSuccess )
{
wxLogSysError(wxT("Could not start queue"));
return NULL;
}
double dTime;
while(true)
{
if (TestDestroy())
break;
if (m_polling)
dTime = 0.0001 * m_polling;
else
dTime = 0.0001 * 10; // check at least every 10 msec in "blocking" case
//true just "handles and returns" - false forces it to stay the time
//amount
#if 1
CFRunLoopRunInMode(kCFRunLoopDefaultMode, dTime, true);
#else
IOReturn ret = NULL;
HIDCallback(this, ret, this, this);
Sleep(3000);
#endif
}
wxASSERT( CFRunLoopContainsSource(pRL, pRLSource, kCFRunLoopDefaultMode) );
CFRunLoopRemoveSource(pRL, pRLSource, kCFRunLoopDefaultMode);
CFRelease(pRLSource);
return NULL;
}
//---------------------------------------------------------------------------
// wxJoystickThread::HIDCallback (static)
//
// Callback for the native HID device when it recieves input.
//
// This is where the REAL dirty work gets done.
//
// 1) Loops through each event the queue has recieved
// 2) First, checks if the thread that is running the loop for
// the polling has ended - if so it breaks out
// 3) Next, it checks if there was an error getting this event from
// the HID queue, if there was, it logs an error and returns
// 4) Now it does the real dirty work by getting the button states
// from cookies 0-40 and axes positions/states from cookies 40-50
// in the native HID device by quering cookie values.
// 5) Sends the event to the polling window (if any)
// 6) Gets the next event and goes back to (1)
//---------------------------------------------------------------------------
/*static*/ void wxJoystickThread::HIDCallback(void* WXUNUSED(target),
IOReturn WXUNUSED(res),
void* context,
void* WXUNUSED(sender))
{
IOHIDEventStruct hidevent;
AbsoluteTime bogustime = {0,0};
IOReturn ret;
wxJoystickThread* pThis = (wxJoystickThread*) context;
wxHIDJoystick* m_hid = pThis->m_hid;
//Get the "first" event from the queue
//bogustime tells it we don't care at what time to start
//where it gets the next from
ret = (*m_hid->GetQueue())->getNextEvent(m_hid->GetQueue(),
&hidevent, bogustime, 0);
while (ret != kIOReturnUnderrun)
{
if (pThis->TestDestroy())
break;
if(ret != kIOReturnSuccess)
{
wxLogSysError(wxString::Format(wxT("wxJoystick Error:[%i]"), ret));
return;
}
wxJoystickEvent wxevent;
//Find the cookie that changed
int nIndex = 0;
IOHIDElementCookie* pCookies = m_hid->GetCookies();
while(nIndex < 50)
{
if(hidevent.elementCookie == pCookies[nIndex])
break;
++nIndex;
}
//debugging stuff
#if 0
if(nIndex == 50)
{
wxLogSysError(wxString::Format(wxT("wxJoystick Out Of Bounds Error")));
break;
}
#endif
//is the cookie a button?
if (nIndex < 40)
{
if (hidevent.value)
{
pThis->m_buttons |= (1 << nIndex);
wxevent.SetEventType(wxEVT_JOY_BUTTON_DOWN);
}
else
{
pThis->m_buttons &= ~(1 << nIndex);
wxevent.SetEventType(wxEVT_JOY_BUTTON_UP);
}
wxevent.SetButtonChange(nIndex+1);
}
else if (nIndex == wxJS_AXIS_X)
{
pThis->m_lastposition.x = hidevent.value;
wxevent.SetEventType(wxEVT_JOY_MOVE);
pThis->m_axe[0] = hidevent.value;
}
else if (nIndex == wxJS_AXIS_Y)
{
pThis->m_lastposition.y = hidevent.value;
wxevent.SetEventType(wxEVT_JOY_MOVE);
pThis->m_axe[1] = hidevent.value;
}
else if (nIndex == wxJS_AXIS_Z)
{
wxevent.SetEventType(wxEVT_JOY_ZMOVE);
pThis->m_axe[2] = hidevent.value;
}
else
wxevent.SetEventType(wxEVT_JOY_MOVE);
Nanoseconds timestamp = AbsoluteToNanoseconds(hidevent.timestamp);
wxULongLong llTime(timestamp.hi, timestamp.lo);
llTime /= 1000000;
wxevent.SetTimestamp(llTime.GetValue());
wxevent.SetJoystick(pThis->m_joystick);
wxevent.SetButtonState(pThis->m_buttons);
wxevent.SetPosition(pThis->m_lastposition);
wxevent.SetZPosition(pThis->m_axe[2]);
wxevent.SetEventObject(pThis->m_catchwin);
if (pThis->m_catchwin)
pThis->m_catchwin->AddPendingEvent(wxevent);
ret = (*m_hid->GetQueue())->getNextEvent(m_hid->GetQueue(),
&hidevent, bogustime, 0);
}
}
#endif // wxUSE_JOYSTICK

View File

@@ -0,0 +1,217 @@
///////////////////////////////////////////////////////////////////////////////
// Name: mac/corefoundation/stdpaths.cpp
// Purpose: wxStandardPaths implementation for CoreFoundation systems
// Author: David Elliott
// Modified by:
// Created: 2004-10-27
// RCS-ID: $Id$
// Copyright: (c) 2004 David Elliott <dfe@cox.net>
// Licence: wxWindows licence
///////////////////////////////////////////////////////////////////////////////
// ============================================================================
// declarations
// ============================================================================
// ----------------------------------------------------------------------------
// headers
// ----------------------------------------------------------------------------
#include "wx/wxprec.h"
#if wxUSE_STDPATHS
#ifndef WX_PRECOMP
#include "wx/intl.h"
#endif //ndef WX_PRECOMP
#include "wx/stdpaths.h"
#include "wx/filename.h"
#ifdef __WXMAC__
#include "wx/mac/private.h"
#endif
#include "wx/mac/corefoundation/cfstring.h"
#include <CoreFoundation/CFBundle.h>
#include <CoreFoundation/CFURL.h>
#define kDefaultPathStyle kCFURLPOSIXPathStyle
// ============================================================================
// implementation
// ============================================================================
// ----------------------------------------------------------------------------
// wxStandardPathsCF ctors/dtor
// ----------------------------------------------------------------------------
wxStandardPathsCF::wxStandardPathsCF()
: m_bundle(CFBundleGetMainBundle())
{
CFRetain(m_bundle);
UseAppInfo(AppInfo_AppName | AppInfo_VendorName);
}
wxStandardPathsCF::wxStandardPathsCF(wxCFBundleRef bundle)
: m_bundle(bundle)
{
CFRetain(m_bundle);
UseAppInfo(AppInfo_AppName | AppInfo_VendorName);
}
wxStandardPathsCF::~wxStandardPathsCF()
{
CFRelease(m_bundle);
}
// ----------------------------------------------------------------------------
// wxStandardPathsCF Mac-specific methods
// ----------------------------------------------------------------------------
void wxStandardPathsCF::SetBundle(wxCFBundleRef bundle)
{
CFRetain(bundle);
CFRelease(m_bundle);
m_bundle = bundle;
}
// ----------------------------------------------------------------------------
// generic functions in terms of which the other ones are implemented
// ----------------------------------------------------------------------------
static wxString BundleRelativeURLToPath(CFURLRef relativeURL)
{
CFURLRef absoluteURL = CFURLCopyAbsoluteURL(relativeURL);
wxCHECK_MSG(absoluteURL, wxEmptyString, wxT("Failed to resolve relative URL to absolute URL"));
CFStringRef cfStrPath = CFURLCopyFileSystemPath(absoluteURL,kDefaultPathStyle);
CFRelease(absoluteURL);
return wxCFStringRef(cfStrPath).AsString(wxLocale::GetSystemEncoding());
}
wxString wxStandardPathsCF::GetFromFunc(wxCFURLRef (*func)(wxCFBundleRef)) const
{
wxCHECK_MSG(m_bundle, wxEmptyString,
wxT("wxStandardPaths for CoreFoundation only works with bundled apps"));
CFURLRef relativeURL = (*func)(m_bundle);
wxCHECK_MSG(relativeURL, wxEmptyString, wxT("Couldn't get URL"));
wxString ret(BundleRelativeURLToPath(relativeURL));
CFRelease(relativeURL);
return ret;
}
wxString wxStandardPathsCF::GetDocumentsDir() const
{
#if defined( __WXMAC__ ) && !defined(__WXOSX_IPHONE__)
return wxMacFindFolderNoSeparator
(
kUserDomain,
kDocumentsFolderType,
kCreateFolder
);
#else
return wxFileName::GetHomeDir() + wxT("/Documents");
#endif
}
// ----------------------------------------------------------------------------
// wxStandardPathsCF public API
// ----------------------------------------------------------------------------
wxString wxStandardPathsCF::GetConfigDir() const
{
#if defined( __WXMAC__ ) && !defined(__WXOSX_IPHONE__)
return wxMacFindFolder((short)kLocalDomain, kPreferencesFolderType, kCreateFolder);
#else
return wxT("/Library/Preferences");
#endif
}
wxString wxStandardPathsCF::GetUserConfigDir() const
{
#if defined( __WXMAC__ ) && !defined(__WXOSX_IPHONE__)
return wxMacFindFolder((short)kUserDomain, kPreferencesFolderType, kCreateFolder);
#else
return wxFileName::GetHomeDir() + wxT("/Library/Preferences");
#endif
}
wxString wxStandardPathsCF::GetDataDir() const
{
return GetFromFunc(CFBundleCopySharedSupportURL);
}
wxString wxStandardPathsCF::GetExecutablePath() const
{
#ifdef __WXMAC__
#if 1
return GetFromFunc(CFBundleCopyBundleURL);
#else
// TODO remove if cf implementation ok
ProcessInfoRec processinfo;
ProcessSerialNumber procno ;
#ifdef __LP64__
FSRef fsRef;
#else
FSSpec fsSpec;
#endif
procno.highLongOfPSN = 0 ;
procno.lowLongOfPSN = kCurrentProcess ;
processinfo.processInfoLength = sizeof(ProcessInfoRec);
processinfo.processName = NULL;
#ifdef __LP64__
processinfo.processAppRef = &fsRef;
#else
processinfo.processAppSpec = &fsSpec;
#endif
GetProcessInformation( &procno , &processinfo ) ;
#ifdef __LP64__
return wxMacFSRefToPath(&fsRef);
#else
return wxMacFSSpec2MacFilename(&fsSpec);
#endif
#endif
#else
return wxStandardPathsBase::GetExecutablePath();
#endif
}
wxString wxStandardPathsCF::GetLocalDataDir() const
{
#if defined( __WXMAC__ ) && !defined(__WXOSX_IPHONE__)
return AppendAppInfo(wxMacFindFolder((short)kLocalDomain, kApplicationSupportFolderType, kCreateFolder));
#else
return AppendAppInfo(wxT("/Library/Application Support"));
#endif
}
wxString wxStandardPathsCF::GetUserDataDir() const
{
#if defined( __WXMAC__ ) && !defined(__WXOSX_IPHONE__)
return AppendAppInfo(wxMacFindFolder((short)kUserDomain, kApplicationSupportFolderType, kCreateFolder));
#else
return AppendAppInfo(wxFileName::GetHomeDir() + _T("/Library/Application Support"));
#endif
}
wxString wxStandardPathsCF::GetPluginsDir() const
{
return GetFromFunc(CFBundleCopyBuiltInPlugInsURL);
}
wxString wxStandardPathsCF::GetResourcesDir() const
{
return GetFromFunc(CFBundleCopyResourcesDirectoryURL);
}
wxString
wxStandardPathsCF::GetLocalizedResourcesDir(const wxString& lang,
ResourceCat category) const
{
return wxStandardPathsBase::
GetLocalizedResourcesDir(lang, category) + _T(".lproj");
}
#endif // wxUSE_STDPATHS

228
src/mac/core/strconv_cf.cpp Normal file
View File

@@ -0,0 +1,228 @@
/////////////////////////////////////////////////////////////////////////////
// Name: src/mac/corefoundation/strconv.cpp
// Purpose: Unicode conversion classes
// Author: David Elliott
// Modified by:
// Created: 2007-07-06
// RCS-ID: $Id$
// Copyright: (c) 2007 David Elliott
// Licence: wxWindows licence
/////////////////////////////////////////////////////////////////////////////
// For compilers that support precompilation, includes "wx.h".
#include "wx/wxprec.h"
#ifndef WX_PRECOMP
#include "wx/string.h"
#endif
#include "wx/strconv.h"
#include "wx/fontmap.h"
#ifdef __DARWIN__
#include "wx/mac/corefoundation/private/strconv_cf.h"
#include "wx/mac/corefoundation/cfref.h"
// ============================================================================
// CoreFoundation conversion classes
// ============================================================================
/* Provide factory functions for unit tests. Not in any header. Do not
* assume ABI compatibility even within a given wxWidgets release.
*/
WXDLLIMPEXP_BASE wxMBConv* new_wxMBConv_cf( const char* name)
{
wxMBConv_cf *result = new wxMBConv_cf(name);
if(!result->IsOk())
{
delete result;
return NULL;
}
else
return result;
}
WXDLLIMPEXP_BASE wxMBConv* new_wxMBConv_cf(wxFontEncoding encoding)
{
wxMBConv_cf *result = new wxMBConv_cf(encoding);
if(!result->IsOk())
{
delete result;
return NULL;
}
else
return result;
}
// Provide a constant for the wchat_t encoding used by the host platform.
#ifdef WORDS_BIGENDIAN
static const CFStringEncoding wxCFStringEncodingWcharT = kCFStringEncodingUTF32BE;
#else
static const CFStringEncoding wxCFStringEncodingWcharT = kCFStringEncodingUTF32LE;
#endif
size_t wxMBConv_cf::ToWChar(wchar_t * dst, size_t dstSize, const char * src, size_t srcSize) const
{
wxCHECK(src, wxCONV_FAILED);
/* NOTE: This is wrong if the source encoding has an element size
* other than char (e.g. it's kCFStringEncodingUnicode)
* If the user specifies it, it's presumably right though.
* Right now we don't support UTF-16 in anyway since wx can do a better job.
*/
if(srcSize == wxNO_LEN)
srcSize = strlen(src) + 1;
// First create the temporary CFString
wxCFRef<CFStringRef> theString( CFStringCreateWithBytes (
NULL, //the allocator
(const UInt8*)src,
srcSize,
m_encoding,
false //no BOM/external representation
));
wxCHECK(theString != NULL, wxCONV_FAILED);
/* NOTE: The string content includes the NULL element if the source string did
* That means we have to do nothing special because the destination will have
* the NULL element iff the source did and the NULL element will be included
* in the count iff it was included in the source count.
*/
/* If we're compiling against Tiger headers we can support direct conversion
* to UTF32. If we are then run against a pre-Tiger system, the encoding
* won't be available so we'll defer to the string->UTF-16->UTF-32 conversion.
*/
if(CFStringIsEncodingAvailable(wxCFStringEncodingWcharT))
{
CFRange fullStringRange = CFRangeMake(0, CFStringGetLength(theString));
CFIndex usedBufLen;
CFIndex charsConverted = CFStringGetBytes(
theString,
fullStringRange,
wxCFStringEncodingWcharT,
0,
false,
// if dstSize is 0 then pass NULL to get required length in usedBufLen
dstSize != 0?(UInt8*)dst:NULL,
dstSize * sizeof(wchar_t),
&usedBufLen);
// charsConverted is > 0 iff conversion succeeded
if(charsConverted <= 0)
return wxCONV_FAILED;
/* usedBufLen is the number of bytes written, so we divide by
* sizeof(wchar_t) to get the number of elements written.
*/
wxASSERT( (usedBufLen % sizeof(wchar_t)) == 0 );
// CFStringGetBytes does exactly the right thing when buffer
// pointer is NULL and returns the number of bytes required
return usedBufLen / sizeof(wchar_t);
}
else
{
// NOTE: Includes NULL iff source did
/* NOTE: This is an approximation. The eventual UTF-32 will
* possibly have less elements but certainly not more.
*/
size_t returnSize = CFStringGetLength(theString);
if (dstSize == 0 || dst == NULL)
{
return returnSize;
}
// Convert the entire string.. too hard to figure out how many UTF-16 we'd need
// for an undersized UTF-32 destination buffer.
CFRange fullStringRange = CFRangeMake(0, CFStringGetLength(theString));
UniChar *szUniCharBuffer = new UniChar[fullStringRange.length];
CFStringGetCharacters(theString, fullStringRange, szUniCharBuffer);
wxMBConvUTF16 converter;
returnSize = converter.ToWChar( dst, dstSize, (const char*)szUniCharBuffer, fullStringRange.length );
delete [] szUniCharBuffer;
return returnSize;
}
// NOTREACHED
}
size_t wxMBConv_cf::FromWChar(char *dst, size_t dstSize, const wchar_t *src, size_t srcSize) const
{
wxCHECK(src, wxCONV_FAILED);
if(srcSize == wxNO_LEN)
srcSize = wxStrlen(src) + 1;
// Temporary CFString
wxCFRef<CFStringRef> theString;
/* If we're compiling against Tiger headers we can support direct conversion
* from UTF32. If we are then run against a pre-Tiger system, the encoding
* won't be available so we'll defer to the UTF-32->UTF-16->string conversion.
*/
if(CFStringIsEncodingAvailable(wxCFStringEncodingWcharT))
{
theString = wxCFRef<CFStringRef>(CFStringCreateWithBytes(
kCFAllocatorDefault,
(UInt8*)src,
srcSize * sizeof(wchar_t),
wxCFStringEncodingWcharT,
false));
}
else
{
wxMBConvUTF16 converter;
size_t cbUniBuffer = converter.FromWChar( NULL, 0, src, srcSize );
wxASSERT(cbUniBuffer % sizeof(UniChar));
// Will be free'd by kCFAllocatorMalloc when CFString is released
UniChar *tmpUniBuffer = (UniChar*)malloc(cbUniBuffer);
cbUniBuffer = converter.FromWChar( (char*) tmpUniBuffer, cbUniBuffer, src, srcSize );
wxASSERT(cbUniBuffer % sizeof(UniChar));
theString = wxCFRef<CFStringRef>(CFStringCreateWithCharactersNoCopy(
kCFAllocatorDefault,
tmpUniBuffer,
cbUniBuffer / sizeof(UniChar),
kCFAllocatorMalloc
));
}
wxCHECK(theString != NULL, wxCONV_FAILED);
CFIndex usedBufLen;
CFIndex charsConverted = CFStringGetBytes(
theString,
CFRangeMake(0, CFStringGetLength(theString)),
m_encoding,
0, // FAIL on unconvertible characters
false, // not an external representation
// if dstSize is 0 then pass NULL to get required length in usedBufLen
(dstSize != 0)?(UInt8*)dst:NULL,
dstSize,
&usedBufLen
);
// charsConverted is > 0 iff conversion succeeded
if(charsConverted <= 0)
return wxCONV_FAILED;
return usedBufLen;
}
#endif // __DARWIN__

View File

@@ -0,0 +1,229 @@
/////////////////////////////////////////////////////////////////////////////
// Name: mac/corefoundation/utilsexc_base.cpp
// Purpose: wxMacLaunch
// Author: Ryan Norton
// Modified by:
// Created: 2005-06-21
// RCS-ID: $Id$
// Copyright: (c) Ryan Norton
// Licence: wxWindows licence
// Notes: Source was originally in utilsexc_cf.cpp,1.6 then moved
// to totally unrelated hid.cpp,1.8.
/////////////////////////////////////////////////////////////////////////////
//===========================================================================
// DECLARATIONS
//===========================================================================
//---------------------------------------------------------------------------
// Pre-compiled header stuff
//---------------------------------------------------------------------------
// For compilers that support precompilation, includes "wx.h".
#include "wx/wxprec.h"
// WX includes
#ifndef WX_PRECOMP
#include "wx/string.h"
#include "wx/log.h"
#include "wx/intl.h"
#include "wx/utils.h"
#include "wx/wxcrt.h"
#endif // WX_PRECOMP
// Mac Includes
#include <CoreFoundation/CoreFoundation.h>
#ifndef __WXOSX_IPHONE__
#include <ApplicationServices/ApplicationServices.h>
#endif
// More WX Includes
#include "wx/filename.h"
#include "wx/mac/corefoundation/cfstring.h"
// Default path style
#define kDefaultPathStyle kCFURLPOSIXPathStyle
//===========================================================================
// IMPLEMENTATION
//===========================================================================
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
//
// wxMacLaunch
//
// argv is the command line split up, with the application path first
// flags are the flags from wxExecute
// process is the process passed from wxExecute for pipe streams etc.
// returns -1 on error for wxEXEC_SYNC and 0 on error for wxEXEC_ASYNC
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
bool wxMacLaunch(char **argv)
{
// Obtains the number of arguments for determining the size of
// the CFArray used to hold them
CFIndex cfiCount = 0;
for(char** argvcopy = argv; *argvcopy != NULL ; ++argvcopy)
{
++cfiCount;
}
// If there is not a single argument then there is no application
// to launch
if(cfiCount == 0)
{
wxLogDebug(wxT("wxMacLaunch No file to launch!"));
return false ;
}
// Path to bundle
wxString path = *argv++;
// Create a CFURL for the application path
// Created this way because we are opening a bundle which is a directory
CFURLRef cfurlApp =
CFURLCreateWithFileSystemPath(
kCFAllocatorDefault,
wxCFStringRef(path),
kDefaultPathStyle,
true); //false == not a directory
// Check for error from the CFURL
if(!cfurlApp)
{
wxLogDebug(wxT("wxMacLaunch Can't open path: %s"), path.c_str());
return false ;
}
// Create a CFBundle from the CFURL created earlier
CFBundleRef cfbApp = CFBundleCreate(kCFAllocatorDefault, cfurlApp);
// Check to see if CFBundleCreate returned an error,
// and if it did this was an invalid bundle or not a bundle
// at all (maybe a simple directory etc.)
if(!cfbApp)
{
wxLogDebug(wxT("wxMacLaunch Bad bundle: %s"), path.c_str());
CFRelease(cfurlApp);
return false ;
}
// Get the bundle type and make sure its an 'APPL' bundle
// Otherwise we're dealing with something else here...
UInt32 dwBundleType, dwBundleCreator;
CFBundleGetPackageInfo(cfbApp, &dwBundleType, &dwBundleCreator);
if(dwBundleType != 'APPL')
{
wxLogDebug(wxT("wxMacLaunch Not an APPL bundle: %s"), path.c_str());
CFRelease(cfbApp);
CFRelease(cfurlApp);
return false ;
}
// Create a CFArray for dealing with the command line
// arguments to the bundle
CFMutableArrayRef cfaFiles = CFArrayCreateMutable(kCFAllocatorDefault,
cfiCount-1, &kCFTypeArrayCallBacks);
if(!cfaFiles) //This should never happen
{
wxLogDebug(wxT("wxMacLaunch Could not create CFMutableArray"));
CFRelease(cfbApp);
CFRelease(cfurlApp);
return false ;
}
// Loop through command line arguments to the bundle,
// turn them into CFURLs and then put them in cfaFiles
// For use to launch services call
for( ; *argv != NULL ; ++argv)
{
// Check for '<' as this will ring true for
// CFURLCreateWithString but is generally not considered
// typical on mac but is usually passed here from wxExecute
if (wxStrcmp(*argv, wxT("<")) == 0)
continue;
CFURLRef cfurlCurrentFile; // CFURL to hold file path
wxFileName argfn(*argv); // Filename for path
if(argfn.DirExists())
{
// First, try creating as a directory
cfurlCurrentFile = CFURLCreateWithFileSystemPath(
kCFAllocatorDefault,
wxCFStringRef(*argv),
kDefaultPathStyle,
true); //true == directory
}
else if(argfn.FileExists())
{
// And if it isn't a directory try creating it
// as a regular file
cfurlCurrentFile = CFURLCreateWithFileSystemPath(
kCFAllocatorDefault,
wxCFStringRef(*argv),
kDefaultPathStyle,
false); //false == regular file
}
else
{
// Argument did not refer to
// an entry in the local filesystem,
// so try creating it through CFURLCreateWithString
cfurlCurrentFile = CFURLCreateWithString(
kCFAllocatorDefault,
wxCFStringRef(*argv),
NULL);
}
// Continue in the loop if the CFURL could not be created
if(!cfurlCurrentFile)
{
wxLogDebug(
wxT("wxMacLaunch Could not create CFURL for argument:%s"),
*argv);
continue;
}
// Add the valid CFURL to the argument array and then
// release it as the CFArray adds a ref count to it
CFArrayAppendValue(
cfaFiles,
cfurlCurrentFile
);
CFRelease(cfurlCurrentFile); // array has retained it
}
// Create a LSLaunchURLSpec for use with LSOpenFromURLSpec
// Note that there are several flag options (launchFlags) such
// as kLSLaunchDontSwitch etc. and maybe we could be more
// picky about the flags we choose
LSLaunchURLSpec launchspec;
launchspec.appURL = cfurlApp;
launchspec.itemURLs = cfaFiles;
launchspec.passThruParams = NULL; //AEDesc*
launchspec.launchFlags = kLSLaunchDefaults;
launchspec.asyncRefCon = NULL;
// Finally, call LSOpenFromURL spec with our arguments
// 2nd parameter is a pointer to a CFURL that gets
// the actual path launched by the function
OSStatus status = LSOpenFromURLSpec(&launchspec, NULL);
// Cleanup corefoundation references
CFRelease(cfbApp);
CFRelease(cfurlApp);
CFRelease(cfaFiles);
// Check for error from LSOpenFromURLSpec
if(status != noErr)
{
wxLogDebug(wxT("wxMacLaunch LSOpenFromURLSpec Error: %d"),
(int)status);
return false ;
}
// No error from LSOpenFromURLSpec, so app was launched
return true ;
}

View File

@@ -0,0 +1,118 @@
/////////////////////////////////////////////////////////////////////////////
// Name: src/mac/corefoundation/utilsexec_cf.cpp
// Purpose: Execution-related utilities for Darwin
// Author: David Elliott, Ryan Norton (wxMacExecute)
// Modified by: Stefan Csomor (added necessary wxT for unicode builds)
// Created: 2004-11-04
// RCS-ID: $Id$
// Copyright: (c) David Elliott, Ryan Norton
// Licence: wxWindows licence
// Notes: This code comes from src/mac/carbon/utilsexc.cpp,1.11
/////////////////////////////////////////////////////////////////////////////
#include "wx/wxprec.h"
#ifndef WX_PRECOMP
#include "wx/log.h"
#include "wx/utils.h"
#endif //ndef WX_PRECOMP
#include "wx/unix/execute.h"
#include "wx/stdpaths.h"
#include "wx/app.h"
#include "wx/apptrait.h"
#include "wx/thread.h"
#include "wx/process.h"
#include <sys/wait.h>
#include <CoreFoundation/CFSocket.h>
/*!
Called due to source signal detected by the CFRunLoop.
This is nearly identical to the wxGTK equivalent.
*/
extern "C" void WXCF_EndProcessDetector(CFSocketRef s,
CFSocketCallBackType WXUNUSED(callbackType),
CFDataRef WXUNUSED(address),
void const *WXUNUSED(data),
void *info)
{
/*
Either our pipe was closed or the process ended successfully. Either way,
we're done. It's not if waitpid is going to magically succeed when
we get fired again. CFSocketInvalidate closes the fd for us and also
invalidates the run loop source for us which should cause it to
release the CFSocket (thus causing it to be deallocated) and remove
itself from the runloop which should release it and cause it to also
be deallocated. Of course, it's possible the RunLoop hangs onto
one or both of them by retaining/releasing them within its stack
frame. However, that shouldn't be depended on. Assume that s is
deallocated due to the following call.
*/
CFSocketInvalidate(s);
// Now tell wx that the process has ended.
wxHandleProcessTermination(static_cast<wxEndProcessData *>(info));
}
/*!
Implements the GUI-specific AddProcessCallback() for both wxMac and
wxCocoa using the CFSocket/CFRunLoop API which is available to both.
Takes advantage of the fact that sockets on UNIX are just regular
file descriptors and thus even a non-socket file descriptor can
apparently be used with CFSocket so long as you only tell CFSocket
to do things with it that would be valid for a non-socket fd.
*/
int wxGUIAppTraits::AddProcessCallback(wxEndProcessData *proc_data, int fd)
{
static int s_last_tag = 0;
CFSocketContext context =
{ 0
, static_cast<void*>(proc_data)
, NULL
, NULL
, NULL
};
CFSocketRef cfSocket = CFSocketCreateWithNative(kCFAllocatorDefault,fd,kCFSocketReadCallBack,&WXCF_EndProcessDetector,&context);
if(cfSocket == NULL)
{
wxLogError(wxT("Failed to create socket for end process detection"));
return 0;
}
CFRunLoopSourceRef runLoopSource = CFSocketCreateRunLoopSource(kCFAllocatorDefault, cfSocket, /*highest priority:*/0);
if(runLoopSource == NULL)
{
wxLogError(wxT("Failed to create CFRunLoopSource from CFSocket for end process detection"));
// closes the fd.. we can't really stop it, nor do we necessarily want to.
CFSocketInvalidate(cfSocket);
CFRelease(cfSocket);
return 0;
}
// Now that the run loop source has the socket retained and we no longer
// need to refer to it within this method, we can release it.
CFRelease(cfSocket);
CFRunLoopAddSource(CFRunLoopGetCurrent(), runLoopSource, kCFRunLoopCommonModes);
// Now that the run loop has the source retained we can release it.
CFRelease(runLoopSource);
/*
Feed wx some bullshit.. we don't use it since CFSocket helpfully passes
itself into our callback and that's enough to be able to
CFSocketInvalidate it which is all we need to do to get everything we
just created to be deallocated.
*/
return ++s_last_tag;
}
/////////////////////////////////////////////////////////////////////////////
// NOTE: This doesn't really belong here but this was a handy file to
// put it in because it's already compiled for wxCocoa and wxMac GUI lib.
#if wxUSE_STDPATHS
static wxStandardPathsCF gs_stdPaths;
wxStandardPathsBase& wxGUIAppTraits::GetStandardPaths()
{
return gs_stdPaths;
}
#endif