1*9f62ea84SAndrew Rist /************************************************************** 2cdf0e10cSrcweir * 3*9f62ea84SAndrew Rist * Licensed to the Apache Software Foundation (ASF) under one 4*9f62ea84SAndrew Rist * or more contributor license agreements. See the NOTICE file 5*9f62ea84SAndrew Rist * distributed with this work for additional information 6*9f62ea84SAndrew Rist * regarding copyright ownership. The ASF licenses this file 7*9f62ea84SAndrew Rist * to you under the Apache License, Version 2.0 (the 8*9f62ea84SAndrew Rist * "License"); you may not use this file except in compliance 9*9f62ea84SAndrew Rist * with the License. You may obtain a copy of the License at 10cdf0e10cSrcweir * 11*9f62ea84SAndrew Rist * http://www.apache.org/licenses/LICENSE-2.0 12cdf0e10cSrcweir * 13*9f62ea84SAndrew Rist * Unless required by applicable law or agreed to in writing, 14*9f62ea84SAndrew Rist * software distributed under the License is distributed on an 15*9f62ea84SAndrew Rist * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 16*9f62ea84SAndrew Rist * KIND, either express or implied. See the License for the 17*9f62ea84SAndrew Rist * specific language governing permissions and limitations 18*9f62ea84SAndrew Rist * under the License. 19cdf0e10cSrcweir * 20*9f62ea84SAndrew Rist *************************************************************/ 21*9f62ea84SAndrew Rist 22*9f62ea84SAndrew Rist 23cdf0e10cSrcweir 24cdf0e10cSrcweir // MARKER(update_precomp.py): autogen include statement, do not remove 25cdf0e10cSrcweir #include "precompiled_vcl.hxx" 26cdf0e10cSrcweir 27cdf0e10cSrcweir #include <string.h> 28cdf0e10cSrcweir #include <vcl/svapp.hxx> 29cdf0e10cSrcweir #include <vcl/settings.hxx> 30cdf0e10cSrcweir #include <vcl/mnemonic.hxx> 31cdf0e10cSrcweir 32cdf0e10cSrcweir #include <vcl/unohelp.hxx> 33cdf0e10cSrcweir #include <com/sun/star/i18n/XCharacterClassification.hpp> 34cdf0e10cSrcweir 35cdf0e10cSrcweir using namespace ::com::sun::star; 36cdf0e10cSrcweir 37cdf0e10cSrcweir 38cdf0e10cSrcweir // ======================================================================= 39cdf0e10cSrcweir 40cdf0e10cSrcweir MnemonicGenerator::MnemonicGenerator() 41cdf0e10cSrcweir { 42cdf0e10cSrcweir memset( maMnemonics, 1, sizeof( maMnemonics ) ); 43cdf0e10cSrcweir } 44cdf0e10cSrcweir 45cdf0e10cSrcweir // ----------------------------------------------------------------------- 46cdf0e10cSrcweir 47cdf0e10cSrcweir sal_uInt16 MnemonicGenerator::ImplGetMnemonicIndex( sal_Unicode c ) 48cdf0e10cSrcweir { 49cdf0e10cSrcweir static sal_uInt16 const aImplMnemonicRangeTab[MNEMONIC_RANGES*2] = 50cdf0e10cSrcweir { 51cdf0e10cSrcweir MNEMONIC_RANGE_1_START, MNEMONIC_RANGE_1_END, 52cdf0e10cSrcweir MNEMONIC_RANGE_2_START, MNEMONIC_RANGE_2_END, 53cdf0e10cSrcweir MNEMONIC_RANGE_3_START, MNEMONIC_RANGE_3_END, 54cdf0e10cSrcweir MNEMONIC_RANGE_4_START, MNEMONIC_RANGE_4_END 55cdf0e10cSrcweir }; 56cdf0e10cSrcweir 57cdf0e10cSrcweir sal_uInt16 nMnemonicIndex = 0; 58cdf0e10cSrcweir for ( sal_uInt16 i = 0; i < MNEMONIC_RANGES; i++ ) 59cdf0e10cSrcweir { 60cdf0e10cSrcweir if ( (c >= aImplMnemonicRangeTab[i*2]) && 61cdf0e10cSrcweir (c <= aImplMnemonicRangeTab[i*2+1]) ) 62cdf0e10cSrcweir return nMnemonicIndex+c-aImplMnemonicRangeTab[i*2]; 63cdf0e10cSrcweir 64cdf0e10cSrcweir nMnemonicIndex += aImplMnemonicRangeTab[i*2+1]-aImplMnemonicRangeTab[i*2]; 65cdf0e10cSrcweir } 66cdf0e10cSrcweir 67cdf0e10cSrcweir return MNEMONIC_INDEX_NOTFOUND; 68cdf0e10cSrcweir } 69cdf0e10cSrcweir 70cdf0e10cSrcweir // ----------------------------------------------------------------------- 71cdf0e10cSrcweir 72cdf0e10cSrcweir sal_Unicode MnemonicGenerator::ImplFindMnemonic( const XubString& rKey ) 73cdf0e10cSrcweir { 74cdf0e10cSrcweir xub_StrLen nIndex = 0; 75cdf0e10cSrcweir while ( (nIndex = rKey.Search( MNEMONIC_CHAR, nIndex )) != STRING_NOTFOUND ) 76cdf0e10cSrcweir { 77cdf0e10cSrcweir sal_Unicode cMnemonic = rKey.GetChar( nIndex+1 ); 78cdf0e10cSrcweir if ( cMnemonic != MNEMONIC_CHAR ) 79cdf0e10cSrcweir return cMnemonic; 80cdf0e10cSrcweir nIndex += 2; 81cdf0e10cSrcweir } 82cdf0e10cSrcweir 83cdf0e10cSrcweir return 0; 84cdf0e10cSrcweir } 85cdf0e10cSrcweir 86cdf0e10cSrcweir // ----------------------------------------------------------------------- 87cdf0e10cSrcweir 88cdf0e10cSrcweir void MnemonicGenerator::RegisterMnemonic( const XubString& rKey ) 89cdf0e10cSrcweir { 90cdf0e10cSrcweir const ::com::sun::star::lang::Locale& rLocale = Application::GetSettings().GetUILocale(); 91cdf0e10cSrcweir uno::Reference < i18n::XCharacterClassification > xCharClass = GetCharClass(); 92cdf0e10cSrcweir 93cdf0e10cSrcweir // Don't crash even when we don't have access to i18n service 94cdf0e10cSrcweir if ( !xCharClass.is() ) 95cdf0e10cSrcweir return; 96cdf0e10cSrcweir 97cdf0e10cSrcweir XubString aKey = xCharClass->toUpper( rKey, 0, rKey.Len(), rLocale ); 98cdf0e10cSrcweir 99cdf0e10cSrcweir // If we find a Mnemonic, set the flag. In other case count the 100cdf0e10cSrcweir // characters, because we need this to set most as possible 101cdf0e10cSrcweir // Mnemonics 102cdf0e10cSrcweir sal_Unicode cMnemonic = ImplFindMnemonic( aKey ); 103cdf0e10cSrcweir if ( cMnemonic ) 104cdf0e10cSrcweir { 105cdf0e10cSrcweir sal_uInt16 nMnemonicIndex = ImplGetMnemonicIndex( cMnemonic ); 106cdf0e10cSrcweir if ( nMnemonicIndex != MNEMONIC_INDEX_NOTFOUND ) 107cdf0e10cSrcweir maMnemonics[nMnemonicIndex] = 0; 108cdf0e10cSrcweir } 109cdf0e10cSrcweir else 110cdf0e10cSrcweir { 111cdf0e10cSrcweir xub_StrLen nIndex = 0; 112cdf0e10cSrcweir xub_StrLen nLen = aKey.Len(); 113cdf0e10cSrcweir while ( nIndex < nLen ) 114cdf0e10cSrcweir { 115cdf0e10cSrcweir sal_Unicode c = aKey.GetChar( nIndex ); 116cdf0e10cSrcweir 117cdf0e10cSrcweir sal_uInt16 nMnemonicIndex = ImplGetMnemonicIndex( c ); 118cdf0e10cSrcweir if ( nMnemonicIndex != MNEMONIC_INDEX_NOTFOUND ) 119cdf0e10cSrcweir { 120cdf0e10cSrcweir if ( maMnemonics[nMnemonicIndex] && (maMnemonics[nMnemonicIndex] < 0xFF) ) 121cdf0e10cSrcweir maMnemonics[nMnemonicIndex]++; 122cdf0e10cSrcweir } 123cdf0e10cSrcweir 124cdf0e10cSrcweir nIndex++; 125cdf0e10cSrcweir } 126cdf0e10cSrcweir } 127cdf0e10cSrcweir } 128cdf0e10cSrcweir 129cdf0e10cSrcweir // ----------------------------------------------------------------------- 130cdf0e10cSrcweir 131cdf0e10cSrcweir sal_Bool MnemonicGenerator::CreateMnemonic( XubString& rKey ) 132cdf0e10cSrcweir { 133cdf0e10cSrcweir if ( !rKey.Len() || ImplFindMnemonic( rKey ) ) 134cdf0e10cSrcweir return sal_False; 135cdf0e10cSrcweir 136cdf0e10cSrcweir const ::com::sun::star::lang::Locale& rLocale = Application::GetSettings().GetUILocale(); 137cdf0e10cSrcweir uno::Reference < i18n::XCharacterClassification > xCharClass = GetCharClass(); 138cdf0e10cSrcweir 139cdf0e10cSrcweir // Don't crash even when we don't have access to i18n service 140cdf0e10cSrcweir if ( !xCharClass.is() ) 141cdf0e10cSrcweir return sal_False; 142cdf0e10cSrcweir 143cdf0e10cSrcweir XubString aKey = xCharClass->toUpper( rKey, 0, rKey.Len(), rLocale ); 144cdf0e10cSrcweir 145cdf0e10cSrcweir sal_Bool bChanged = sal_False; 146cdf0e10cSrcweir xub_StrLen nLen = aKey.Len(); 147cdf0e10cSrcweir 148cdf0e10cSrcweir sal_Bool bCJK = sal_False; 149cdf0e10cSrcweir switch( Application::GetSettings().GetUILanguage() ) 150cdf0e10cSrcweir { 151cdf0e10cSrcweir case LANGUAGE_JAPANESE: 152cdf0e10cSrcweir case LANGUAGE_CHINESE_TRADITIONAL: 153cdf0e10cSrcweir case LANGUAGE_CHINESE_SIMPLIFIED: 154cdf0e10cSrcweir case LANGUAGE_CHINESE_HONGKONG: 155cdf0e10cSrcweir case LANGUAGE_CHINESE_SINGAPORE: 156cdf0e10cSrcweir case LANGUAGE_CHINESE_MACAU: 157cdf0e10cSrcweir case LANGUAGE_KOREAN: 158cdf0e10cSrcweir case LANGUAGE_KOREAN_JOHAB: 159cdf0e10cSrcweir bCJK = sal_True; 160cdf0e10cSrcweir break; 161cdf0e10cSrcweir default: 162cdf0e10cSrcweir break; 163cdf0e10cSrcweir } 164cdf0e10cSrcweir // #107889# in CJK versions ALL strings (even those that contain latin characters) 165cdf0e10cSrcweir // will get mnemonics in the form: xyz (M) 166cdf0e10cSrcweir // thus steps 1) and 2) are skipped for CJK locales 167cdf0e10cSrcweir 168cdf0e10cSrcweir // #110720#, avoid CJK-style mnemonics for latin-only strings that do not contain useful mnemonic chars 169cdf0e10cSrcweir if( bCJK ) 170cdf0e10cSrcweir { 171cdf0e10cSrcweir sal_Bool bLatinOnly = sal_True; 172cdf0e10cSrcweir sal_Bool bMnemonicIndexFound = sal_False; 173cdf0e10cSrcweir sal_Unicode c; 174cdf0e10cSrcweir xub_StrLen nIndex; 175cdf0e10cSrcweir 176cdf0e10cSrcweir for( nIndex=0; nIndex < nLen; nIndex++ ) 177cdf0e10cSrcweir { 178cdf0e10cSrcweir c = aKey.GetChar( nIndex ); 179cdf0e10cSrcweir if ( ((c >= 0x3000) && (c <= 0xD7FF)) || // cjk 180cdf0e10cSrcweir ((c >= 0xFF61) && (c <= 0xFFDC)) ) // halfwidth forms 181cdf0e10cSrcweir { 182cdf0e10cSrcweir bLatinOnly = sal_False; 183cdf0e10cSrcweir break; 184cdf0e10cSrcweir } 185cdf0e10cSrcweir if( ImplGetMnemonicIndex( c ) != MNEMONIC_INDEX_NOTFOUND ) 186cdf0e10cSrcweir bMnemonicIndexFound = sal_True; 187cdf0e10cSrcweir } 188cdf0e10cSrcweir if( bLatinOnly && !bMnemonicIndexFound ) 189cdf0e10cSrcweir return sal_False; 190cdf0e10cSrcweir } 191cdf0e10cSrcweir 192cdf0e10cSrcweir 193cdf0e10cSrcweir int nCJK = 0; 194cdf0e10cSrcweir sal_uInt16 nMnemonicIndex; 195cdf0e10cSrcweir sal_Unicode c; 196cdf0e10cSrcweir xub_StrLen nIndex = 0; 197cdf0e10cSrcweir if( !bCJK ) 198cdf0e10cSrcweir { 199cdf0e10cSrcweir // 1) first try the first character of a word 200cdf0e10cSrcweir do 201cdf0e10cSrcweir { 202cdf0e10cSrcweir c = aKey.GetChar( nIndex ); 203cdf0e10cSrcweir 204cdf0e10cSrcweir if ( nCJK != 2 ) 205cdf0e10cSrcweir { 206cdf0e10cSrcweir if ( ((c >= 0x3000) && (c <= 0xD7FF)) || // cjk 207cdf0e10cSrcweir ((c >= 0xFF61) && (c <= 0xFFDC)) ) // halfwidth forms 208cdf0e10cSrcweir nCJK = 1; 209cdf0e10cSrcweir else if ( ((c >= 0x0030) && (c <= 0x0039)) || // digits 210cdf0e10cSrcweir ((c >= 0x0041) && (c <= 0x005A)) || // latin capitals 211cdf0e10cSrcweir ((c >= 0x0061) && (c <= 0x007A)) || // latin small 212cdf0e10cSrcweir ((c >= 0x0370) && (c <= 0x037F)) || // greek numeral signs 213cdf0e10cSrcweir ((c >= 0x0400) && (c <= 0x04FF)) ) // cyrillic 214cdf0e10cSrcweir nCJK = 2; 215cdf0e10cSrcweir } 216cdf0e10cSrcweir 217cdf0e10cSrcweir nMnemonicIndex = ImplGetMnemonicIndex( c ); 218cdf0e10cSrcweir if ( nMnemonicIndex != MNEMONIC_INDEX_NOTFOUND ) 219cdf0e10cSrcweir { 220cdf0e10cSrcweir if ( maMnemonics[nMnemonicIndex] ) 221cdf0e10cSrcweir { 222cdf0e10cSrcweir maMnemonics[nMnemonicIndex] = 0; 223cdf0e10cSrcweir rKey.Insert( MNEMONIC_CHAR, nIndex ); 224cdf0e10cSrcweir bChanged = sal_True; 225cdf0e10cSrcweir break; 226cdf0e10cSrcweir } 227cdf0e10cSrcweir } 228cdf0e10cSrcweir 229cdf0e10cSrcweir // Search for next word 230cdf0e10cSrcweir do 231cdf0e10cSrcweir { 232cdf0e10cSrcweir nIndex++; 233cdf0e10cSrcweir c = aKey.GetChar( nIndex ); 234cdf0e10cSrcweir if ( c == ' ' ) 235cdf0e10cSrcweir break; 236cdf0e10cSrcweir } 237cdf0e10cSrcweir while ( nIndex < nLen ); 238cdf0e10cSrcweir nIndex++; 239cdf0e10cSrcweir } 240cdf0e10cSrcweir while ( nIndex < nLen ); 241cdf0e10cSrcweir 242cdf0e10cSrcweir // 2) search for a unique/uncommon character 243cdf0e10cSrcweir if ( !bChanged ) 244cdf0e10cSrcweir { 245cdf0e10cSrcweir sal_uInt16 nBestCount = 0xFFFF; 246cdf0e10cSrcweir sal_uInt16 nBestMnemonicIndex = 0; 247cdf0e10cSrcweir xub_StrLen nBestIndex = 0; 248cdf0e10cSrcweir nIndex = 0; 249cdf0e10cSrcweir do 250cdf0e10cSrcweir { 251cdf0e10cSrcweir c = aKey.GetChar( nIndex ); 252cdf0e10cSrcweir nMnemonicIndex = ImplGetMnemonicIndex( c ); 253cdf0e10cSrcweir if ( nMnemonicIndex != MNEMONIC_INDEX_NOTFOUND ) 254cdf0e10cSrcweir { 255cdf0e10cSrcweir if ( maMnemonics[nMnemonicIndex] ) 256cdf0e10cSrcweir { 257cdf0e10cSrcweir if ( maMnemonics[nMnemonicIndex] < nBestCount ) 258cdf0e10cSrcweir { 259cdf0e10cSrcweir nBestCount = maMnemonics[nMnemonicIndex]; 260cdf0e10cSrcweir nBestIndex = nIndex; 261cdf0e10cSrcweir nBestMnemonicIndex = nMnemonicIndex; 262cdf0e10cSrcweir if ( nBestCount == 2 ) 263cdf0e10cSrcweir break; 264cdf0e10cSrcweir } 265cdf0e10cSrcweir } 266cdf0e10cSrcweir } 267cdf0e10cSrcweir 268cdf0e10cSrcweir nIndex++; 269cdf0e10cSrcweir } 270cdf0e10cSrcweir while ( nIndex < nLen ); 271cdf0e10cSrcweir 272cdf0e10cSrcweir if ( nBestCount != 0xFFFF ) 273cdf0e10cSrcweir { 274cdf0e10cSrcweir maMnemonics[nBestMnemonicIndex] = 0; 275cdf0e10cSrcweir rKey.Insert( MNEMONIC_CHAR, nBestIndex ); 276cdf0e10cSrcweir bChanged = sal_True; 277cdf0e10cSrcweir } 278cdf0e10cSrcweir } 279cdf0e10cSrcweir } 280cdf0e10cSrcweir else 281cdf0e10cSrcweir nCJK = 1; 282cdf0e10cSrcweir 283cdf0e10cSrcweir // 3) Add English Mnemonic for CJK Text 284cdf0e10cSrcweir if ( !bChanged && (nCJK == 1) && rKey.Len() ) 285cdf0e10cSrcweir { 286cdf0e10cSrcweir // Append Ascii Mnemonic 287cdf0e10cSrcweir for ( c = MNEMONIC_RANGE_2_START; c <= MNEMONIC_RANGE_2_END; c++ ) 288cdf0e10cSrcweir { 289cdf0e10cSrcweir nMnemonicIndex = ImplGetMnemonicIndex( c ); 290cdf0e10cSrcweir if ( nMnemonicIndex != MNEMONIC_INDEX_NOTFOUND ) 291cdf0e10cSrcweir { 292cdf0e10cSrcweir if ( maMnemonics[nMnemonicIndex] ) 293cdf0e10cSrcweir { 294cdf0e10cSrcweir maMnemonics[nMnemonicIndex] = 0; 295cdf0e10cSrcweir UniString aStr( '(' ); 296cdf0e10cSrcweir aStr += MNEMONIC_CHAR; 297cdf0e10cSrcweir aStr += c; 298cdf0e10cSrcweir aStr += ')'; 299cdf0e10cSrcweir nIndex = rKey.Len(); 300cdf0e10cSrcweir if( nIndex >= 2 ) 301cdf0e10cSrcweir { 302cdf0e10cSrcweir static sal_Unicode cGreaterGreater[] = { 0xFF1E, 0xFF1E }; 303cdf0e10cSrcweir if ( rKey.EqualsAscii( ">>", nIndex-2, 2 ) || 304cdf0e10cSrcweir rKey.Equals( cGreaterGreater, nIndex-2, 2 ) ) 305cdf0e10cSrcweir nIndex -= 2; 306cdf0e10cSrcweir } 307cdf0e10cSrcweir if( nIndex >= 3 ) 308cdf0e10cSrcweir { 309cdf0e10cSrcweir static sal_Unicode cDotDotDot[] = { 0xFF0E, 0xFF0E, 0xFF0E }; 310cdf0e10cSrcweir if ( rKey.EqualsAscii( "...", nIndex-3, 3 ) || 311cdf0e10cSrcweir rKey.Equals( cDotDotDot, nIndex-3, 3 ) ) 312cdf0e10cSrcweir nIndex -= 3; 313cdf0e10cSrcweir } 314cdf0e10cSrcweir if( nIndex >= 1) 315cdf0e10cSrcweir { 316cdf0e10cSrcweir sal_Unicode cLastChar = rKey.GetChar( nIndex-1 ); 317cdf0e10cSrcweir if ( (cLastChar == ':') || (cLastChar == 0xFF1A) || 318cdf0e10cSrcweir (cLastChar == '.') || (cLastChar == 0xFF0E) || 319cdf0e10cSrcweir (cLastChar == '?') || (cLastChar == 0xFF1F) || 320cdf0e10cSrcweir (cLastChar == ' ') ) 321cdf0e10cSrcweir nIndex--; 322cdf0e10cSrcweir } 323cdf0e10cSrcweir rKey.Insert( aStr, nIndex ); 324cdf0e10cSrcweir bChanged = sal_True; 325cdf0e10cSrcweir break; 326cdf0e10cSrcweir } 327cdf0e10cSrcweir } 328cdf0e10cSrcweir } 329cdf0e10cSrcweir } 330cdf0e10cSrcweir 331cdf0e10cSrcweir // #i87415# Duplicates mnemonics are bad for consistent keyboard accessibility 332cdf0e10cSrcweir // It's probably better to not have mnemonics for some widgets, than to have ambiguous ones. 333cdf0e10cSrcweir // if( ! bChanged ) 334cdf0e10cSrcweir // { 335cdf0e10cSrcweir // /* 336cdf0e10cSrcweir // * #97809# if all else fails use the first character of a word 337cdf0e10cSrcweir // * anyway and live with duplicate mnemonics 338cdf0e10cSrcweir // */ 339cdf0e10cSrcweir // nIndex = 0; 340cdf0e10cSrcweir // do 341cdf0e10cSrcweir // { 342cdf0e10cSrcweir // c = aKey.GetChar( nIndex ); 343cdf0e10cSrcweir // 344cdf0e10cSrcweir // nMnemonicIndex = ImplGetMnemonicIndex( c ); 345cdf0e10cSrcweir // if ( nMnemonicIndex != MNEMONIC_INDEX_NOTFOUND ) 346cdf0e10cSrcweir // { 347cdf0e10cSrcweir // maMnemonics[nMnemonicIndex] = 0; 348cdf0e10cSrcweir // rKey.Insert( MNEMONIC_CHAR, nIndex ); 349cdf0e10cSrcweir // bChanged = sal_True; 350cdf0e10cSrcweir // break; 351cdf0e10cSrcweir // } 352cdf0e10cSrcweir // 353cdf0e10cSrcweir // // Search for next word 354cdf0e10cSrcweir // do 355cdf0e10cSrcweir // { 356cdf0e10cSrcweir // nIndex++; 357cdf0e10cSrcweir // c = aKey.GetChar( nIndex ); 358cdf0e10cSrcweir // if ( c == ' ' ) 359cdf0e10cSrcweir // break; 360cdf0e10cSrcweir // } 361cdf0e10cSrcweir // while ( nIndex < nLen ); 362cdf0e10cSrcweir // nIndex++; 363cdf0e10cSrcweir // } 364cdf0e10cSrcweir // while ( nIndex < nLen ); 365cdf0e10cSrcweir // } 366cdf0e10cSrcweir 367cdf0e10cSrcweir return bChanged; 368cdf0e10cSrcweir } 369cdf0e10cSrcweir 370cdf0e10cSrcweir // ----------------------------------------------------------------------- 371cdf0e10cSrcweir 372cdf0e10cSrcweir uno::Reference< i18n::XCharacterClassification > MnemonicGenerator::GetCharClass() 373cdf0e10cSrcweir { 374cdf0e10cSrcweir if ( !mxCharClass.is() ) 375cdf0e10cSrcweir mxCharClass = vcl::unohelper::CreateCharacterClassification(); 376cdf0e10cSrcweir return mxCharClass; 377cdf0e10cSrcweir } 378cdf0e10cSrcweir 379cdf0e10cSrcweir // ----------------------------------------------------------------------- 380cdf0e10cSrcweir 381cdf0e10cSrcweir String MnemonicGenerator::EraseAllMnemonicChars( const String& rStr ) 382cdf0e10cSrcweir { 383cdf0e10cSrcweir String aStr = rStr; 384cdf0e10cSrcweir xub_StrLen nLen = aStr.Len(); 385cdf0e10cSrcweir xub_StrLen i = 0; 386cdf0e10cSrcweir 387cdf0e10cSrcweir while ( i < nLen ) 388cdf0e10cSrcweir { 389cdf0e10cSrcweir if ( aStr.GetChar( i ) == '~' ) 390cdf0e10cSrcweir { 391cdf0e10cSrcweir // check for CJK-style mnemonic 392cdf0e10cSrcweir if( i > 0 && (i+2) < nLen ) 393cdf0e10cSrcweir { 394cdf0e10cSrcweir sal_Unicode c = aStr.GetChar(i+1); 395cdf0e10cSrcweir if( aStr.GetChar( i-1 ) == '(' && 396cdf0e10cSrcweir aStr.GetChar( i+2 ) == ')' && 397cdf0e10cSrcweir c >= MNEMONIC_RANGE_2_START && c <= MNEMONIC_RANGE_2_END ) 398cdf0e10cSrcweir { 399cdf0e10cSrcweir aStr.Erase( i-1, 4 ); 400cdf0e10cSrcweir nLen -= 4; 401cdf0e10cSrcweir i--; 402cdf0e10cSrcweir continue; 403cdf0e10cSrcweir } 404cdf0e10cSrcweir } 405cdf0e10cSrcweir 406cdf0e10cSrcweir // remove standard mnemonics 407cdf0e10cSrcweir aStr.Erase( i, 1 ); 408cdf0e10cSrcweir nLen--; 409cdf0e10cSrcweir } 410cdf0e10cSrcweir else 411cdf0e10cSrcweir i++; 412cdf0e10cSrcweir } 413cdf0e10cSrcweir 414cdf0e10cSrcweir return aStr; 415cdf0e10cSrcweir } 416