Files
wxWidgets/src/common/accelcmn.cpp
Vadim Zeitlin 7a0079d5a4 Add wxIsascii() function and use it instead of isascii() in our code.
isascii() is non-ANSI and is not available under all platforms. While we
currently define it ourselves in wx/wxcrtbase.h in this case, it's not a good
idea as this can't be easily done correctly for all platforms so start
transitioning away from using isascii() by adding wxIsascii() and using it in
our own code.

The only remaining occurrences of isascii() are in Scintilla code which we
probably don't want to modify.

git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@63165 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
2010-01-18 00:28:11 +00:00

353 lines
11 KiB
C++

///////////////////////////////////////////////////////////////////////////////
// Name: src/common/accelcmn.cpp
// Purpose: implementation of platform-independent wxAcceleratorEntry parts
// Author: Vadim Zeitlin
// Created: 2007-05-05
// RCS-ID: $Id$
// Copyright: (c) 2007 Vadim Zeitlin <vadim@wxwindows.org>
// Licence: wxWindows licence
///////////////////////////////////////////////////////////////////////////////
// ============================================================================
// declarations
// ============================================================================
// ----------------------------------------------------------------------------
// headers
// ----------------------------------------------------------------------------
// for compilers that support precompilation, includes "wx.h".
#include "wx/wxprec.h"
#ifdef __BORLANDC__
#pragma hdrstop
#endif
#if wxUSE_ACCEL
#ifndef WX_PRECOMP
#include "wx/string.h"
#include "wx/intl.h"
#include "wx/log.h"
#include "wx/accel.h"
#include "wx/crt.h"
#endif //WX_PRECOMP
// ============================================================================
// wxAcceleratorEntry implementation
// ============================================================================
static const struct wxKeyName
{
wxKeyCode code;
const char *name;
} wxKeyNames[] =
{
{ WXK_DELETE, wxTRANSLATE("DEL") },
{ WXK_DELETE, wxTRANSLATE("DELETE") },
{ WXK_BACK, wxTRANSLATE("BACK") },
{ WXK_INSERT, wxTRANSLATE("INS") },
{ WXK_INSERT, wxTRANSLATE("INSERT") },
{ WXK_RETURN, wxTRANSLATE("ENTER") },
{ WXK_RETURN, wxTRANSLATE("RETURN") },
{ WXK_PAGEUP, wxTRANSLATE("PGUP") },
{ WXK_PAGEDOWN, wxTRANSLATE("PGDN") },
{ WXK_LEFT, wxTRANSLATE("LEFT") },
{ WXK_RIGHT, wxTRANSLATE("RIGHT") },
{ WXK_UP, wxTRANSLATE("UP") },
{ WXK_DOWN, wxTRANSLATE("DOWN") },
{ WXK_HOME, wxTRANSLATE("HOME") },
{ WXK_END, wxTRANSLATE("END") },
{ WXK_SPACE, wxTRANSLATE("SPACE") },
{ WXK_TAB, wxTRANSLATE("TAB") },
{ WXK_ESCAPE, wxTRANSLATE("ESC") },
{ WXK_ESCAPE, wxTRANSLATE("ESCAPE") },
{ WXK_CANCEL, wxTRANSLATE("CANCEL") },
{ WXK_CLEAR, wxTRANSLATE("CLEAR") },
{ WXK_MENU, wxTRANSLATE("MENU") },
{ WXK_PAUSE, wxTRANSLATE("PAUSE") },
{ WXK_CAPITAL, wxTRANSLATE("CAPITAL") },
{ WXK_SELECT, wxTRANSLATE("SELECT") },
{ WXK_PRINT, wxTRANSLATE("PRINT") },
{ WXK_EXECUTE, wxTRANSLATE("EXECUTE") },
{ WXK_SNAPSHOT, wxTRANSLATE("SNAPSHOT") },
{ WXK_HELP, wxTRANSLATE("HELP") },
{ WXK_ADD, wxTRANSLATE("ADD") },
{ WXK_SEPARATOR, wxTRANSLATE("SEPARATOR") },
{ WXK_SUBTRACT, wxTRANSLATE("SUBTRACT") },
{ WXK_DECIMAL, wxTRANSLATE("DECIMAL") },
{ WXK_DIVIDE, wxTRANSLATE("DIVIDE") },
{ WXK_NUMLOCK, wxTRANSLATE("NUM_LOCK") },
{ WXK_SCROLL, wxTRANSLATE("SCROLL_LOCK") },
{ WXK_PAGEUP, wxTRANSLATE("PAGEUP") },
{ WXK_PAGEDOWN, wxTRANSLATE("PAGEDOWN") },
{ WXK_NUMPAD_SPACE, wxTRANSLATE("KP_SPACE") },
{ WXK_NUMPAD_TAB, wxTRANSLATE("KP_TAB") },
{ WXK_NUMPAD_ENTER, wxTRANSLATE("KP_ENTER") },
{ WXK_NUMPAD_HOME, wxTRANSLATE("KP_HOME") },
{ WXK_NUMPAD_LEFT, wxTRANSLATE("KP_LEFT") },
{ WXK_NUMPAD_UP, wxTRANSLATE("KP_UP") },
{ WXK_NUMPAD_RIGHT, wxTRANSLATE("KP_RIGHT") },
{ WXK_NUMPAD_DOWN, wxTRANSLATE("KP_DOWN") },
{ WXK_NUMPAD_PAGEUP, wxTRANSLATE("KP_PRIOR") },
{ WXK_NUMPAD_PAGEUP, wxTRANSLATE("KP_PAGEUP") },
{ WXK_NUMPAD_PAGEDOWN, wxTRANSLATE("KP_NEXT") },
{ WXK_NUMPAD_PAGEDOWN, wxTRANSLATE("KP_PAGEDOWN") },
{ WXK_NUMPAD_END, wxTRANSLATE("KP_END") },
{ WXK_NUMPAD_BEGIN, wxTRANSLATE("KP_BEGIN") },
{ WXK_NUMPAD_INSERT, wxTRANSLATE("KP_INSERT") },
{ WXK_NUMPAD_DELETE, wxTRANSLATE("KP_DELETE") },
{ WXK_NUMPAD_EQUAL, wxTRANSLATE("KP_EQUAL") },
{ WXK_NUMPAD_MULTIPLY, wxTRANSLATE("KP_MULTIPLY") },
{ WXK_NUMPAD_ADD, wxTRANSLATE("KP_ADD") },
{ WXK_NUMPAD_SEPARATOR, wxTRANSLATE("KP_SEPARATOR") },
{ WXK_NUMPAD_SUBTRACT, wxTRANSLATE("KP_SUBTRACT") },
{ WXK_NUMPAD_DECIMAL, wxTRANSLATE("KP_DECIMAL") },
{ WXK_NUMPAD_DIVIDE, wxTRANSLATE("KP_DIVIDE") },
{ WXK_WINDOWS_LEFT, wxTRANSLATE("WINDOWS_LEFT") },
{ WXK_WINDOWS_RIGHT, wxTRANSLATE("WINDOWS_RIGHT") },
{ WXK_WINDOWS_MENU, wxTRANSLATE("WINDOWS_MENU") },
{ WXK_COMMAND, wxTRANSLATE("COMMAND") },
};
// return true if the 2 strings refer to the same accel
//
// as accels can be either translated or not, check for both possibilities and
// also compare case-insensitively as the key names case doesn't count
static inline bool CompareAccelString(const wxString& str, const char *accel)
{
return str.CmpNoCase(accel) == 0
#if wxUSE_INTL
|| str.CmpNoCase(wxGetTranslation(accel)) == 0
#endif
;
}
// return prefixCode+number if the string is of the form "<prefix><number>" and
// 0 if it isn't
//
// first and last parameter specify the valid domain for "number" part
static int IsNumberedAccelKey(const wxString& str,
const char *prefix,
wxKeyCode prefixCode,
unsigned first,
unsigned last)
{
const size_t lenPrefix = wxStrlen(prefix);
if ( !CompareAccelString(str.Left(lenPrefix), prefix) )
return 0;
unsigned long num;
if ( !str.Mid(lenPrefix).ToULong(&num) )
return 0;
if ( num < first || num > last )
{
// this must be a mistake, chances that this is a valid name of another
// key are vanishingly small
wxLogDebug(wxT("Invalid key string \"%s\""), str.c_str());
return 0;
}
return prefixCode + num - first;
}
/* static */
bool
wxAcceleratorEntry::ParseAccel(const wxString& text, int *flagsOut, int *keyOut)
{
// the parser won't like trailing spaces
wxString label = text;
label.Trim(true); // the initial \t must be preserved so don't strip leading whitespaces
// check for accelerators: they are given after '\t'
int posTab = label.Find(wxT('\t'));
if ( posTab == wxNOT_FOUND )
{
return false;
}
// parse the accelerator string
int accelFlags = wxACCEL_NORMAL;
wxString current;
for ( size_t n = (size_t)posTab + 1; n < label.length(); n++ )
{
if ( (label[n] == '+') || (label[n] == '-') )
{
if ( CompareAccelString(current, wxTRANSLATE("ctrl")) )
accelFlags |= wxACCEL_CTRL;
else if ( CompareAccelString(current, wxTRANSLATE("alt")) )
accelFlags |= wxACCEL_ALT;
else if ( CompareAccelString(current, wxTRANSLATE("shift")) )
accelFlags |= wxACCEL_SHIFT;
else // not a recognized modifier name
{
// we may have "Ctrl-+", for example, but we still want to
// catch typos like "Crtl-A" so only give the warning if we
// have something before the current '+' or '-', else take
// it as a literal symbol
if ( current.empty() )
{
current += label[n];
// skip clearing it below
continue;
}
else
{
wxLogDebug(wxT("Unknown accel modifier: '%s'"),
current.c_str());
}
}
current.clear();
}
else // not special character
{
current += (wxChar) wxTolower(label[n]);
}
}
int keyCode;
const size_t len = current.length();
switch ( len )
{
case 0:
wxLogDebug(wxT("No accel key found, accel string ignored."));
return false;
case 1:
// it's just a letter
keyCode = current[0U];
// if the key is used with any modifiers, make it an uppercase one
// because Ctrl-A and Ctrl-a are the same; but keep it as is if it's
// used alone as 'a' and 'A' are different
if ( accelFlags != wxACCEL_NORMAL )
keyCode = wxToupper(keyCode);
break;
default:
keyCode = IsNumberedAccelKey(current, wxTRANSLATE("F"),
WXK_F1, 1, 12);
if ( !keyCode )
{
for ( size_t n = 0; n < WXSIZEOF(wxKeyNames); n++ )
{
const wxKeyName& kn = wxKeyNames[n];
if ( CompareAccelString(current, kn.name) )
{
keyCode = kn.code;
break;
}
}
}
if ( !keyCode )
keyCode = IsNumberedAccelKey(current, wxTRANSLATE("KP_"),
WXK_NUMPAD0, 0, 9);
if ( !keyCode )
keyCode = IsNumberedAccelKey(current, wxTRANSLATE("SPECIAL"),
WXK_SPECIAL1, 1, 20);
if ( !keyCode )
{
wxLogDebug(wxT("Unrecognized accel key '%s', accel string ignored."),
current.c_str());
return false;
}
}
wxASSERT_MSG( keyCode, wxT("logic error: should have key code here") );
if ( flagsOut )
*flagsOut = accelFlags;
if ( keyOut )
*keyOut = keyCode;
return true;
}
/* static */
wxAcceleratorEntry *wxAcceleratorEntry::Create(const wxString& str)
{
int flags,
keyCode;
if ( !ParseAccel(str, &flags, &keyCode) )
return NULL;
return new wxAcceleratorEntry(flags, keyCode);
}
bool wxAcceleratorEntry::FromString(const wxString& str)
{
return ParseAccel(str, &m_flags, &m_keyCode);
}
wxString wxAcceleratorEntry::ToString() const
{
wxString text;
int flags = GetFlags();
if ( flags & wxACCEL_ALT )
text += _("Alt-");
if ( flags & wxACCEL_CTRL )
text += _("Ctrl-");
if ( flags & wxACCEL_SHIFT )
text += _("Shift-");
const int code = GetKeyCode();
if ( code >= WXK_F1 && code <= WXK_F12 )
text << _("F") << code - WXK_F1 + 1;
else if ( code >= WXK_NUMPAD0 && code <= WXK_NUMPAD9 )
text << _("KP_") << code - WXK_NUMPAD0;
else if ( code >= WXK_SPECIAL1 && code <= WXK_SPECIAL20 )
text << _("SPECIAL") << code - WXK_SPECIAL1 + 1;
else // check the named keys
{
size_t n;
for ( n = 0; n < WXSIZEOF(wxKeyNames); n++ )
{
const wxKeyName& kn = wxKeyNames[n];
if ( code == kn.code )
{
text << wxGetTranslation(kn.name);
break;
}
}
if ( n == WXSIZEOF(wxKeyNames) )
{
// must be a simple key
if (
#if !wxUSE_UNICODE
// we can't call wxIsalnum() for non-ASCII characters in ASCII
// build as they're only defined for the ASCII range (or EOF)
wxIsascii(code) &&
#endif // ANSI
wxIsalnum(code) )
{
text << (wxChar)code;
}
else
{
wxFAIL_MSG( wxT("unknown keyboard accelerator code") );
}
}
}
return text;
}
wxAcceleratorEntry *wxGetAccelFromString(const wxString& label)
{
return wxAcceleratorEntry::Create(label);
}
#endif // wxUSE_ACCEL