From 9acbdb4313d9d421911dc27cc3c5a815786c7aef Mon Sep 17 00:00:00 2001 From: Stefan Csomor Date: Wed, 11 Jun 2008 16:26:59 +0000 Subject: [PATCH] renaming git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@54115 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775 --- src/mac/core/cfstring.cpp | 732 ++++++++++++++++++++++++++ src/mac/core/gsockosx.cpp | 318 ++++++++++++ src/mac/core/hid.cpp | 741 +++++++++++++++++++++++++++ src/mac/core/hidjoystick.cpp | 905 +++++++++++++++++++++++++++++++++ src/mac/core/stdpaths_cf.cpp | 217 ++++++++ src/mac/core/strconv_cf.cpp | 228 +++++++++ src/mac/core/utilsexc_base.cpp | 229 +++++++++ src/mac/core/utilsexc_cf.cpp | 118 +++++ 8 files changed, 3488 insertions(+) create mode 100644 src/mac/core/cfstring.cpp create mode 100644 src/mac/core/gsockosx.cpp create mode 100644 src/mac/core/hid.cpp create mode 100644 src/mac/core/hidjoystick.cpp create mode 100644 src/mac/core/stdpaths_cf.cpp create mode 100644 src/mac/core/strconv_cf.cpp create mode 100644 src/mac/core/utilsexc_base.cpp create mode 100644 src/mac/core/utilsexc_cf.cpp diff --git a/src/mac/core/cfstring.cpp b/src/mac/core/cfstring.cpp new file mode 100644 index 0000000000..5b1f8ce7e1 --- /dev/null +++ b/src/mac/core/cfstring.cpp @@ -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 + +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 ; +} diff --git a/src/mac/core/gsockosx.cpp b/src/mac/core/gsockosx.cpp new file mode 100644 index 0000000000..695dab74ca --- /dev/null +++ b/src/mac/core/gsockosx.cpp @@ -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 + +// ---------------------------------------------------------------------------- +// 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 diff --git a/src/mac/core/hid.cpp b/src/mac/core/hid.cpp new file mode 100644 index 0000000000..fb9a4d051d --- /dev/null +++ b/src/mac/core/hid.cpp @@ -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__ diff --git a/src/mac/core/hidjoystick.cpp b/src/mac/core/hidjoystick.cpp new file mode 100644 index 0000000000..637546c414 --- /dev/null +++ b/src/mac/core/hidjoystick.cpp @@ -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 +#include +#include +#include + +//--------------------------------------------------------------------------- +// 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 diff --git a/src/mac/core/stdpaths_cf.cpp b/src/mac/core/stdpaths_cf.cpp new file mode 100644 index 0000000000..69e524f1fc --- /dev/null +++ b/src/mac/core/stdpaths_cf.cpp @@ -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 +// 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 +#include + +#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 diff --git a/src/mac/core/strconv_cf.cpp b/src/mac/core/strconv_cf.cpp new file mode 100644 index 0000000000..e68d8e4ef6 --- /dev/null +++ b/src/mac/core/strconv_cf.cpp @@ -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 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 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(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(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__ + + diff --git a/src/mac/core/utilsexc_base.cpp b/src/mac/core/utilsexc_base.cpp new file mode 100644 index 0000000000..377b2464be --- /dev/null +++ b/src/mac/core/utilsexc_base.cpp @@ -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 +#ifndef __WXOSX_IPHONE__ +#include +#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 ; +} + diff --git a/src/mac/core/utilsexc_cf.cpp b/src/mac/core/utilsexc_cf.cpp new file mode 100644 index 0000000000..2d95454fe9 --- /dev/null +++ b/src/mac/core/utilsexc_cf.cpp @@ -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 + +#include + +/*! + 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(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(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 + -- 2.45.2