1 ///////////////////////////////////////////////////////////////////////////////
2 // Name: src/common/accelcmn.cpp
3 // Purpose: implementation of platform-independent wxAcceleratorEntry parts
4 // Author: Vadim Zeitlin
6 // Copyright: (c) 2007 Vadim Zeitlin <vadim@wxwindows.org>
7 // Licence: wxWindows licence
8 ///////////////////////////////////////////////////////////////////////////////
10 // ============================================================================
12 // ============================================================================
14 // ----------------------------------------------------------------------------
16 // ----------------------------------------------------------------------------
18 // for compilers that support precompilation, includes "wx.h".
19 #include "wx/wxprec.h"
29 #include "wx/string.h"
35 wxAcceleratorTable wxNullAcceleratorTable
;
37 // ============================================================================
38 // wxAcceleratorEntry implementation
39 // ============================================================================
41 static const struct wxKeyName
47 { WXK_DELETE
, wxTRANSLATE("DEL") },
48 { WXK_DELETE
, wxTRANSLATE("DELETE") },
49 { WXK_BACK
, wxTRANSLATE("BACK") },
50 { WXK_INSERT
, wxTRANSLATE("INS") },
51 { WXK_INSERT
, wxTRANSLATE("INSERT") },
52 { WXK_RETURN
, wxTRANSLATE("ENTER") },
53 { WXK_RETURN
, wxTRANSLATE("RETURN") },
54 { WXK_PAGEUP
, wxTRANSLATE("PGUP") },
55 { WXK_PAGEDOWN
, wxTRANSLATE("PGDN") },
56 { WXK_LEFT
, wxTRANSLATE("LEFT") },
57 { WXK_RIGHT
, wxTRANSLATE("RIGHT") },
58 { WXK_UP
, wxTRANSLATE("UP") },
59 { WXK_DOWN
, wxTRANSLATE("DOWN") },
60 { WXK_HOME
, wxTRANSLATE("HOME") },
61 { WXK_END
, wxTRANSLATE("END") },
62 { WXK_SPACE
, wxTRANSLATE("SPACE") },
63 { WXK_TAB
, wxTRANSLATE("TAB") },
64 { WXK_ESCAPE
, wxTRANSLATE("ESC") },
65 { WXK_ESCAPE
, wxTRANSLATE("ESCAPE") },
66 { WXK_CANCEL
, wxTRANSLATE("CANCEL") },
67 { WXK_CLEAR
, wxTRANSLATE("CLEAR") },
68 { WXK_MENU
, wxTRANSLATE("MENU") },
69 { WXK_PAUSE
, wxTRANSLATE("PAUSE") },
70 { WXK_CAPITAL
, wxTRANSLATE("CAPITAL") },
71 { WXK_SELECT
, wxTRANSLATE("SELECT") },
72 { WXK_PRINT
, wxTRANSLATE("PRINT") },
73 { WXK_EXECUTE
, wxTRANSLATE("EXECUTE") },
74 { WXK_SNAPSHOT
, wxTRANSLATE("SNAPSHOT") },
75 { WXK_HELP
, wxTRANSLATE("HELP") },
76 { WXK_ADD
, wxTRANSLATE("ADD") },
77 { WXK_SEPARATOR
, wxTRANSLATE("SEPARATOR") },
78 { WXK_SUBTRACT
, wxTRANSLATE("SUBTRACT") },
79 { WXK_DECIMAL
, wxTRANSLATE("DECIMAL") },
80 { WXK_DIVIDE
, wxTRANSLATE("DIVIDE") },
81 { WXK_NUMLOCK
, wxTRANSLATE("NUM_LOCK") },
82 { WXK_SCROLL
, wxTRANSLATE("SCROLL_LOCK") },
83 { WXK_PAGEUP
, wxTRANSLATE("PAGEUP") },
84 { WXK_PAGEDOWN
, wxTRANSLATE("PAGEDOWN") },
85 { WXK_NUMPAD_SPACE
, wxTRANSLATE("KP_SPACE") },
86 { WXK_NUMPAD_TAB
, wxTRANSLATE("KP_TAB") },
87 { WXK_NUMPAD_ENTER
, wxTRANSLATE("KP_ENTER") },
88 { WXK_NUMPAD_HOME
, wxTRANSLATE("KP_HOME") },
89 { WXK_NUMPAD_LEFT
, wxTRANSLATE("KP_LEFT") },
90 { WXK_NUMPAD_UP
, wxTRANSLATE("KP_UP") },
91 { WXK_NUMPAD_RIGHT
, wxTRANSLATE("KP_RIGHT") },
92 { WXK_NUMPAD_DOWN
, wxTRANSLATE("KP_DOWN") },
93 { WXK_NUMPAD_PAGEUP
, wxTRANSLATE("KP_PRIOR") },
94 { WXK_NUMPAD_PAGEUP
, wxTRANSLATE("KP_PAGEUP") },
95 { WXK_NUMPAD_PAGEDOWN
, wxTRANSLATE("KP_NEXT") },
96 { WXK_NUMPAD_PAGEDOWN
, wxTRANSLATE("KP_PAGEDOWN") },
97 { WXK_NUMPAD_END
, wxTRANSLATE("KP_END") },
98 { WXK_NUMPAD_BEGIN
, wxTRANSLATE("KP_BEGIN") },
99 { WXK_NUMPAD_INSERT
, wxTRANSLATE("KP_INSERT") },
100 { WXK_NUMPAD_DELETE
, wxTRANSLATE("KP_DELETE") },
101 { WXK_NUMPAD_EQUAL
, wxTRANSLATE("KP_EQUAL") },
102 { WXK_NUMPAD_MULTIPLY
, wxTRANSLATE("KP_MULTIPLY") },
103 { WXK_NUMPAD_ADD
, wxTRANSLATE("KP_ADD") },
104 { WXK_NUMPAD_SEPARATOR
, wxTRANSLATE("KP_SEPARATOR") },
105 { WXK_NUMPAD_SUBTRACT
, wxTRANSLATE("KP_SUBTRACT") },
106 { WXK_NUMPAD_DECIMAL
, wxTRANSLATE("KP_DECIMAL") },
107 { WXK_NUMPAD_DIVIDE
, wxTRANSLATE("KP_DIVIDE") },
108 { WXK_WINDOWS_LEFT
, wxTRANSLATE("WINDOWS_LEFT") },
109 { WXK_WINDOWS_RIGHT
, wxTRANSLATE("WINDOWS_RIGHT") },
110 { WXK_WINDOWS_MENU
, wxTRANSLATE("WINDOWS_MENU") },
111 { WXK_COMMAND
, wxTRANSLATE("COMMAND") },
114 // return true if the 2 strings refer to the same accel
116 // as accels can be either translated or not, check for both possibilities and
117 // also compare case-insensitively as the key names case doesn't count
118 static inline bool CompareAccelString(const wxString
& str
, const char *accel
)
120 return str
.CmpNoCase(accel
) == 0
122 || str
.CmpNoCase(wxGetTranslation(accel
)) == 0
127 // return prefixCode+number if the string is of the form "<prefix><number>" and
130 // first and last parameter specify the valid domain for "number" part
131 static int IsNumberedAccelKey(const wxString
& str
,
133 wxKeyCode prefixCode
,
137 const size_t lenPrefix
= wxStrlen(prefix
);
138 if ( !CompareAccelString(str
.Left(lenPrefix
), prefix
) )
142 if ( !str
.Mid(lenPrefix
).ToULong(&num
) )
145 if ( num
< first
|| num
> last
)
147 // this must be a mistake, chances that this is a valid name of another
148 // key are vanishingly small
149 wxLogDebug(wxT("Invalid key string \"%s\""), str
.c_str());
153 return prefixCode
+ num
- first
;
158 wxAcceleratorEntry::ParseAccel(const wxString
& text
, int *flagsOut
, int *keyOut
)
160 // the parser won't like trailing spaces
161 wxString label
= text
;
164 // For compatibility with the old wx versions which accepted (and actually
165 // even required) a TAB character in the string passed to this function we
166 // ignore anything up to the first TAB. Notice however that the correct
167 // input consists of just the accelerator itself and nothing else, this is
168 // done for compatibility and compatibility only.
169 int posTab
= label
.Find(wxT('\t'));
170 if ( posTab
== wxNOT_FOUND
)
175 // parse the accelerator string
176 int accelFlags
= wxACCEL_NORMAL
;
178 for ( size_t n
= (size_t)posTab
; n
< label
.length(); n
++ )
180 if ( (label
[n
] == '+') || (label
[n
] == '-') )
182 if ( CompareAccelString(current
, wxTRANSLATE("ctrl")) )
183 accelFlags
|= wxACCEL_CTRL
;
184 else if ( CompareAccelString(current
, wxTRANSLATE("alt")) )
185 accelFlags
|= wxACCEL_ALT
;
186 else if ( CompareAccelString(current
, wxTRANSLATE("shift")) )
187 accelFlags
|= wxACCEL_SHIFT
;
188 else if ( CompareAccelString(current
, wxTRANSLATE("rawctrl")) )
189 accelFlags
|= wxACCEL_RAW_CTRL
;
190 else // not a recognized modifier name
192 // we may have "Ctrl-+", for example, but we still want to
193 // catch typos like "Crtl-A" so only give the warning if we
194 // have something before the current '+' or '-', else take
195 // it as a literal symbol
196 if ( current
.empty() )
200 // skip clearing it below
205 wxLogDebug(wxT("Unknown accel modifier: '%s'"),
212 else // not special character
214 current
+= (wxChar
) wxTolower(label
[n
]);
219 const size_t len
= current
.length();
223 wxLogDebug(wxT("No accel key found, accel string ignored."));
227 // it's just a letter
228 keyCode
= current
[0U];
230 // if the key is used with any modifiers, make it an uppercase one
231 // because Ctrl-A and Ctrl-a are the same; but keep it as is if it's
232 // used alone as 'a' and 'A' are different
233 if ( accelFlags
!= wxACCEL_NORMAL
)
234 keyCode
= wxToupper(keyCode
);
238 keyCode
= IsNumberedAccelKey(current
, wxTRANSLATE("F"),
242 for ( size_t n
= 0; n
< WXSIZEOF(wxKeyNames
); n
++ )
244 const wxKeyName
& kn
= wxKeyNames
[n
];
245 if ( CompareAccelString(current
, kn
.name
) )
254 keyCode
= IsNumberedAccelKey(current
, wxTRANSLATE("KP_"),
257 keyCode
= IsNumberedAccelKey(current
, wxTRANSLATE("SPECIAL"),
258 WXK_SPECIAL1
, 1, 20);
262 wxLogDebug(wxT("Unrecognized accel key '%s', accel string ignored."),
269 wxASSERT_MSG( keyCode
, wxT("logic error: should have key code here") );
272 *flagsOut
= accelFlags
;
280 wxAcceleratorEntry
*wxAcceleratorEntry::Create(const wxString
& str
)
282 const wxString accelStr
= str
.AfterFirst('\t');
283 if ( accelStr
.empty() )
285 // It's ok to pass strings not containing any accelerators at all to
286 // this function, wxMenuItem code does it and we should just return
287 // NULL in this case.
293 if ( !ParseAccel(accelStr
, &flags
, &keyCode
) )
296 return new wxAcceleratorEntry(flags
, keyCode
);
299 bool wxAcceleratorEntry::FromString(const wxString
& str
)
301 return ParseAccel(str
, &m_flags
, &m_keyCode
);
307 wxString
PossiblyLocalize(const wxString
& str
, bool localize
)
309 return localize
? wxGetTranslation(str
) : str
;
314 wxString
wxAcceleratorEntry::AsPossiblyLocalizedString(bool localized
) const
318 int flags
= GetFlags();
319 if ( flags
& wxACCEL_ALT
)
320 text
+= PossiblyLocalize(wxTRANSLATE("Alt+"), localized
);
321 if ( flags
& wxACCEL_CTRL
)
322 text
+= PossiblyLocalize(wxTRANSLATE("Ctrl+"), localized
);
323 if ( flags
& wxACCEL_SHIFT
)
324 text
+= PossiblyLocalize(wxTRANSLATE("Shift+"), localized
);
325 #if defined(__WXMAC__) || defined(__WXCOCOA__)
326 if ( flags
& wxACCEL_RAW_CTRL
)
327 text
+= PossiblyLocalize(wxTRANSLATE("RawCtrl+"), localized
);
330 const int code
= GetKeyCode();
332 if ( code
>= WXK_F1
&& code
<= WXK_F12
)
333 text
<< PossiblyLocalize(wxTRANSLATE("F"), localized
)
334 << code
- WXK_F1
+ 1;
335 else if ( code
>= WXK_NUMPAD0
&& code
<= WXK_NUMPAD9
)
336 text
<< PossiblyLocalize(wxTRANSLATE("KP_"), localized
)
337 << code
- WXK_NUMPAD0
;
338 else if ( code
>= WXK_SPECIAL1
&& code
<= WXK_SPECIAL20
)
339 text
<< PossiblyLocalize(wxTRANSLATE("SPECIAL"), localized
)
340 << code
- WXK_SPECIAL1
+ 1;
341 else // check the named keys
344 for ( n
= 0; n
< WXSIZEOF(wxKeyNames
); n
++ )
346 const wxKeyName
& kn
= wxKeyNames
[n
];
347 if ( code
== kn
.code
)
349 text
<< PossiblyLocalize(kn
.name
, localized
);
354 if ( n
== WXSIZEOF(wxKeyNames
) )
356 // must be a simple key
359 // we can't call wxIsalnum() for non-ASCII characters in ASCII
360 // build as they're only defined for the ASCII range (or EOF)
365 text
<< (wxChar
)code
;
369 wxFAIL_MSG( wxT("unknown keyboard accelerator code") );
377 wxAcceleratorEntry
*wxGetAccelFromString(const wxString
& label
)
379 return wxAcceleratorEntry::Create(label
);
382 #endif // wxUSE_ACCEL