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