Aegisub/aegisub/hotkeys.cpp

524 lines
15 KiB
C++

// Copyright (c) 2005, Rodrigo Braz Monteiro
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// * Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
// * Neither the name of the Aegisub Group nor the names of its contributors
// may be used to endorse or promote products derived from this software
// without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.
//
// -----------------------------------------------------------------------------
//
// AEGISUB
//
// Website: http://aegisub.cellosoft.com
// Contact: mailto:zeratul@cellosoft.com
//
///////////
// Headers
#include "config.h"
#include "hotkeys.h"
#include <fstream>
#include "text_file_reader.h"
#include "text_file_writer.h"
#include <wx/filename.h>
#include <wx/accel.h>
/////////////////////////////// HotkeyType //////////////////////////////////
////////////////
// Constructors
HotkeyType::HotkeyType() {
flags = 0;
keycode = 0;
}
HotkeyType::HotkeyType(wxString text,wxString name) {
Parse(text);
origName = name;
}
////////////////////////
// Get string of hotkey
wxString HotkeyType::GetText() {
wxString text;
// Modifiers
if (flags & wxACCEL_CTRL) text += _T("Ctrl-");
if (flags & wxACCEL_ALT) text += _T("Alt-");
if (flags & wxACCEL_SHIFT) text += _T("Shift-");
// Key name
text += GetKeyName(keycode);
return text;
}
//////////////////////////
// Parse text into hotkey
void HotkeyType::Parse(wxString text) {
// Reset
flags = 0;
keycode = 0;
wxString work = text.Lower();
// Parse modifiers
while (true) {
// Ctrl
if (work.Left(5) == _T("ctrl-")) {
flags |= wxACCEL_CTRL;
work = work.Mid(5);
continue;
}
// Alt
if (work.Left(4) == _T("alt-")) {
flags |= wxACCEL_ALT;
work = work.Mid(4);
continue;
}
// Shift
if (work.Left(6) == _T("shift-")) {
flags |= wxACCEL_SHIFT;
work = work.Mid(6);
continue;
}
break;
}
// Get key name
FillMap();
bool got = false;
std::map<int,wxString>::iterator cur;
for (cur = keyName.begin();cur != keyName.end();cur++) {
if (cur->second.Lower() == work) {
keycode = cur->first;
got = true;
break;
}
}
// Didn't find, check if it's a raw code
if (!got) {
if (work.Left(1) == _T("[") && work.Right(1) == _T("]")) {
work = work.Mid(1,work.Length()-2);
if (work.IsNumber()) {
long temp;
work.ToLong(&temp);
keycode = temp;
}
}
}
}
//////////////////////////
// Get name from Key code
std::map<int,wxString> HotkeyType::keyName;
wxString HotkeyType::GetKeyName(int keycode) {
// Fill map
FillMap();
// Blank key
if (keycode == 0) return _T("");
// Get key name
std::map<int,wxString>::iterator cur = keyName.find(keycode);
if (cur != keyName.end()) return cur->second;
else return wxString::Format(_T("[%i]"),keycode);
}
////////////
// Fill map
void HotkeyType::FillMap() {
if (keyName.empty()) {
keyName[WXK_BACK] = _T("Backspace");
keyName[WXK_SPACE] = _T("Space");
keyName[WXK_RETURN] = _T("Enter");
keyName[WXK_TAB] = _T("Tab");
keyName[WXK_PAUSE] = _T("Pause");
keyName[WXK_LEFT] = _T("Left");
keyName[WXK_RIGHT] = _T("Right");
keyName[WXK_UP] = _T("Up");
keyName[WXK_DOWN] = _T("Down");
keyName[WXK_INSERT] = _T("Insert");
keyName[WXK_DELETE] = _T("Delete");
keyName[WXK_HOME] = _T("Home");
keyName[WXK_END] = _T("End");
keyName[WXK_PAGEUP] = _T("PgUp");
keyName[WXK_PAGEDOWN] = _T("PgDn");
keyName[WXK_NUMPAD0] = _T("KP_0");
keyName[WXK_NUMPAD1] = _T("KP_1");
keyName[WXK_NUMPAD2] = _T("KP_2");
keyName[WXK_NUMPAD3] = _T("KP_3");
keyName[WXK_NUMPAD4] = _T("KP_4");
keyName[WXK_NUMPAD5] = _T("KP_5");
keyName[WXK_NUMPAD6] = _T("KP_6");
keyName[WXK_NUMPAD7] = _T("KP_7");
keyName[WXK_NUMPAD8] = _T("KP_8");
keyName[WXK_NUMPAD9] = _T("KP_9");
keyName[WXK_NUMPAD_ADD] = _T("KP_Add");
keyName[WXK_NUMPAD_SUBTRACT] = _T("KP_Subtract");
keyName[WXK_NUMPAD_SUBTRACT] = _T("KP_Subtract");
keyName[WXK_NUMPAD_MULTIPLY] = _T("KP_Multiply");
keyName[WXK_NUMPAD_DIVIDE] = _T("KP_Divide");
keyName[WXK_NUMPAD_DECIMAL] = _T("KP_Decimal");
keyName[WXK_NUMPAD_ENTER] = _T("KP_Enter");
keyName[WXK_F1] = _T("F1");
keyName[WXK_F2] = _T("F2");
keyName[WXK_F3] = _T("F3");
keyName[WXK_F4] = _T("F4");
keyName[WXK_F5] = _T("F5");
keyName[WXK_F6] = _T("F6");
keyName[WXK_F7] = _T("F7");
keyName[WXK_F8] = _T("F8");
keyName[WXK_F9] = _T("F9");
keyName[WXK_F10] = _T("F10");
keyName[WXK_F11] = _T("F11");
keyName[WXK_F12] = _T("F12");
for (char i='!';i<='`';i++) {
keyName[i] = wchar_t(i);
}
}
}
////////////////////////////// HotkeyManager ////////////////////////////////
//////////////
// Definition
HotkeyManager Hotkeys;
///////////////
// Constructor
HotkeyManager::HotkeyManager() {
modified = false;
}
//////////////
// Destructor
HotkeyManager::~HotkeyManager() {
key.clear();
}
////////
// Save
void HotkeyManager::Save() {
// Check if it's actually modified
if (!modified) return;
// Open file
using namespace std;
TextFileWriter file(filename,_T("UTF-8"));
file.WriteLineToFile(_T("[Hotkeys]"));
// Put variables in it
for (map<wxString,HotkeyType>::iterator cur=key.begin();cur!=key.end();cur++) {
file.WriteLineToFile((*cur).first + _T("=") + (*cur).second.GetText());
}
// Close
modified = false;
}
////////
// Load
void HotkeyManager::Load() {
// Load defaults
LoadDefaults();
// Check if file exists (create if it doesn't)
wxFileName path(filename);
if (!path.FileExists()) {
modified = true;
Save();
return;
}
// Open file
using namespace std;
TextFileReader file(filename);
wxString header = file.ReadLineFromFile();
if (header != _T("[Hotkeys]")) throw _T("Invalid hotkeys file");
// Get variables
wxString curLine;
map<wxString,HotkeyType>::iterator cur;
while (file.HasMoreLines()) {
// Parse line
curLine = file.ReadLineFromFile();
if (curLine.IsEmpty()) continue;
size_t pos = curLine.Find(_T("="));
if (pos == wxString::npos) continue;
wxString func = curLine.Left(pos);
wxString value = curLine.Mid(pos+1);
// Find it
cur = key.find(func);
if (cur != key.end()) {
(*cur).second.Parse(value);
}
// Commented out so it discards anything that isn't listed:
//else SetHotkey(func,value);
}
// Close
Save();
}
/////////////////
// Load defaults
void HotkeyManager::LoadDefaults() {
modified = true;
// NOTE!!
// _() is used here instead of _T(). This is done so the strings can be extracted.
// However, since this function is called before locale is set, it won't ever be translated.
// Keep this in mind: THESE CANNOT BE TRANSLATED HERE!
// As a safeguard, _() is undefined here
#undef _
#define _(a) _T(a)
SetHotkey(_("New subtitles"),_T("Ctrl-N"));
SetHotkey(_("Open subtitles"),_T("Ctrl-O"));
SetHotkey(_("Save subtitles"),_T("Ctrl-S"));
#ifdef __APPLE__
SetHotkey(_("Exit"),_T("Ctrl-Q"));
SetHotkey(_("Help"),_T("Ctrl-?"));
SetHotkey(_("Options"),_T("Ctrl-,"));
#else
SetHotkey(_("Exit"),_T("Alt-F4"));
SetHotkey(_("Help"),_T("F1"));
SetHotkey(_("Options"),_T("Alt-O"));
#endif
SetHotkey(_("Edit Box Commit"),_T("Ctrl-Enter"));
SetHotkey(_("Undo"),_T("Ctrl-Z"));
#ifdef __APPLE__
SetHotkey(_("Redo"),_T("Ctrl-Shift-Z"));
#else
SetHotkey(_("Redo"),_T("Ctrl-Y"));
#endif
SetHotkey(_("Shift Times"),_T("Ctrl-I"));
SetHotkey(_("Find"),_T("Ctrl-F"));
#ifdef __APPLE__
SetHotkey(_("Find Next"),_T("Ctrl-G"));
SetHotkey(_("Replace"),_T("Ctrl-Shift-F")); // non-standard?
#else
SetHotkey(_("Find Next"),_T("F3"));
SetHotkey(_("Replace"),_T("Ctrl-H"));
#endif
SetHotkey(_("Select Lines"),_T(""));
SetHotkey(_("Copy"),_T("Ctrl-C"));
SetHotkey(_("Cut"),_T("Ctrl-X"));
SetHotkey(_("Paste"),_T("Ctrl-V"));
SetHotkey(_("Paste Over"),_T("Ctrl-Shift-V"));
#ifdef __APPLE__
SetHotkey(_("Video Jump"),_T("Ctrl-J"));
#else
SetHotkey(_("Video Jump"),_T("Ctrl-G"));
#endif
SetHotkey(_("Jump Video to Start"),_T("Ctrl-1"));
SetHotkey(_("Jump Video to End"),_T("Ctrl-2"));
SetHotkey(_("Set Start to Video"),_T("Ctrl-3"));
SetHotkey(_("Set End to Video"),_T("Ctrl-4"));
SetHotkey(_("Snap to Scene"),_T("Ctrl-5"));
SetHotkey(_("Shift by Current Time"),_T("Ctrl-6"));
SetHotkey(_("Zoom 50%"),_T(""));
SetHotkey(_("Zoom 100%"),_T(""));
SetHotkey(_("Zoom 200%"),_T(""));
SetHotkey(_("Video global prev frame"),_T("Ctrl-KP_4"));
SetHotkey(_("Video global next frame"),_T("Ctrl-KP_6"));
SetHotkey(_("Video global focus seek"),_T("Ctrl-Space"));
SetHotkey(_("Video global play"),_T("Ctrl-P"));
SetHotkey(_("Grid global prev line"),_T("Ctrl-KP_8"));
SetHotkey(_("Grid global next line"),_T("Ctrl-KP_2"));
SetHotkey(_("Save Subtitles Alt"),_T("F2"));
SetHotkey(_("Video global zoom in"),_T("Ctrl-KP_Add"));
SetHotkey(_("Video global zoom out"),_T("Ctrl-KP_Subtract"));
SetHotkey(_("Grid move row down"),_T("Alt-Down"));
SetHotkey(_("Grid move row up"),_T("Alt-Up"));
#ifdef __APPLE__
SetHotkey(_("Grid delete rows"),_T("Ctrl-Backspace"));
#else
SetHotkey(_("Grid delete rows"),_T("Ctrl-Delete"));
#endif
SetHotkey(_("Grid duplicate rows"),_T(""));
SetHotkey(_("Grid duplicate and shift one frame"),_T("Ctrl-D"));
SetHotkey(_("Audio Commit Alt"),_T("G"));
SetHotkey(_("Audio Commit"),_T("Enter"));
SetHotkey(_("Audio Commit (Stay)"),_T("F8"));
SetHotkey(_("Audio Prev Line"),_T("Left"));
SetHotkey(_("Audio Prev Line Alt"),_T("Z"));
SetHotkey(_("Audio Next Line"),_T("Right"));
SetHotkey(_("Audio Next Line Alt"),_T("X"));
SetHotkey(_("Audio Play"),_T("Space"));
SetHotkey(_("Audio Play Alt"),_T("S"));
SetHotkey(_("Audio Play or Stop"),_T("B"));
SetHotkey(_("Audio Stop"),_T("H"));
SetHotkey(_("Audio Karaoke Increase Len"),_T("KP_Add"));
SetHotkey(_("Audio Karaoke Decrease Len"),_T("KP_Subtract"));
SetHotkey(_("Audio Karaoke Increase Len Shift"),_T("Shift-KP_Add"));
SetHotkey(_("Audio Karaoke Decrease Len Shift"),_T("Shift-KP_Subtract"));
SetHotkey(_("Audio Scroll Left"),_T("A"));
SetHotkey(_("Audio Scroll Right"),_T("F"));
SetHotkey(_("Audio Play First 500ms"),_T("E"));
SetHotkey(_("Audio Play Last 500ms"),_T("D"));
SetHotkey(_("Audio Play 500ms Before"),_T("Q"));
SetHotkey(_("Audio Play 500ms After"),_T("W"));
SetHotkey(_("Audio Play To End"),_T("T"));
SetHotkey(_("Audio Play Original Line"),_T("R"));
SetHotkey(_("Audio Add Lead In"),_T("C"));
SetHotkey(_("Audio Add Lead Out"),_T("V"));
SetHotkey(_("Audio Medusa Toggle"),_T("Ctrl-KP_Multiply"));
SetHotkey(_("Audio Medusa Play"),_T("KP_5"));
SetHotkey(_("Audio Medusa Stop"),_T("KP_8"));
SetHotkey(_("Audio Medusa Shift Start Back"),_T("KP_4"));
SetHotkey(_("Audio Medusa Shift Start Forward"),_T("KP_6"));
SetHotkey(_("Audio Medusa Shift End Back"),_T("KP_7"));
SetHotkey(_("Audio Medusa Shift End Forward"),_T("KP_9"));
SetHotkey(_("Audio Medusa Play Before"),_T("KP_1"));
SetHotkey(_("Audio Medusa Play After"),_T("KP_3"));
SetHotkey(_("Audio Medusa Next"),_T("KP_2"));
SetHotkey(_("Audio Medusa Previous"),_T("KP_0"));
SetHotkey(_("Audio Medusa Enter"),_T("KP_Enter"));
SetHotkey(_("Translation Assistant Play Audio"),_T("End"));
SetHotkey(_("Translation Assistant Play Video"),_T("Home"));
SetHotkey(_("Translation Assistant Next"),_T("PgDn"));
SetHotkey(_("Translation Assistant Prev"),_T("PgUp"));
SetHotkey(_("Translation Assistant Accept"),_T("Enter"));
SetHotkey(_("Translation Assistant Preview"),_T("F8"));
SetHotkey(_("Translation Assistant Insert Original"),_T("Insert"));
SetHotkey(_("Styling Assistant Play Audio"),_T("End"));
SetHotkey(_("Styling Assistant Play Video"),_T("Home"));
SetHotkey(_("Styling Assistant Next"),_T("PgDn"));
SetHotkey(_("Styling Assistant Prev"),_T("PgUp"));
SetHotkey(_("Styling Assistant Accept"),_T("Enter"));
SetHotkey(_("Styling Assistant Preview"),_T("F8"));
}
//////////////
// Set hotkey
void HotkeyManager::SetHotkey(wxString function,HotkeyType hotkey) {
key[function.Lower()] = hotkey;
modified = true;
}
void HotkeyManager::SetHotkey(wxString function,wxString hotkey) {
key[function.Lower()] = HotkeyType(hotkey,function);
modified = true;
}
////////////
// Set file
void HotkeyManager::SetFile(wxString file) {
filename = file;
}
//////////////////////
// Get hotkey as text
wxString HotkeyManager::GetText(wxString function) {
std::map<wxString,HotkeyType>::iterator cur = key.find(function.Lower());
if (cur != key.end()) {
return (*cur).second.GetText();
}
else throw _T("Hotkey not defined");
}
///////////////////////////////////
// Get hotkey as accelerator entry
wxAcceleratorEntry HotkeyManager::GetAccelerator(wxString function,int id) {
std::map<wxString,HotkeyType>::iterator cur = key.find(function.Lower());
if (cur != key.end()) {
HotkeyType *hotkey = &(*cur).second;
wxAcceleratorEntry entry;
entry.Set(hotkey->flags,hotkey->keycode,id);
return entry;
}
else throw _T("Hotkey not defined");
}
////////////////////////
// Set last key pressed
void HotkeyManager::SetPressed(int keypress,bool ctrl,bool alt,bool shift) {
lastKey = keypress;
lastMod = 0;
if (ctrl) lastMod |= wxACCEL_CTRL;
if (alt) lastMod |= wxACCEL_ALT;
if (shift) lastMod |= wxACCEL_SHIFT;
}
///////////////
// Is pressed?
bool HotkeyManager::IsPressed(wxString function) {
std::map<wxString,HotkeyType>::iterator cur = key.find(function.Lower());
if (cur != key.end()) {
HotkeyType *hotkey = &(*cur).second;
return (hotkey->keycode == lastKey && hotkey->flags == lastMod);
}
else throw _T("Hotkey not defined");
}
///////////////////////
// Search for a hotkey
HotkeyType *HotkeyManager::Find(int keycode,int mod) {
for (std::map<wxString,HotkeyType>::iterator cur = key.begin();cur != key.end();cur++) {
if (cur->second.keycode == keycode && cur->second.flags == mod) {
return &(cur->second);
}
}
return NULL;
}