mirror of
https://github.com/cookiengineer/audacity
synced 2025-06-25 16:48:44 +02:00
Fixes for bugs 1122 and 1113
Several other issues were also fixed (hopefully ;-)). This is a major change to accelerator handling and keyboard capturing. Menu shortcuts, non-menu commands, label editing, navigation, and basically anything else were you might use the keyboard should be thoroughly tested.
This commit is contained in:
parent
534741de78
commit
f36fe29f96
@ -754,9 +754,6 @@ typedef int (AudacityApp::*SPECIALKEYEVENT)(wxKeyEvent&);
|
|||||||
BEGIN_EVENT_TABLE(AudacityApp, wxApp)
|
BEGIN_EVENT_TABLE(AudacityApp, wxApp)
|
||||||
EVT_QUERY_END_SESSION(AudacityApp::OnEndSession)
|
EVT_QUERY_END_SESSION(AudacityApp::OnEndSession)
|
||||||
|
|
||||||
EVT_KEY_DOWN(AudacityApp::OnKeyDown)
|
|
||||||
EVT_CHAR(AudacityApp::OnChar)
|
|
||||||
EVT_KEY_UP(AudacityApp::OnKeyUp)
|
|
||||||
EVT_TIMER(kAudacityAppTimerID, AudacityApp::OnTimer)
|
EVT_TIMER(kAudacityAppTimerID, AudacityApp::OnTimer)
|
||||||
#ifdef __WXMAC__
|
#ifdef __WXMAC__
|
||||||
EVT_MENU(wxID_NEW, AudacityApp::OnMenuNew)
|
EVT_MENU(wxID_NEW, AudacityApp::OnMenuNew)
|
||||||
@ -1899,63 +1896,6 @@ void AudacityApp::OnEndSession(wxCloseEvent & event)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void AudacityApp::OnKeyDown(wxKeyEvent & event)
|
|
||||||
{
|
|
||||||
// Not handled
|
|
||||||
event.Skip(true);
|
|
||||||
|
|
||||||
// Make sure this event is destined for a project window
|
|
||||||
AudacityProject *prj = GetActiveProject();
|
|
||||||
|
|
||||||
// TODO: I don't know how it can happen, but it did on 2006-07-06.
|
|
||||||
// I was switching between apps fairly quickly so maybe that has something
|
|
||||||
// to do with it.
|
|
||||||
if (!prj)
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (prj->HandleKeyDown(event))
|
|
||||||
event.Skip(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
void AudacityApp::OnChar(wxKeyEvent & event)
|
|
||||||
{
|
|
||||||
// Not handled
|
|
||||||
event.Skip(true);
|
|
||||||
|
|
||||||
// Make sure this event is destined for a project window
|
|
||||||
AudacityProject *prj = GetActiveProject();
|
|
||||||
|
|
||||||
// TODO: I don't know how it can happen, but it did on 2006-07-06.
|
|
||||||
// I was switching between apps fairly quickly so maybe that has something
|
|
||||||
// to do with it.
|
|
||||||
if (!prj)
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (prj->HandleChar(event))
|
|
||||||
event.Skip(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
void AudacityApp::OnKeyUp(wxKeyEvent & event)
|
|
||||||
{
|
|
||||||
// Not handled
|
|
||||||
event.Skip(true);
|
|
||||||
|
|
||||||
// Make sure this event is destined for a project window
|
|
||||||
AudacityProject *prj = GetActiveProject();
|
|
||||||
|
|
||||||
// TODO: I don't know how it can happen, but it did on 2006-07-06.
|
|
||||||
// I was switching between apps fairly quickly so maybe that has something
|
|
||||||
// to do with it.
|
|
||||||
if (!prj)
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (prj != wxGetTopLevelParent(wxWindow::FindFocus()))
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (prj->HandleKeyUp(event))
|
|
||||||
event.Skip(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
void AudacityApp::AddFileToHistory(const wxString & name)
|
void AudacityApp::AddFileToHistory(const wxString & name)
|
||||||
{
|
{
|
||||||
mRecentFiles->AddFileToHistory(name);
|
mRecentFiles->AddFileToHistory(name);
|
||||||
|
@ -118,13 +118,6 @@ class AudacityApp:public wxApp {
|
|||||||
|
|
||||||
void OnEndSession(wxCloseEvent & event);
|
void OnEndSession(wxCloseEvent & event);
|
||||||
|
|
||||||
void OnKeyDown(wxKeyEvent & event);
|
|
||||||
void OnChar(wxKeyEvent & event);
|
|
||||||
void OnKeyUp(wxKeyEvent & event);
|
|
||||||
|
|
||||||
void OnCaptureKeyboard(wxCommandEvent & event);
|
|
||||||
void OnReleaseKeyboard(wxCommandEvent & event);
|
|
||||||
|
|
||||||
// Most Recently Used File support (for all platforms).
|
// Most Recently Used File support (for all platforms).
|
||||||
void OnMRUClear(wxCommandEvent &event);
|
void OnMRUClear(wxCommandEvent &event);
|
||||||
void OnMRUFile(wxCommandEvent &event);
|
void OnMRUFile(wxCommandEvent &event);
|
||||||
|
@ -1607,25 +1607,19 @@ bool LabelTrack::HandleMouse(const wxMouseEvent & evt,
|
|||||||
// Check for keys that we will process
|
// Check for keys that we will process
|
||||||
bool LabelTrack::CaptureKey(wxKeyEvent & event)
|
bool LabelTrack::CaptureKey(wxKeyEvent & event)
|
||||||
{
|
{
|
||||||
// Cache the keycode
|
// Check for modifiers and only allow shift
|
||||||
int keyCode = event.GetKeyCode();
|
int mods = event.GetModifiers();
|
||||||
|
if (mods != wxMOD_NONE && mods != wxMOD_SHIFT) {
|
||||||
// Check for modifiers -- this does what wxKeyEvent::HasModifiers() should
|
|
||||||
// do (it checks Control instead of CMD on Mac)
|
|
||||||
bool hasMods = ((event.GetModifiers() & (wxMOD_CMD | wxMOD_ALT)) != 0);
|
|
||||||
if (hasMods) {
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mSelIndex >= 0) {
|
if (mSelIndex >= 0) {
|
||||||
if (IsGoodLabelEditKey(keyCode)) {
|
if (IsGoodLabelEditKey(event)) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else {
|
||||||
{
|
if (IsGoodLabelFirstKey(event)) {
|
||||||
if (IsGoodLabelFirstKey(keyCode))
|
|
||||||
{
|
|
||||||
AudacityProject * pProj = GetActiveProject();
|
AudacityProject * pProj = GetActiveProject();
|
||||||
|
|
||||||
// If we're playing, don't capture if the selection is the same as the
|
// If we're playing, don't capture if the selection is the same as the
|
||||||
@ -1844,7 +1838,7 @@ bool LabelTrack::OnKeyDown(SelectedRegion &newSel, wxKeyEvent & event)
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
if (!IsGoodLabelEditKey(keyCode)) {
|
if (!IsGoodLabelEditKey(event)) {
|
||||||
event.Skip();
|
event.Skip();
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@ -1888,7 +1882,7 @@ bool LabelTrack::OnKeyDown(SelectedRegion &newSel, wxKeyEvent & event)
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
if (!IsGoodLabelFirstKey(keyCode)) {
|
if (!IsGoodLabelFirstKey(event)) {
|
||||||
event.Skip();
|
event.Skip();
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@ -1908,52 +1902,17 @@ bool LabelTrack::OnChar(SelectedRegion &WXUNUSED(newSel), wxKeyEvent & event)
|
|||||||
// Only track true changes to the label
|
// Only track true changes to the label
|
||||||
bool updated = false;
|
bool updated = false;
|
||||||
|
|
||||||
// Cache the keycode
|
// Cache the character
|
||||||
int keyCode = event.GetKeyCode();
|
wxChar charCode = event.GetUnicodeKey();
|
||||||
wxChar charCode = keyCode;
|
if (charCode == 0) {
|
||||||
#if wxUSE_UNICODE
|
|
||||||
charCode = event.GetUnicodeKey();
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// We still have some filtering to do. Character events can be generated for,
|
|
||||||
// i.e., the F keys, and if they aren't handled in OnKeyDown() or in the
|
|
||||||
// command manager we get them here.
|
|
||||||
|
|
||||||
// AWD: the following behavior is not really documented (I figured it out by
|
|
||||||
// entering lots of Unicode characters on various OSes), and it's possible
|
|
||||||
// that different versions of wxWidgets act differently. It's unfortunately
|
|
||||||
// the only way I can find to allow input of full Unicode ranges without
|
|
||||||
// breaking other stuff (Audacity's command manager, keyboard menu
|
|
||||||
// navigation, Windows' Alt-+-xxxx arbitrary Unicode entry, etc.)
|
|
||||||
bool bogusChar =
|
|
||||||
#if defined(__WXMSW__) && wxUSE_UNICODE
|
|
||||||
// In Windows Unicode builds, these have keyCode not matching charCode
|
|
||||||
(keyCode != (int)charCode) ||
|
|
||||||
#else
|
|
||||||
// In Windows non-unicode, GTK+, and Mac builds the keyCode comes in the
|
|
||||||
// WXK_* range
|
|
||||||
(keyCode >= WXK_START && keyCode <= WXK_COMMAND) ||
|
|
||||||
#endif
|
|
||||||
// Avoid modified characters, but allow Alt (option) on Mac because
|
|
||||||
// several legit characters come in with it set.
|
|
||||||
(event.CmdDown()) ||
|
|
||||||
#if !defined(__WXMAC__)
|
|
||||||
(event.AltDown()) ||
|
|
||||||
#endif
|
|
||||||
// Avoid control characters on all platforms; Casting to wxUChar to avoid
|
|
||||||
// assertions in Windows non-Unicode builds...
|
|
||||||
(wxIscntrl((wxUChar)charCode));
|
|
||||||
|
|
||||||
if (bogusChar) {
|
|
||||||
event.Skip();
|
event.Skip();
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// If we've reached this point and aren't currently editing, add new label
|
// If we've reached this point and aren't currently editing, add new label
|
||||||
if (mSelIndex < 0) {
|
if (mSelIndex < 0) {
|
||||||
// Don't create a new label for a space
|
// Don't create a new label for a space
|
||||||
if (wxIsspace((wxUChar)charCode)) {
|
if (wxIsspace(charCode)) {
|
||||||
event.Skip();
|
event.Skip();
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -2799,10 +2758,9 @@ void LabelTrack::CreateCustomGlyphs()
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Returns true for keys we capture to start a label.
|
/// Returns true for keys we capture to start a label.
|
||||||
bool LabelTrack::IsGoodLabelFirstKey(int keyCode)
|
bool LabelTrack::IsGoodLabelFirstKey(const wxKeyEvent & evt)
|
||||||
{
|
{
|
||||||
// Allow everything before WXK_START except space, return and delete, the numpad keys
|
int keyCode = evt.GetKeyCode();
|
||||||
// when numlock is on, and everything after WXK_COMMAND
|
|
||||||
return (keyCode < WXK_START
|
return (keyCode < WXK_START
|
||||||
&& keyCode != WXK_SPACE && keyCode != WXK_DELETE && keyCode != WXK_RETURN) ||
|
&& keyCode != WXK_SPACE && keyCode != WXK_DELETE && keyCode != WXK_RETURN) ||
|
||||||
(keyCode >= WXK_NUMPAD0 && keyCode <= WXK_DIVIDE) ||
|
(keyCode >= WXK_NUMPAD0 && keyCode <= WXK_DIVIDE) ||
|
||||||
@ -2814,8 +2772,10 @@ bool LabelTrack::IsGoodLabelFirstKey(int keyCode)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// This returns true for keys we capture for label editing.
|
/// This returns true for keys we capture for label editing.
|
||||||
bool LabelTrack::IsGoodLabelEditKey(int keyCode)
|
bool LabelTrack::IsGoodLabelEditKey(const wxKeyEvent & evt)
|
||||||
{
|
{
|
||||||
|
int keyCode = evt.GetKeyCode();
|
||||||
|
|
||||||
// Accept everything outside of WXK_START through WXK_COMMAND, plus the keys
|
// Accept everything outside of WXK_START through WXK_COMMAND, plus the keys
|
||||||
// within that range that are usually printable, plus the ones we use for
|
// within that range that are usually printable, plus the ones we use for
|
||||||
// keyboard navigation.
|
// keyboard navigation.
|
||||||
|
@ -113,8 +113,8 @@ class AUDACITY_DLL_API LabelTrack : public Track
|
|||||||
friend class LabelStruct;
|
friend class LabelStruct;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
bool IsGoodLabelFirstKey(int keyCode);
|
bool IsGoodLabelFirstKey(const wxKeyEvent & evt);
|
||||||
bool IsGoodLabelEditKey(int keyCode);
|
bool IsGoodLabelEditKey(const wxKeyEvent & evt);
|
||||||
bool IsTextSelected();
|
bool IsTextSelected();
|
||||||
|
|
||||||
void CreateCustomGlyphs();
|
void CreateCustomGlyphs();
|
||||||
|
@ -1867,16 +1867,9 @@ void AudacityProject::OnScroll(wxScrollEvent & WXUNUSED(event))
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Called from the CommandMananger
|
||||||
bool AudacityProject::HandleKeyDown(wxKeyEvent & event)
|
bool AudacityProject::HandleKeyDown(wxKeyEvent & event)
|
||||||
{
|
{
|
||||||
// Check to see if it is a meta command
|
|
||||||
if (mCommandManager.HandleMeta(event))
|
|
||||||
return true;
|
|
||||||
|
|
||||||
// Any other keypresses must be destined for this project window.
|
|
||||||
if (wxGetTopLevelParent(wxWindow::FindFocus()) != this)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
if (event.GetKeyCode() == WXK_ESCAPE)
|
if (event.GetKeyCode() == WXK_ESCAPE)
|
||||||
mTrackPanel->HandleEscapeKey(true);
|
mTrackPanel->HandleEscapeKey(true);
|
||||||
|
|
||||||
@ -1898,20 +1891,12 @@ bool AudacityProject::HandleKeyDown(wxKeyEvent & event)
|
|||||||
if (event.GetKeyCode() == WXK_PAGEDOWN)
|
if (event.GetKeyCode() == WXK_PAGEDOWN)
|
||||||
mTrackPanel->HandlePageDownKey();
|
mTrackPanel->HandlePageDownKey();
|
||||||
|
|
||||||
return mCommandManager.HandleKey(event, GetUpdateFlags(), 0xFFFFFFFF);
|
return true;
|
||||||
}
|
|
||||||
|
|
||||||
bool AudacityProject::HandleChar(wxKeyEvent & WXUNUSED(event))
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Called from the CommandMananger
|
||||||
bool AudacityProject::HandleKeyUp(wxKeyEvent & event)
|
bool AudacityProject::HandleKeyUp(wxKeyEvent & event)
|
||||||
{
|
{
|
||||||
// All keypresses must be destined for this project window.
|
|
||||||
if (wxGetTopLevelParent(wxWindow::FindFocus()) != this)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
if (event.GetKeyCode() == WXK_ESCAPE)
|
if (event.GetKeyCode() == WXK_ESCAPE)
|
||||||
mTrackPanel->HandleEscapeKey(false);
|
mTrackPanel->HandleEscapeKey(false);
|
||||||
|
|
||||||
@ -1925,7 +1910,7 @@ bool AudacityProject::HandleKeyUp(wxKeyEvent & event)
|
|||||||
if (event.GetKeyCode() == WXK_CONTROL)
|
if (event.GetKeyCode() == WXK_CONTROL)
|
||||||
mTrackPanel->HandleControlKey(false);
|
mTrackPanel->HandleControlKey(false);
|
||||||
|
|
||||||
return mCommandManager.HandleKey(event, GetUpdateFlags(), 0xFFFFFFFF);
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Determines if flags for command are compatible with current state.
|
/// Determines if flags for command are compatible with current state.
|
||||||
|
@ -298,8 +298,8 @@ class AUDACITY_DLL_API AudacityProject: public wxFrame,
|
|||||||
void OnODTaskUpdate(wxCommandEvent & event);
|
void OnODTaskUpdate(wxCommandEvent & event);
|
||||||
void OnODTaskComplete(wxCommandEvent & event);
|
void OnODTaskComplete(wxCommandEvent & event);
|
||||||
void OnTrackListUpdated(wxCommandEvent & event);
|
void OnTrackListUpdated(wxCommandEvent & event);
|
||||||
|
|
||||||
bool HandleKeyDown(wxKeyEvent & event);
|
bool HandleKeyDown(wxKeyEvent & event);
|
||||||
bool HandleChar(wxKeyEvent & event);
|
|
||||||
bool HandleKeyUp(wxKeyEvent & event);
|
bool HandleKeyUp(wxKeyEvent & event);
|
||||||
|
|
||||||
void HandleResize();
|
void HandleResize();
|
||||||
@ -661,6 +661,9 @@ class AUDACITY_DLL_API AudacityProject: public wxFrame,
|
|||||||
// Keyboard capture
|
// Keyboard capture
|
||||||
wxWindow *mKeyboardCaptureHandler;
|
wxWindow *mKeyboardCaptureHandler;
|
||||||
|
|
||||||
|
// CommandManager needs to use private methods
|
||||||
|
friend class CommandManager;
|
||||||
|
|
||||||
DECLARE_EVENT_TABLE()
|
DECLARE_EVENT_TABLE()
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -111,6 +111,8 @@ CommandManager. It holds the callback for one command.
|
|||||||
#if defined(__WXMAC__)
|
#if defined(__WXMAC__)
|
||||||
#include <AppKit/AppKit.h>
|
#include <AppKit/AppKit.h>
|
||||||
#include <wx/osx/private.h>
|
#include <wx/osx/private.h>
|
||||||
|
#elif defined(__WXGTK__)
|
||||||
|
#include <gtk/gtk.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Shared by all projects
|
// Shared by all projects
|
||||||
@ -134,6 +136,8 @@ public:
|
|||||||
wxWidgetImpl::FindFromWXWidget(widget);
|
wxWidgetImpl::FindFromWXWidget(widget);
|
||||||
if (impl)
|
if (impl)
|
||||||
{
|
{
|
||||||
|
mEvent = event;
|
||||||
|
|
||||||
wxKeyEvent wxevent(wxEVT_KEY_DOWN);
|
wxKeyEvent wxevent(wxEVT_KEY_DOWN);
|
||||||
impl->SetupKeyEvent(wxevent, event);
|
impl->SetupKeyEvent(wxevent, event);
|
||||||
|
|
||||||
@ -161,34 +165,64 @@ public:
|
|||||||
|
|
||||||
int FilterEvent(wxEvent& event)
|
int FilterEvent(wxEvent& event)
|
||||||
{
|
{
|
||||||
AudacityProject *project = GetActiveProject();
|
|
||||||
if (!project)
|
|
||||||
{
|
|
||||||
return Event_Skip;
|
|
||||||
}
|
|
||||||
|
|
||||||
wxEvtHandler *handler = project->GetKeyboardCaptureHandler();
|
|
||||||
if (!handler)
|
|
||||||
{
|
|
||||||
return Event_Skip;
|
|
||||||
}
|
|
||||||
|
|
||||||
wxEventType type = event.GetEventType();
|
wxEventType type = event.GetEventType();
|
||||||
if (type != wxEVT_CHAR_HOOK)
|
if (type != wxEVT_CHAR_HOOK)
|
||||||
{
|
{
|
||||||
return Event_Skip;
|
return Event_Skip;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
AudacityProject *project = GetActiveProject();
|
||||||
|
if (!project)
|
||||||
|
{
|
||||||
|
return Event_Skip;
|
||||||
|
}
|
||||||
|
|
||||||
|
wxWindow *handler = project->GetKeyboardCaptureHandler();
|
||||||
|
if (handler && HandleCapture(handler, (wxKeyEvent &) event))
|
||||||
|
{
|
||||||
|
return Event_Processed;
|
||||||
|
}
|
||||||
|
|
||||||
|
CommandManager *manager = project->GetCommandManager();
|
||||||
|
if (manager && manager->FilterKeyEvent(project, (wxKeyEvent &) event))
|
||||||
|
{
|
||||||
|
return Event_Processed;
|
||||||
|
}
|
||||||
|
|
||||||
|
return Event_Skip;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
// Returns true if the event was captured and processed
|
||||||
|
bool HandleCapture(wxWindow *target, wxKeyEvent & event)
|
||||||
|
{
|
||||||
|
if (wxGetTopLevelParent(target) != wxGetTopLevelParent(wxWindow::FindFocus()))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
wxEvtHandler *handler = target->GetEventHandler();
|
||||||
|
|
||||||
wxKeyEvent temp = (wxKeyEvent &) event;
|
wxKeyEvent temp = (wxKeyEvent &) event;
|
||||||
temp.SetEventType(wxEVT_KEY_DOWN);
|
temp.SetEventType(wxEVT_KEY_DOWN);
|
||||||
|
|
||||||
|
#if defined(__WXGTK__)
|
||||||
|
// wxGTK uses the control and alt modifiers to represent ALTGR,
|
||||||
|
// so remove it as it might confuse the capture handlers.
|
||||||
|
if (temp.GetModifiers() == (wxMOD_CONTROL | wxMOD_ALT))
|
||||||
|
{
|
||||||
|
temp.SetControlDown(false);
|
||||||
|
temp.SetAltDown(false);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
wxCommandEvent e(EVT_CAPTURE_KEY);
|
wxCommandEvent e(EVT_CAPTURE_KEY);
|
||||||
e.SetEventObject(&temp);
|
e.SetEventObject(&temp);
|
||||||
e.StopPropagation();
|
e.StopPropagation();
|
||||||
|
|
||||||
if (!handler->ProcessEvent(e))
|
if (!handler->ProcessEvent(e))
|
||||||
{
|
{
|
||||||
return Event_Skip;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
temp.WasProcessed();
|
temp.WasProcessed();
|
||||||
@ -196,43 +230,19 @@ public:
|
|||||||
wxEventProcessInHandlerOnly onlyDown(temp, handler);
|
wxEventProcessInHandlerOnly onlyDown(temp, handler);
|
||||||
if (!handler->ProcessEvent(temp))
|
if (!handler->ProcessEvent(temp))
|
||||||
{
|
{
|
||||||
return Event_Skip;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
int keyCode = temp.GetKeyCode();
|
wxString chars = GetUnicodeString(temp);
|
||||||
switch (keyCode)
|
for (size_t i = 0, cnt = chars.Length(); i < cnt; i++)
|
||||||
{
|
{
|
||||||
case WXK_SHIFT:
|
|
||||||
case WXK_CONTROL:
|
|
||||||
case WXK_MENU:
|
|
||||||
case WXK_CAPITAL:
|
|
||||||
case WXK_NUMLOCK:
|
|
||||||
case WXK_SCROLL:
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
temp = (wxKeyEvent &) event;
|
temp = (wxKeyEvent &) event;
|
||||||
temp.SetEventType(wxEVT_CHAR);
|
temp.SetEventType(wxEVT_CHAR);
|
||||||
|
|
||||||
if (!temp.ShiftDown())
|
|
||||||
{
|
|
||||||
if (wxIsascii(temp.m_keyCode))
|
|
||||||
{
|
|
||||||
temp.m_keyCode = wxTolower(temp.m_keyCode);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (temp.m_keyCode < WXK_START)
|
|
||||||
{
|
|
||||||
temp.m_uniChar = wxTolower(temp.m_uniChar);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
temp.WasProcessed();
|
temp.WasProcessed();
|
||||||
temp.StopPropagation();
|
temp.StopPropagation();
|
||||||
|
temp.m_uniChar = chars[i];
|
||||||
wxEventProcessInHandlerOnly onlyChar(temp, handler);
|
wxEventProcessInHandlerOnly onlyChar(temp, handler);
|
||||||
handler->ProcessEvent(temp);
|
handler->ProcessEvent(temp);
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
temp = (wxKeyEvent &) event;
|
temp = (wxKeyEvent &) event;
|
||||||
@ -242,13 +252,97 @@ public:
|
|||||||
wxEventProcessInHandlerOnly onlyUp(temp, handler);
|
wxEventProcessInHandlerOnly onlyUp(temp, handler);
|
||||||
handler->ProcessEvent(temp);
|
handler->ProcessEvent(temp);
|
||||||
|
|
||||||
return Event_Processed;
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
wxString GetUnicodeString(const wxKeyEvent & event)
|
||||||
|
{
|
||||||
|
wxString chars;
|
||||||
|
|
||||||
|
#if defined(__WXMSW__)
|
||||||
|
|
||||||
|
BYTE ks[256];
|
||||||
|
GetKeyboardState(ks);
|
||||||
|
WCHAR ucode[256];
|
||||||
|
int res = ToUnicode(event.GetRawKeyCode(), 0, ks, ucode, 256, 0);
|
||||||
|
if (res >= 1)
|
||||||
|
{
|
||||||
|
chars.Append(ucode, res);
|
||||||
|
}
|
||||||
|
|
||||||
|
#elif defined(__WXGTK__)
|
||||||
|
|
||||||
|
chars.Append((wxChar) gdk_keyval_to_unicode(event.GetRawKeyCode()));
|
||||||
|
|
||||||
|
#elif defined(__WXMAC__)
|
||||||
|
|
||||||
|
NSString *c = [mEvent charactersIgnoringModifiers];
|
||||||
|
if ([c length] == 1)
|
||||||
|
{
|
||||||
|
unichar codepoint = [c characterAtIndex:0];
|
||||||
|
if ((codepoint >= 0xF700 && codepoint <= 0xF8FF) || codepoint == 0x7F)
|
||||||
|
{
|
||||||
|
return chars;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
c = [mEvent characters];
|
||||||
|
chars = [c UTF8String];
|
||||||
|
|
||||||
|
TISInputSourceRef currentKeyboard = TISCopyCurrentKeyboardInputSource();
|
||||||
|
CFDataRef uchr = (CFDataRef)TISGetInputSourceProperty(currentKeyboard, kTISPropertyUnicodeKeyLayoutData);
|
||||||
|
CFRelease(currentKeyboard);
|
||||||
|
if (uchr == NULL)
|
||||||
|
{
|
||||||
|
return chars;
|
||||||
|
}
|
||||||
|
|
||||||
|
const UCKeyboardLayout *keyboardLayout = (const UCKeyboardLayout*)CFDataGetBytePtr(uchr);
|
||||||
|
if (keyboardLayout == NULL)
|
||||||
|
{
|
||||||
|
return chars;
|
||||||
|
}
|
||||||
|
|
||||||
|
const UniCharCount maxStringLength = 255;
|
||||||
|
UniCharCount actualStringLength = 0;
|
||||||
|
UniChar unicodeString[maxStringLength];
|
||||||
|
UInt32 nsflags = [mEvent modifierFlags];
|
||||||
|
UInt16 modifiers = (nsflags & NSAlphaShiftKeyMask ? alphaLock : 0) |
|
||||||
|
(nsflags & NSShiftKeyMask ? shiftKey : 0) |
|
||||||
|
(nsflags & NSControlKeyMask ? controlKey : 0) |
|
||||||
|
(nsflags & NSAlternateKeyMask ? optionKey : 0) |
|
||||||
|
(nsflags & NSCommandKeyMask ? cmdKey : 0);
|
||||||
|
|
||||||
|
OSStatus status = UCKeyTranslate(keyboardLayout,
|
||||||
|
[mEvent keyCode],
|
||||||
|
kUCKeyActionDown,
|
||||||
|
(modifiers >> 8) & 0xff,
|
||||||
|
LMGetKbdType(),
|
||||||
|
0,
|
||||||
|
&mDeadKeyState,
|
||||||
|
maxStringLength,
|
||||||
|
&actualStringLength,
|
||||||
|
unicodeString);
|
||||||
|
|
||||||
|
if (status != noErr)
|
||||||
|
{
|
||||||
|
return chars;
|
||||||
|
}
|
||||||
|
|
||||||
|
chars = [[NSString stringWithCharacters:unicodeString
|
||||||
|
length:(NSInteger)actualStringLength] UTF8String];
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return chars;
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
#if defined(__WXMAC__)
|
#if defined(__WXMAC__)
|
||||||
id mHandler;
|
id mHandler;
|
||||||
|
NSEvent *mEvent;
|
||||||
|
UInt32 mDeadKeyState;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
} monitor;
|
} monitor;
|
||||||
@ -336,7 +430,7 @@ wxMenuBar *CommandManager::AddMenuBar(wxString sMenu)
|
|||||||
///
|
///
|
||||||
/// Retrieves the menubar based on the name given in AddMenuBar(name)
|
/// Retrieves the menubar based on the name given in AddMenuBar(name)
|
||||||
///
|
///
|
||||||
wxMenuBar * CommandManager::GetMenuBar(wxString sMenu)
|
wxMenuBar * CommandManager::GetMenuBar(wxString sMenu) const
|
||||||
{
|
{
|
||||||
for(unsigned int i = 0; i < mMenuBarList.GetCount(); i++)
|
for(unsigned int i = 0; i < mMenuBarList.GetCount(); i++)
|
||||||
{
|
{
|
||||||
@ -351,7 +445,7 @@ wxMenuBar * CommandManager::GetMenuBar(wxString sMenu)
|
|||||||
///
|
///
|
||||||
/// Retrieve the 'current' menubar; either NULL or the
|
/// Retrieve the 'current' menubar; either NULL or the
|
||||||
/// last on in the mMenuBarList.
|
/// last on in the mMenuBarList.
|
||||||
wxMenuBar * CommandManager::CurrentMenuBar()
|
wxMenuBar * CommandManager::CurrentMenuBar() const
|
||||||
{
|
{
|
||||||
if(mMenuBarList.IsEmpty())
|
if(mMenuBarList.IsEmpty())
|
||||||
return NULL;
|
return NULL;
|
||||||
@ -433,7 +527,7 @@ void CommandManager::EndSubMenu()
|
|||||||
///
|
///
|
||||||
/// This returns the 'Current' Submenu, which is the one at the
|
/// This returns the 'Current' Submenu, which is the one at the
|
||||||
/// end of the mSubMenuList (or NULL, if it doesn't exist).
|
/// end of the mSubMenuList (or NULL, if it doesn't exist).
|
||||||
wxMenu * CommandManager::CurrentSubMenu()
|
wxMenu * CommandManager::CurrentSubMenu() const
|
||||||
{
|
{
|
||||||
if(mSubMenuList.IsEmpty())
|
if(mSubMenuList.IsEmpty())
|
||||||
return NULL;
|
return NULL;
|
||||||
@ -445,7 +539,7 @@ wxMenu * CommandManager::CurrentSubMenu()
|
|||||||
/// This returns the current menu that we're appending to - note that
|
/// This returns the current menu that we're appending to - note that
|
||||||
/// it could be a submenu if BeginSubMenu was called and we haven't
|
/// it could be a submenu if BeginSubMenu was called and we haven't
|
||||||
/// reached EndSubMenu yet.
|
/// reached EndSubMenu yet.
|
||||||
wxMenu * CommandManager::CurrentMenu()
|
wxMenu * CommandManager::CurrentMenu() const
|
||||||
{
|
{
|
||||||
if(!mCurrentMenu)
|
if(!mCurrentMenu)
|
||||||
return NULL;
|
return NULL;
|
||||||
@ -515,7 +609,9 @@ void CommandManager::InsertItem(wxString name, wxString label_in,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int ID = NewIdentifier(name, label, menu, callback, false, 0, 0);
|
CommandListEntry *entry = NewIdentifier(name, label, menu, callback, false, 0, 0);
|
||||||
|
int ID = entry->id;
|
||||||
|
label = GetLabel(entry);
|
||||||
|
|
||||||
if (checkmark >= 0) {
|
if (checkmark >= 0) {
|
||||||
menu->InsertCheckItem(pos, ID, label);
|
menu->InsertCheckItem(pos, ID, label);
|
||||||
@ -528,6 +624,8 @@ void CommandManager::InsertItem(wxString name, wxString label_in,
|
|||||||
mbSeparatorAllowed = true;
|
mbSeparatorAllowed = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void CommandManager::AddCheck(const wxChar *name,
|
void CommandManager::AddCheck(const wxChar *name,
|
||||||
const wxChar *label,
|
const wxChar *label,
|
||||||
CommandFunctor *callback,
|
CommandFunctor *callback,
|
||||||
@ -563,16 +661,15 @@ void CommandManager::AddItem(const wxChar *name,
|
|||||||
unsigned int mask,
|
unsigned int mask,
|
||||||
int checkmark)
|
int checkmark)
|
||||||
{
|
{
|
||||||
wxString label(label_in);
|
CommandListEntry *entry = NewIdentifier(name, label_in, accel, CurrentMenu(), callback, false, 0, 0);
|
||||||
label += wxT("\t");
|
int ID = entry->id;
|
||||||
label += accel ? accel : wxEmptyString;
|
wxString label = GetLabel(entry);
|
||||||
|
|
||||||
int ID = NewIdentifier(name, label, CurrentMenu(), callback, false, 0, 0);
|
|
||||||
|
|
||||||
if (flags != NoFlagsSpecifed || mask != NoFlagsSpecifed) {
|
if (flags != NoFlagsSpecifed || mask != NoFlagsSpecifed) {
|
||||||
SetCommandFlags(name, flags, mask);
|
SetCommandFlags(name, flags, mask);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
if (checkmark >= 0) {
|
if (checkmark >= 0) {
|
||||||
CurrentMenu()->AppendCheckItem(ID, label);
|
CurrentMenu()->AppendCheckItem(ID, label);
|
||||||
CurrentMenu()->Check(ID, checkmark != 0);
|
CurrentMenu()->Check(ID, checkmark != 0);
|
||||||
@ -593,17 +690,15 @@ void CommandManager::AddItem(const wxChar *name,
|
|||||||
void CommandManager::AddItemList(wxString name, wxArrayString labels,
|
void CommandManager::AddItemList(wxString name, wxArrayString labels,
|
||||||
CommandFunctor *callback)
|
CommandFunctor *callback)
|
||||||
{
|
{
|
||||||
unsigned int i;
|
for (size_t i = 0, cnt = labels.GetCount(); i < cnt; i++) {
|
||||||
|
CommandListEntry *entry = NewIdentifier(name,
|
||||||
unsigned int effLen = labels.GetCount();
|
labels[i],
|
||||||
|
CurrentMenu(),
|
||||||
wxString label;
|
callback,
|
||||||
int tmpmax;
|
true,
|
||||||
|
i,
|
||||||
for(i=0; i<effLen; i++) {
|
cnt);
|
||||||
int ID = NewIdentifier(name, labels[i], CurrentMenu(), callback,
|
CurrentMenu()->Append(entry->id, GetLabel(entry));
|
||||||
true, i, effLen);
|
|
||||||
CurrentMenu()->Append(ID, labels[i]);
|
|
||||||
mbSeparatorAllowed = true;
|
mbSeparatorAllowed = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -627,11 +722,7 @@ void CommandManager::AddCommand(const wxChar *name,
|
|||||||
unsigned int flags,
|
unsigned int flags,
|
||||||
unsigned int mask)
|
unsigned int mask)
|
||||||
{
|
{
|
||||||
wxString label(label_in);
|
NewIdentifier(name, label_in, accel, NULL, callback, false, 0, 0);
|
||||||
label += wxT("\t");
|
|
||||||
label += accel;
|
|
||||||
|
|
||||||
NewIdentifier(name, label, NULL, callback, false, 0, 0);
|
|
||||||
|
|
||||||
if (flags != NoFlagsSpecifed || mask != NoFlagsSpecifed) {
|
if (flags != NoFlagsSpecifed || mask != NoFlagsSpecifed) {
|
||||||
SetCommandFlags(name, flags, mask);
|
SetCommandFlags(name, flags, mask);
|
||||||
@ -643,13 +734,8 @@ void CommandManager::AddMetaCommand(const wxChar *name,
|
|||||||
CommandFunctor *callback,
|
CommandFunctor *callback,
|
||||||
const wxChar *accel)
|
const wxChar *accel)
|
||||||
{
|
{
|
||||||
wxString label(label_in);
|
CommandListEntry *entry = NewIdentifier(name, label_in, accel, NULL, callback, false, 0, 0);
|
||||||
label += wxT("\t");
|
|
||||||
label += accel;
|
|
||||||
|
|
||||||
NewIdentifier(name, label, NULL, callback, false, 0, 0);
|
|
||||||
|
|
||||||
CommandListEntry *entry = mCommandNameHash[name];
|
|
||||||
entry->enabled = false;
|
entry->enabled = false;
|
||||||
entry->isMeta = true;
|
entry->isMeta = true;
|
||||||
entry->flags = 0;
|
entry->flags = 0;
|
||||||
@ -679,15 +765,34 @@ int CommandManager::NextIdentifier(int ID)
|
|||||||
///WARNING: Does this conflict with the identifiers set for controls/windows?
|
///WARNING: Does this conflict with the identifiers set for controls/windows?
|
||||||
///If it does, a workaround may be to keep controls below wxID_LOWEST
|
///If it does, a workaround may be to keep controls below wxID_LOWEST
|
||||||
///and keep menus above wxID_HIGHEST
|
///and keep menus above wxID_HIGHEST
|
||||||
int CommandManager::NewIdentifier(wxString name,
|
CommandListEntry *CommandManager::NewIdentifier(const wxString & name,
|
||||||
wxString label,
|
const wxString & label,
|
||||||
wxMenu *menu,
|
wxMenu *menu,
|
||||||
CommandFunctor *callback,
|
CommandFunctor *callback,
|
||||||
bool multi,
|
bool multi,
|
||||||
int index,
|
int index,
|
||||||
int count)
|
int count)
|
||||||
{
|
{
|
||||||
CommandListEntry *tmpEntry = new CommandListEntry;
|
return NewIdentifier(name,
|
||||||
|
label.BeforeFirst(wxT('\t')),
|
||||||
|
label.AfterFirst(wxT('\t')),
|
||||||
|
menu,
|
||||||
|
callback,
|
||||||
|
multi,
|
||||||
|
index,
|
||||||
|
count);
|
||||||
|
}
|
||||||
|
|
||||||
|
CommandListEntry *CommandManager::NewIdentifier(const wxString & name,
|
||||||
|
const wxString & label,
|
||||||
|
const wxString & accel,
|
||||||
|
wxMenu *menu,
|
||||||
|
CommandFunctor *callback,
|
||||||
|
bool multi,
|
||||||
|
int index,
|
||||||
|
int count)
|
||||||
|
{
|
||||||
|
CommandListEntry *entry = new CommandListEntry;
|
||||||
|
|
||||||
wxString labelPrefix;
|
wxString labelPrefix;
|
||||||
if (!mSubMenuList.IsEmpty()) {
|
if (!mSubMenuList.IsEmpty()) {
|
||||||
@ -704,86 +809,88 @@ int CommandManager::NewIdentifier(wxString name,
|
|||||||
// menu (which might be translated).
|
// menu (which might be translated).
|
||||||
|
|
||||||
mCurrentID = NextIdentifier(mCurrentID);
|
mCurrentID = NextIdentifier(mCurrentID);
|
||||||
tmpEntry->id = mCurrentID;
|
entry->id = mCurrentID;
|
||||||
tmpEntry->key = GetKey(label);
|
|
||||||
|
|
||||||
#if defined(__WXMAC__)
|
#if defined(__WXMAC__)
|
||||||
if (name == wxT("Preferences"))
|
if (name == wxT("Preferences"))
|
||||||
tmpEntry->id = wxID_PREFERENCES;
|
entry->id = wxID_PREFERENCES;
|
||||||
else if (name == wxT("Exit"))
|
else if (name == wxT("Exit"))
|
||||||
tmpEntry->id = wxID_EXIT;
|
entry->id = wxID_EXIT;
|
||||||
else if (name == wxT("About"))
|
else if (name == wxT("About"))
|
||||||
tmpEntry->id = wxID_ABOUT;
|
entry->id = wxID_ABOUT;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
tmpEntry->defaultKey = tmpEntry->key;
|
entry->defaultKey = entry->key;
|
||||||
|
entry->name = name;
|
||||||
|
entry->label = label;
|
||||||
|
entry->key = KeyStringNormalize(accel.BeforeFirst(wxT('\t')));
|
||||||
|
entry->labelPrefix = labelPrefix;
|
||||||
|
entry->labelTop = wxMenuItem::GetLabelText(mCurrentMenuName);
|
||||||
|
entry->menu = menu;
|
||||||
|
entry->callback = callback;
|
||||||
|
entry->multi = multi;
|
||||||
|
entry->index = index;
|
||||||
|
entry->count = count;
|
||||||
|
entry->flags = mDefaultFlags;
|
||||||
|
entry->mask = mDefaultMask;
|
||||||
|
entry->enabled = true;
|
||||||
|
entry->wantevent = (accel.Find(wxT("\twantevent")) != wxNOT_FOUND);
|
||||||
|
entry->ignoredown = (accel.Find(wxT("\tignoredown")) != wxNOT_FOUND);
|
||||||
|
entry->isMeta = false;
|
||||||
|
|
||||||
// For key bindings for commands with a list, such as effects,
|
// For key bindings for commands with a list, such as effects,
|
||||||
// the name in prefs is the category name plus the effect name.
|
// the name in prefs is the category name plus the effect name.
|
||||||
if( multi )
|
if (multi) {
|
||||||
name= wxString::Format( wxT("%s:%s"), name.c_str(), label.c_str() );
|
entry->name = wxString::Format( wxT("%s:%s"), name.c_str(), label.c_str() );
|
||||||
tmpEntry->name = name;
|
}
|
||||||
|
|
||||||
tmpEntry->label = label;
|
|
||||||
tmpEntry->labelPrefix = labelPrefix;
|
|
||||||
tmpEntry->labelTop = wxMenuItem::GetLabelText(mCurrentMenuName);
|
|
||||||
tmpEntry->menu = menu;
|
|
||||||
tmpEntry->callback = callback;
|
|
||||||
tmpEntry->multi = multi;
|
|
||||||
tmpEntry->index = index;
|
|
||||||
tmpEntry->count = count;
|
|
||||||
tmpEntry->flags = mDefaultFlags;
|
|
||||||
tmpEntry->mask = mDefaultMask;
|
|
||||||
tmpEntry->enabled = true;
|
|
||||||
tmpEntry->wantevent = (label.Find(wxT("\twantevent")) != wxNOT_FOUND);
|
|
||||||
tmpEntry->ignoredown = (label.Find(wxT("\tignoredown")) != wxNOT_FOUND);
|
|
||||||
tmpEntry->isMeta = false;
|
|
||||||
|
|
||||||
// Key from preferences overridse the default key given
|
// Key from preferences overridse the default key given
|
||||||
gPrefs->SetPath(wxT("/NewKeys"));
|
gPrefs->SetPath(wxT("/NewKeys"));
|
||||||
if (gPrefs->HasEntry(name)) {
|
if (gPrefs->HasEntry(name)) {
|
||||||
tmpEntry->key = KeyStringNormalize(gPrefs->Read(name, tmpEntry->key));
|
entry->key = KeyStringNormalize(gPrefs->Read(name, entry->key));
|
||||||
}
|
}
|
||||||
gPrefs->SetPath(wxT("/"));
|
gPrefs->SetPath(wxT("/"));
|
||||||
|
|
||||||
mCommandList.Add(tmpEntry);
|
mCommandList.Add(entry);
|
||||||
mCommandIDHash[tmpEntry->id] = tmpEntry;
|
mCommandIDHash[entry->id] = entry;
|
||||||
|
|
||||||
#if defined(__WXDEBUG__)
|
#if defined(__WXDEBUG__)
|
||||||
CommandListEntry *prev = mCommandNameHash[name];
|
CommandListEntry *prev = mCommandNameHash[entry->name];
|
||||||
if (prev) {
|
if (prev) {
|
||||||
// Under Linux it looks as if we may ask for a newID for the same command
|
// Under Linux it looks as if we may ask for a newID for the same command
|
||||||
// more than once. So it's only an error if two different commands
|
// more than once. So it's only an error if two different commands
|
||||||
// have the exact same name.
|
// have the exact same name.
|
||||||
if( prev->label != tmpEntry->label )
|
if( prev->label != entry->label )
|
||||||
{
|
{
|
||||||
wxLogDebug(wxT("Command '%s' defined by '%s' and '%s'"),
|
wxLogDebug(wxT("Command '%s' defined by '%s' and '%s'"),
|
||||||
name.c_str(),
|
entry->name.c_str(),
|
||||||
prev->label.BeforeFirst(wxT('\t')).c_str(),
|
prev->label.BeforeFirst(wxT('\t')).c_str(),
|
||||||
tmpEntry->label.BeforeFirst(wxT('\t')).c_str());
|
entry->label.BeforeFirst(wxT('\t')).c_str());
|
||||||
wxFAIL_MSG(wxString::Format(wxT("Command '%s' defined by '%s' and '%s'"),
|
wxFAIL_MSG(wxString::Format(wxT("Command '%s' defined by '%s' and '%s'"),
|
||||||
name.c_str(),
|
entry->name.c_str(),
|
||||||
prev->label.BeforeFirst(wxT('\t')).c_str(),
|
prev->label.BeforeFirst(wxT('\t')).c_str(),
|
||||||
tmpEntry->label.BeforeFirst(wxT('\t')).c_str()));
|
entry->label.BeforeFirst(wxT('\t')).c_str()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
mCommandNameHash[name] = tmpEntry;
|
mCommandNameHash[name] = entry;
|
||||||
|
|
||||||
if (tmpEntry->key != wxT("")) {
|
if (entry->key != wxT("")) {
|
||||||
mCommandKeyHash[tmpEntry->key] = tmpEntry;
|
mCommandKeyHash[entry->key] = entry;
|
||||||
}
|
}
|
||||||
|
|
||||||
return tmpEntry->id;
|
return entry;
|
||||||
}
|
}
|
||||||
|
|
||||||
wxString CommandManager::GetKey(wxString label)
|
wxString CommandManager::GetLabel(const CommandListEntry *entry) const
|
||||||
{
|
{
|
||||||
wxString key = label.AfterFirst(wxT('\t')).BeforeFirst(wxT('\t'));
|
wxString label = entry->label;
|
||||||
if (key.IsEmpty()) {
|
if (!entry->key.IsEmpty())
|
||||||
return key;
|
{
|
||||||
|
label += wxT("\t") + entry->key;
|
||||||
}
|
}
|
||||||
|
|
||||||
return KeyStringNormalize(key);
|
return label;
|
||||||
}
|
}
|
||||||
|
|
||||||
///Enables or disables a menu item based on its name (not the
|
///Enables or disables a menu item based on its name (not the
|
||||||
@ -932,6 +1039,44 @@ void CommandManager::TellUserWhyDisallowed( wxUint32 flagsGot, wxUint32 flagsReq
|
|||||||
wxMessageBox(reason, _("Disallowed"), wxICON_WARNING | wxOK );
|
wxMessageBox(reason, _("Disallowed"), wxICON_WARNING | wxOK );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
///
|
||||||
|
///
|
||||||
|
bool CommandManager::FilterKeyEvent(AudacityProject *project, wxKeyEvent & evt)
|
||||||
|
{
|
||||||
|
if (HandleMeta(evt))
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Any other keypresses must be destined for this project window.
|
||||||
|
if (wxGetTopLevelParent(wxWindow::FindFocus()) != project)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
wxUint32 flags = project->GetUpdateFlags();
|
||||||
|
|
||||||
|
wxKeyEvent temp = evt;
|
||||||
|
temp.SetEventType(wxEVT_KEY_DOWN);
|
||||||
|
if (HandleKey(temp, flags, 0xFFFFFFFF))
|
||||||
|
{
|
||||||
|
temp.SetEventType(wxEVT_KEY_UP);
|
||||||
|
HandleKey(temp, flags, 0xFFFFFFFF);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (project->HandleKeyDown(evt))
|
||||||
|
{
|
||||||
|
wxKeyEvent temp = evt;
|
||||||
|
temp.SetEventType(wxEVT_KEY_UP);
|
||||||
|
project->HandleKeyUp(temp);
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
/// HandleCommandEntry() takes a CommandListEntry and executes it
|
/// HandleCommandEntry() takes a CommandListEntry and executes it
|
||||||
/// returning true iff successful. If you pass any flags,
|
/// returning true iff successful. If you pass any flags,
|
||||||
///the command won't be executed unless the flags are compatible
|
///the command won't be executed unless the flags are compatible
|
||||||
@ -952,7 +1097,6 @@ bool CommandManager::HandleCommandEntry(CommandListEntry * entry, wxUint32 flags
|
|||||||
|
|
||||||
// NB: The call may have the side effect of changing flags.
|
// NB: The call may have the side effect of changing flags.
|
||||||
bool allowed = proj->TryToMakeActionAllowed( flags, entry->flags, combinedMask );
|
bool allowed = proj->TryToMakeActionAllowed( flags, entry->flags, combinedMask );
|
||||||
|
|
||||||
if (!allowed)
|
if (!allowed)
|
||||||
{
|
{
|
||||||
TellUserWhyDisallowed(
|
TellUserWhyDisallowed(
|
||||||
|
@ -71,6 +71,8 @@ WX_DEFINE_USER_EXPORTED_ARRAY(CommandListEntry *, CommandList, class AUDACITY_DL
|
|||||||
WX_DECLARE_STRING_HASH_MAP_WITH_DECL(CommandListEntry *, CommandNameHash, class AUDACITY_DLL_API);
|
WX_DECLARE_STRING_HASH_MAP_WITH_DECL(CommandListEntry *, CommandNameHash, class AUDACITY_DLL_API);
|
||||||
WX_DECLARE_HASH_MAP_WITH_DECL(int, CommandListEntry *, wxIntegerHash, wxIntegerEqual, CommandIDHash, class AUDACITY_DLL_API);
|
WX_DECLARE_HASH_MAP_WITH_DECL(int, CommandListEntry *, wxIntegerHash, wxIntegerEqual, CommandIDHash, class AUDACITY_DLL_API);
|
||||||
|
|
||||||
|
class AudacityProject;
|
||||||
|
|
||||||
class AUDACITY_DLL_API CommandManager: public XMLTagHandler
|
class AUDACITY_DLL_API CommandManager: public XMLTagHandler
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
@ -183,6 +185,7 @@ class AUDACITY_DLL_API CommandManager: public XMLTagHandler
|
|||||||
//
|
//
|
||||||
// Executing commands
|
// Executing commands
|
||||||
//
|
//
|
||||||
|
bool FilterKeyEvent(AudacityProject *project, wxKeyEvent & evt);
|
||||||
bool HandleCommandEntry(CommandListEntry * entry, wxUint32 flags, wxUint32 mask, const wxEvent * evt = NULL);
|
bool HandleCommandEntry(CommandListEntry * entry, wxUint32 flags, wxUint32 mask, const wxEvent * evt = NULL);
|
||||||
bool HandleMenuID(int id, wxUint32 flags, wxUint32 mask);
|
bool HandleMenuID(int id, wxUint32 flags, wxUint32 mask);
|
||||||
bool HandleKey(wxKeyEvent &evt, wxUint32 flags, wxUint32 mask);
|
bool HandleKey(wxKeyEvent &evt, wxUint32 flags, wxUint32 mask);
|
||||||
@ -228,18 +231,30 @@ class AUDACITY_DLL_API CommandManager: public XMLTagHandler
|
|||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|
||||||
wxMenuBar * CurrentMenuBar();
|
wxMenuBar * CurrentMenuBar() const;
|
||||||
wxMenuBar * GetMenuBar(wxString sMenu);
|
wxMenuBar * GetMenuBar(wxString sMenu) const;
|
||||||
wxMenu * CurrentSubMenu();
|
wxMenu * CurrentSubMenu() const;
|
||||||
wxMenu * CurrentMenu();
|
wxMenu * CurrentMenu() const;
|
||||||
|
|
||||||
int NextIdentifier(int ID);
|
int NextIdentifier(int ID);
|
||||||
int NewIdentifier(wxString name, wxString label, wxMenu *menu,
|
CommandListEntry *NewIdentifier(const wxString & name,
|
||||||
|
const wxString & label,
|
||||||
|
wxMenu *menu,
|
||||||
CommandFunctor *callback,
|
CommandFunctor *callback,
|
||||||
bool multi, int index, int count);
|
bool multi,
|
||||||
|
int index,
|
||||||
|
int count);
|
||||||
|
CommandListEntry *NewIdentifier(const wxString & name,
|
||||||
|
const wxString & label,
|
||||||
|
const wxString & accel,
|
||||||
|
wxMenu *menu,
|
||||||
|
CommandFunctor *callback,
|
||||||
|
bool multi,
|
||||||
|
int index,
|
||||||
|
int count);
|
||||||
void Enable(CommandListEntry *entry, bool enabled);
|
void Enable(CommandListEntry *entry, bool enabled);
|
||||||
|
|
||||||
wxString GetKey(wxString label);
|
wxString GetLabel(const CommandListEntry *entry) const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
MenuBarList mMenuBarList;
|
MenuBarList mMenuBarList;
|
||||||
|
@ -62,11 +62,8 @@ wxString KeyEventToKeyString(const wxKeyEvent & event)
|
|||||||
long key = event.GetKeyCode();
|
long key = event.GetKeyCode();
|
||||||
|
|
||||||
if (event.ControlDown())
|
if (event.ControlDown())
|
||||||
#if defined(__WXMAC__)
|
|
||||||
newStr += wxT("XCtrl+");
|
|
||||||
#else
|
|
||||||
newStr += wxT("Ctrl+");
|
newStr += wxT("Ctrl+");
|
||||||
#endif
|
|
||||||
if (event.AltDown())
|
if (event.AltDown())
|
||||||
newStr += wxT("Alt+");
|
newStr += wxT("Alt+");
|
||||||
|
|
||||||
@ -74,11 +71,11 @@ wxString KeyEventToKeyString(const wxKeyEvent & event)
|
|||||||
newStr += wxT("Shift+");
|
newStr += wxT("Shift+");
|
||||||
|
|
||||||
#if defined(__WXMAC__)
|
#if defined(__WXMAC__)
|
||||||
if (event.MetaDown())
|
if (event.RawControlDown())
|
||||||
newStr += wxT("Ctrl+");
|
newStr += wxT("XCtrl+");
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (event.ControlDown() && key >= 1 && key <= 26)
|
if (event.RawControlDown() && key >= 1 && key <= 26)
|
||||||
newStr += (wxChar)(64 + key);
|
newStr += (wxChar)(64 + key);
|
||||||
else if (key >= 33 && key <= 126)
|
else if (key >= 33 && key <= 126)
|
||||||
newStr += (wxChar)key;
|
newStr += (wxChar)key;
|
||||||
|
@ -305,7 +305,10 @@ void TranscriptionToolBar::RegenerateTooltips()
|
|||||||
{
|
{
|
||||||
#if wxUSE_TOOLTIPS
|
#if wxUSE_TOOLTIPS
|
||||||
mButtons[TTB_PlaySpeed]->SetToolTip(_("Play-at-speed"));
|
mButtons[TTB_PlaySpeed]->SetToolTip(_("Play-at-speed"));
|
||||||
mPlaySpeedSlider->SetToolTip(_("Playback Speed"));
|
|
||||||
|
wxString tip;
|
||||||
|
tip.Printf(_("Playback Speed") + wxT(": %.2fx"), mPlaySpeedSlider->Get());
|
||||||
|
mPlaySpeedSlider->SetToolTip(tip);
|
||||||
|
|
||||||
#ifdef EXPERIMENTAL_VOICE_DETECTION
|
#ifdef EXPERIMENTAL_VOICE_DETECTION
|
||||||
mButtons[TTB_StartOn]->SetToolTip(TRANSLATABLE("Left-to-On"));
|
mButtons[TTB_StartOn]->SetToolTip(TRANSLATABLE("Left-to-On"));
|
||||||
@ -487,6 +490,7 @@ void TranscriptionToolBar::OnPlaySpeed(wxCommandEvent & WXUNUSED(event))
|
|||||||
void TranscriptionToolBar::OnSpeedSlider(wxCommandEvent& WXUNUSED(event))
|
void TranscriptionToolBar::OnSpeedSlider(wxCommandEvent& WXUNUSED(event))
|
||||||
{
|
{
|
||||||
mPlaySpeed = (mPlaySpeedSlider->Get()) * 100;
|
mPlaySpeed = (mPlaySpeedSlider->Get()) * 100;
|
||||||
|
RegenerateTooltips();
|
||||||
|
|
||||||
// If IO is busy, abort immediately
|
// If IO is busy, abort immediately
|
||||||
// AWD: This is disabled to work around a hang on Linux when PulseAudio is
|
// AWD: This is disabled to work around a hang on Linux when PulseAudio is
|
||||||
|
@ -465,6 +465,12 @@ void LWSlider::SetScroll(float line, float page)
|
|||||||
|
|
||||||
void LWSlider::CreatePopWin()
|
void LWSlider::CreatePopWin()
|
||||||
{
|
{
|
||||||
|
if (mTipPanel)
|
||||||
|
{
|
||||||
|
delete mTipPanel;
|
||||||
|
mTipPanel = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
wxString maxTipLabel = mName + wxT(": 000000");
|
wxString maxTipLabel = mName + wxT(": 000000");
|
||||||
|
|
||||||
if (mStyle == PAN_SLIDER || mStyle == DB_SLIDER || mStyle == SPEED_SLIDER
|
if (mStyle == PAN_SLIDER || mStyle == DB_SLIDER || mStyle == SPEED_SLIDER
|
||||||
@ -912,6 +918,15 @@ void LWSlider::OnMouseEvent(wxMouseEvent & event)
|
|||||||
if (!mEnabled)
|
if (!mEnabled)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
// Windows sends a right button mouse event when you press the context menu
|
||||||
|
// key, so ignore it.
|
||||||
|
if ((event.RightDown() && !event.RightIsDown()) ||
|
||||||
|
(event.RightUp() && event.GetPosition() == wxPoint(-1, -1)))
|
||||||
|
{
|
||||||
|
event.Skip(false);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
float prevValue = mCurrentValue;
|
float prevValue = mCurrentValue;
|
||||||
|
|
||||||
// Figure out the thumb position
|
// Figure out the thumb position
|
||||||
@ -940,7 +955,7 @@ void LWSlider::OnMouseEvent(wxMouseEvent & event)
|
|||||||
}
|
}
|
||||||
else if( event.ButtonDown() )
|
else if( event.ButtonDown() )
|
||||||
{
|
{
|
||||||
if( mDefaultShortcut && event.CmdDown() )
|
if( mDefaultShortcut && event.ControlDown() )
|
||||||
{
|
{
|
||||||
mCurrentValue = mDefaultValue;
|
mCurrentValue = mDefaultValue;
|
||||||
}
|
}
|
||||||
@ -974,8 +989,6 @@ void LWSlider::OnMouseEvent(wxMouseEvent & event)
|
|||||||
mParent->CaptureMouse();
|
mParent->CaptureMouse();
|
||||||
}
|
}
|
||||||
|
|
||||||
wxASSERT(mTipPanel == NULL);
|
|
||||||
|
|
||||||
CreatePopWin();
|
CreatePopWin();
|
||||||
FormatPopWin();
|
FormatPopWin();
|
||||||
SetPopWinPosition();
|
SetPopWinPosition();
|
||||||
@ -990,10 +1003,11 @@ void LWSlider::OnMouseEvent(wxMouseEvent & event)
|
|||||||
if (mParent->HasCapture())
|
if (mParent->HasCapture())
|
||||||
mParent->ReleaseMouse();
|
mParent->ReleaseMouse();
|
||||||
|
|
||||||
wxASSERT(mTipPanel != NULL);
|
if (mTipPanel)
|
||||||
|
{
|
||||||
delete mTipPanel;
|
delete mTipPanel;
|
||||||
mTipPanel = NULL;
|
mTipPanel = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
//restore normal tooltip behavor for mouseovers
|
//restore normal tooltip behavor for mouseovers
|
||||||
wxToolTip::Enable(true);
|
wxToolTip::Enable(true);
|
||||||
|
@ -2177,14 +2177,14 @@ void AdornedRulerPanel::OnMouseEvents(wxMouseEvent &evt)
|
|||||||
AudioIOStartStreamOptions options(mProject->GetDefaultPlayOptions());
|
AudioIOStartStreamOptions options(mProject->GetDefaultPlayOptions());
|
||||||
options.playLooped = (loopEnabled && evt.ShiftDown());
|
options.playLooped = (loopEnabled && evt.ShiftDown());
|
||||||
|
|
||||||
if (!evt.CmdDown()) // Use CmdDown rather than ControlDown. See bug 746
|
if (!evt.ControlDown())
|
||||||
options.pStartTime = &mPlayRegionStart;
|
options.pStartTime = &mPlayRegionStart;
|
||||||
else
|
else
|
||||||
options.timeTrack = NULL;
|
options.timeTrack = NULL;
|
||||||
|
|
||||||
ctb->PlayPlayRegion((SelectedRegion(start, end)),
|
ctb->PlayPlayRegion((SelectedRegion(start, end)),
|
||||||
options,
|
options,
|
||||||
evt.CmdDown(),
|
evt.ControlDown(),
|
||||||
false,
|
false,
|
||||||
true);
|
true);
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user