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
353 lines
11 KiB
C++
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
|
|
|
|
|
|
|