Refactored PromptWidget a bit

This commit is contained in:
Thomas Jentzsch 2021-05-09 19:21:15 +02:00
parent e5e4e542b2
commit a39a03309e
7 changed files with 325 additions and 353 deletions

View File

@ -345,52 +345,52 @@ size can be configured e.g. in the
<p>
<table BORDER=1 cellpadding=4>
<tr>
<th>Key</th>
<th>Function</th>
<th>Key</th>
</tr>
<tr>
<td>Control + S</td>
<td>Step</td>
<td>Control + S</td>
</tr>
<tr>
<td>Control + T</td>
<td>Trace</td>
<td>Control + T</td>
</tr>
<tr>
<td>Control + L</td>
<td>Scan +1</td>
<td>Control + L</td>
</tr>
<tr>
<td>Control + F</td>
<td>Frame +1</td>
<td>Control + F</td>
</tr>
<tr>
<td>Alt + Left arrow</td>
<td>Rewind 1</td>
<td>Alt + Left arrow</td>
</tr>
<tr>
<td>Shift-Alt + Left arrow</td>
<td>Rewind 10</td>
<td>Shift-Alt + Left arrow</td>
</tr>
<tr>
<td>Alt + Down arrow</td>
<td>Rewind all</td>
<td>Alt + Down arrow</td>
</tr>
<tr>
<td>Alt + Right arrow</td>
<td>Unwind 1</td>
<td>Alt + Right arrow</td>
</tr>
<tr>
<td>Shift-Alt + Right arrow</td>
<td>Unwind 10</td>
<td>Shift-Alt + Right arrow</td>
</tr>
<tr>
<td>Alt + Up arrow</td>
<td>Unwind all</td>
<td>Alt + Up arrow</td>
</tr>
<tr>
<td>Backquote (`)</td>
<td>Run, exits debugger</td>
<td>Backquote (`)</td>
</tr>
</table>
</p>
@ -428,25 +428,28 @@ or Supermon for the C=64.</p>
Bash-style commands are also supported:</p>
<table border="1" cellpadding=4>
<tr><th>Key</th><th>Function</th></tr>
<tr><td>Home</td><td>Move cursor to beginning of line</td></tr>
<tr><td>End</td><td>Move cursor to end of line</td></tr>
<tr><td>Delete</td><td>Remove character to right of cursor</td></tr>
<tr><td>Backspace</td><td>Remove character to left of cursor</td></tr>
<tr><td>Control + A</td><td>Same function as 'Home'</td></tr>
<tr><td>Control + E</td><td>Same function as 'End'</td></tr>
<tr><td>Control + D</td><td>Same function as 'Delete'</td></tr>
<tr><td>Control + K</td><td>Remove all characters from cursor to end of line</td></tr>
<tr><td>Control + U</td><td>Remove all characters from cursor to beginning of line</td></tr>
<tr><td>Control + W</td><td>Remove entire word to left of cursor</td></tr>
<tr><td>Shift + PgUp</td><td>Scroll up through previous commands one screen/page</td></tr>
<tr><td>Shift + PgDown</td><td>Scroll down through previous commands one screen/page</td></tr>
<tr><td>Shift + Up</td><td>Scroll up through previous commands one line</td></tr>
<tr><td>Shift + Down</td><td>Scroll down through previous commands one line</td></tr>
<tr><td>Shift + Home</td><td>Scroll to beginning of commands</td></tr>
<tr><td>Shift + End</td><td>Scroll to end of commands</td></tr>
<tr><th>Function</th><th>Key</th></tr>
<tr><td>Move cursor to beginning of line</td><td>Home</td></tr>
<tr><td>Move cursor to end of line</td><td>End</td></tr>
<tr><td>Remove character to right of cursor</td><td>Delete</td></tr>
<tr><td>Remove character to left of cursor</td><td>Backspace</td></tr>
<tr><td>Same function as 'Home'</td><td>Control + A</td></tr>
<tr><td>Same function as 'End'</td><td>Control + E</td></tr>
<tr><td>Same function as 'Delete'</td><td>Control + D</td></tr>
<tr><td>Remove all characters from cursor to end of line</td><td>Control + K</td></tr>
<tr><td>Remove all characters from cursor to beginning of line</td><td>Control + U</td></tr>
<tr><td>Remove entire word to left of cursor</td><td>Control + W</td></tr>
<tr><td>Copy current line</td><td>Control + C</td></tr>
<tr><td>Cut current line</td><td>Control + X</td></tr>
<tr><td>Paste over current line</td><td>Control + V</td></tr>
<tr><td>Scroll up through previous commands one screen/page</td><td>Shift + PgUp</td></tr>
<tr><td>Scroll down through previous commands one screen/page</td><td>Shift + PgDown</td></tr>
<tr><td>Scroll up through previous commands one line</td><td>Shift + Up</td></tr>
<tr><td>Scroll down through previous commands one line</td><td>Shift + Down</td></tr>
<tr><td>Scroll to beginning of commands</td><td>Shift + Home</td></tr>
<tr><td>Scroll to end of commands</td><td>Shift + End</td></tr>
</table>
<p>You can also scroll with the mouse. Copy and paste is not yet supported.</p>
<p>You can also scroll with the mouse. Copy and paste is currently only supported for a complete line.</p>
<p>To see the available commands, enter "help". For extended help, type "help cmd",
where 'cmd' is the command you wish to know about. The available commands are listed

View File

@ -65,7 +65,10 @@ PhysicalKeyboardHandler::PhysicalKeyboardHandler(OSystem& system, EventHandler&
setDefaultMapping(Event::NoType, EventMode::kMenuMode, updateDefaults);
#ifdef GUI_SUPPORT
setDefaultMapping(Event::NoType, EventMode::kEditMode, updateDefaults);
#endif // DEBUG
#endif
#ifdef DEBUGGER_SUPPORT
setDefaultMapping(Event::NoType, EventMode::kPromptMode, updateDefaults);
#endif
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@ -195,6 +198,13 @@ void PhysicalKeyboardHandler::setDefaultMapping(Event::Type event, EventMode mod
setDefaultKey(item, event, EventMode::kEditMode);
break;
#endif
#ifdef DEBUGGER_SUPPORT
case EventMode::kPromptMode:
// Edit mode events are always set because they are not saved
for(const auto& item : FixedPromptMapping)
setDefaultKey(item, event, EventMode::kPromptMode);
break;
#endif
default:
break;
@ -470,7 +480,9 @@ bool PhysicalKeyboardHandler::addMapping(Event::Type event, EventMode mode,
myKeyMap.erase(EventMode::kKeypadMode, key, mod);
myKeyMap.erase(EventMode::kCompuMateMode, key, mod);
}
else if(evMode != EventMode::kMenuMode && evMode != EventMode::kEditMode)
else if(evMode != EventMode::kMenuMode
&& evMode != EventMode::kEditMode
&& evMode != EventMode::kPromptMode)
{
// erase identical mapping for kCommonMode
myKeyMap.erase(EventMode::kCommonMode, key, mod);
@ -899,7 +911,28 @@ PhysicalKeyboardHandler::FixedEditMapping = {
{Event::EndEdit, KBDK_KP_ENTER},
{Event::AbortEdit, KBDK_ESCAPE},
};
#endif
#endif // GUI_SUPPORT
#ifdef DEBUGGER_SUPPORT
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
PhysicalKeyboardHandler::EventMappingArray
PhysicalKeyboardHandler::FixedPromptMapping = {
{Event::UINavNext, KBDK_TAB},
{Event::UINavPrev, KBDK_TAB, KBDM_SHIFT},
{Event::UIPgUp, KBDK_PAGEUP},
{Event::UIPgUp, KBDK_PAGEUP, KBDM_SHIFT},
{Event::UIPgDown, KBDK_PAGEDOWN},
{Event::UIPgDown, KBDK_PAGEDOWN, KBDM_SHIFT},
{Event::UIHome, KBDK_HOME, KBDM_SHIFT},
{Event::UIEnd, KBDK_END, KBDM_SHIFT},
{Event::UIUp, KBDK_UP, KBDM_SHIFT},
{Event::UIDown, KBDK_DOWN, KBDM_SHIFT},
{Event::UILeft, KBDK_DOWN},
{Event::UIRight, KBDK_UP},
};
#endif // DEBUGGER_SUPPORT
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
PhysicalKeyboardHandler::EventMappingArray PhysicalKeyboardHandler::DefaultJoystickMapping = {

View File

@ -149,6 +149,9 @@ class PhysicalKeyboardHandler
static EventMappingArray DefaultMenuMapping;
#ifdef GUI_SUPPORT
static EventMappingArray FixedEditMapping;
#endif
#ifdef DEBUGGER_SUPPORT
static EventMappingArray FixedPromptMapping;
#endif
static EventMappingArray DefaultCommonMapping;
// Controller specific mappings

View File

@ -48,6 +48,7 @@ NLOHMANN_JSON_SERIALIZE_ENUM(JoyHatDir, {
NLOHMANN_JSON_SERIALIZE_ENUM(EventMode, {
{EventMode::kEditMode, "kEditMode"},
{EventMode::kPromptMode, "kPromptMode"},
{EventMode::kMenuMode, "kMenuMode"},
{EventMode::kEmulationMode, "kEmulationMode"},
{EventMode::kJoystickMode, "kJoystickMode"},

View File

@ -158,291 +158,158 @@ bool PromptWidget::handleText(char text)
bool PromptWidget::handleKeyDown(StellaKey key, StellaMod mod)
{
bool handled = true;
bool dirty = false;
bool dirty = true;
if(key != KBDK_TAB && !StellaModTest::isShift(mod))
_tabCount = -1;
switch(key)
// Uses normal edit events + special prompt events
Event::Type event = instance().eventHandler().eventForKey(EventMode::kEditMode, key, mod);
if(event == Event::NoType)
event = instance().eventHandler().eventForKey(EventMode::kPromptMode, key, mod);
switch(event)
{
case KBDK_RETURN:
case KBDK_KP_ENTER:
case Event::EndEdit:
{
nextLine();
assert(_promptEndPos >= _promptStartPos);
int len = _promptEndPos - _promptStartPos;
if (len > 0)
{
// Copy the user input to command
string command;
for (int i = 0; i < len; i++)
command += buffer(_promptStartPos + i) & 0x7f;
// Add the input to the history
addToHistory(command.c_str());
// Pass the command to the debugger, and print the result
string result = instance().debugger().run(command);
// This is a bit of a hack
// Certain commands remove the debugger dialog from underneath us,
// so we shouldn't print any messages
// Those commands will return '_EXIT_DEBUGGER' as their result
if(result == "_EXIT_DEBUGGER")
{
_exitedEarly = true;
return true;
}
else if(result == "_NO_PROMPT")
return true;
else if(result != "")
print(result + "\n");
}
if(execute())
return true;
printPrompt();
dirty = true;
break;
}
case KBDK_TAB:
{
// Tab completion: we complete either commands or labels, but not
// both at once.
if(_currentPos <= _promptStartPos)
break; // no input
scrollToCurrent();
int len = _promptEndPos - _promptStartPos;
if(_tabCount != -1)
len = int(strlen(_inputStr));
if(len > 255)
len = 255;
int lastDelimPos = -1;
char delimiter = '\0';
for(int i = 0; i < len; i++)
{
// copy the input at first tab press only
if(_tabCount == -1)
_inputStr[i] = buffer(_promptStartPos + i) & 0x7f;
// whitespace characters
if(strchr("{*@<> =[]()+-/&|!^~%", _inputStr[i]))
{
lastDelimPos = i;
delimiter = _inputStr[i];
}
}
if(_tabCount == -1)
_inputStr[len] = '\0';
StringList list;
if(lastDelimPos == -1)
// no delimiters, do only command completion:
instance().debugger().parser().getCompletions(_inputStr, list);
else
{
size_t strLen = len - lastDelimPos - 1;
// do not show ALL commands/labels without any filter as it makes no sense
if(strLen > 0)
{
// Special case for 'help' command
if(BSPF::startsWithIgnoreCase(_inputStr, "help"))
instance().debugger().parser().getCompletions(_inputStr + lastDelimPos + 1, list);
else
{
// we got a delimiter, so this must be a label or a function
const Debugger& dbg = instance().debugger();
dbg.cartDebug().getCompletions(_inputStr + lastDelimPos + 1, list);
dbg.getCompletions(_inputStr + lastDelimPos + 1, list);
}
}
}
if(list.size() < 1)
break;
sort(list.begin(), list.end());
if(StellaModTest::isShift(mod))
{
if(--_tabCount < 0)
_tabCount = int(list.size()) - 1;
}
else
_tabCount = (++_tabCount) % list.size();
nextLine();
_currentPos = _promptStartPos;
killLine(1); // kill whole line
// start with-autocompleted, fixed string...
for(int i = 0; i < lastDelimPos; i++)
putcharIntern(_inputStr[i]);
if(lastDelimPos > 0)
putcharIntern(delimiter);
// ...and add current autocompletion string
print(list[_tabCount]);
putcharIntern(' ');
_promptEndPos = _currentPos;
dirty = true;
case Event::UINavNext:
dirty = autoComplete(+1);
break;
}
case KBDK_BACKSPACE:
if (_currentPos > _promptStartPos)
case Event::UINavPrev:
dirty = autoComplete(-1);
break;
case Event::UILeft:
historyScroll(-1);
break;
case Event::UIRight:
historyScroll(+1);
break;
case Event::Backspace:
if(_currentPos > _promptStartPos)
killChar(-1);
scrollToCurrent();
dirty = true;
break;
case KBDK_DELETE:
case KBDK_KP_PERIOD: // actually the num delete
if(StellaModTest::isShift(mod))
textCut();
else
killChar(+1);
dirty = true;
case Event::Delete:
killChar(+1);
break;
case KBDK_PAGEUP:
if (StellaModTest::isShift(mod))
{
// Don't scroll up when at top of buffer
if(_scrollLine < _linesPerPage)
break;
_scrollLine -= _linesPerPage - 1;
if (_scrollLine < _firstLineInBuffer + _linesPerPage - 1)
_scrollLine = _firstLineInBuffer + _linesPerPage - 1;
updateScrollBuffer();
dirty = true;
}
case Event::MoveHome:
_currentPos = _promptStartPos;
break;
case KBDK_PAGEDOWN:
if (StellaModTest::isShift(mod))
{
// Don't scroll down when at bottom of buffer
if(_scrollLine >= _promptEndPos / _lineWidth)
break;
_scrollLine += _linesPerPage - 1;
if (_scrollLine > _promptEndPos / _lineWidth)
_scrollLine = _promptEndPos / _lineWidth;
updateScrollBuffer();
dirty = true;
}
case Event::MoveEnd:
_currentPos = _promptEndPos;
break;
case KBDK_HOME:
if (StellaModTest::isShift(mod))
{
_scrollLine = _firstLineInBuffer + _linesPerPage - 1;
updateScrollBuffer();
}
else
_currentPos = _promptStartPos;
dirty = true;
break;
case KBDK_END:
if (StellaModTest::isShift(mod))
{
_scrollLine = _promptEndPos / _lineWidth;
if (_scrollLine < _linesPerPage - 1)
_scrollLine = _linesPerPage - 1;
updateScrollBuffer();
}
else
_currentPos = _promptEndPos;
dirty = true;
break;
case KBDK_UP:
if (StellaModTest::isShift(mod))
{
if(_scrollLine <= _firstLineInBuffer + _linesPerPage - 1)
break;
_scrollLine -= 1;
updateScrollBuffer();
dirty = true;
}
else
historyScroll(+1);
break;
case KBDK_DOWN:
if (StellaModTest::isShift(mod))
{
// Don't scroll down when at bottom of buffer
if(_scrollLine >= _promptEndPos / _lineWidth)
break;
_scrollLine += 1;
updateScrollBuffer();
dirty = true;
}
else
historyScroll(-1);
break;
case KBDK_RIGHT:
if (_currentPos < _promptEndPos)
case Event::MoveRightChar:
if(_currentPos < _promptEndPos)
_currentPos++;
dirty = true;
break;
case KBDK_LEFT:
if (_currentPos > _promptStartPos)
case Event::MoveLeftChar:
if(_currentPos > _promptStartPos)
_currentPos--;
dirty = true;
break;
case KBDK_INSERT:
if(StellaModTest::isShift(mod))
{
textPaste();
dirty = true;
}
else if(StellaModTest::isControl(mod))
{
textCopy();
dirty = true;
}
else
handled = false;
case Event::DeleteRightWord:
killChar(+1);
break;
case Event::DeleteEnd:
killLine(+1);
break;
case Event::DeleteHome:
killLine(-1);
break;
case Event::DeleteLeftWord:
killWord();
break;
case Event::UIUp:
if(_scrollLine <= _firstLineInBuffer + _linesPerPage - 1)
break;
_scrollLine -= 1;
updateScrollBuffer();
break;
case Event::UIDown:
// Don't scroll down when at bottom of buffer
if(_scrollLine >= _promptEndPos / _lineWidth)
break;
_scrollLine += 1;
updateScrollBuffer();
break;
case Event::UIPgUp:
// Don't scroll up when at top of buffer
if(_scrollLine < _linesPerPage)
break;
_scrollLine -= _linesPerPage - 1;
if(_scrollLine < _firstLineInBuffer + _linesPerPage - 1)
_scrollLine = _firstLineInBuffer + _linesPerPage - 1;
updateScrollBuffer();
break;
case Event::UIPgDown:
// Don't scroll down when at bottom of buffer
if(_scrollLine >= _promptEndPos / _lineWidth)
break;
_scrollLine += _linesPerPage - 1;
if(_scrollLine > _promptEndPos / _lineWidth)
_scrollLine = _promptEndPos / _lineWidth;
updateScrollBuffer();
break;
case Event::UIHome:
_scrollLine = _firstLineInBuffer + _linesPerPage - 1;
updateScrollBuffer();
break;
case Event::UIEnd:
_scrollLine = _promptEndPos / _lineWidth;
if(_scrollLine < _linesPerPage - 1)
_scrollLine = _linesPerPage - 1;
updateScrollBuffer();
break;
//case Event::SelectAll:
// textSelectAll();
// break;
case Event::Cut:
textCut();
break;
case Event::Copy:
textCopy();
break;
case Event::Paste:
textPaste();
break;
default:
if (StellaModTest::isControl(mod))
{
specialKeys(key);
}
else if (StellaModTest::isAlt(mod))
{
// Placeholder only - this will never be reached
}
else
handled = false;
handled = false;
dirty = false;
break;
}
@ -546,46 +413,6 @@ int PromptWidget::getWidth() const
return _w + ScrollBarWidget::scrollBarWidth(_font);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void PromptWidget::specialKeys(StellaKey key)
{
bool handled = true;
switch(key)
{
case KBDK_D:
killChar(+1);
break;
case KBDK_K:
killLine(+1);
break;
case KBDK_U:
killLine(-1);
break;
case KBDK_W:
killWord();
break;
case KBDK_A:
textSelectAll();
break;
case KBDK_X:
textCut();
break;
case KBDK_C:
textCopy();
break;
case KBDK_V:
textPaste();
break;
default:
handled = false;
break;
}
if(handled)
setDirty();
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void PromptWidget::killChar(int direction)
{
@ -807,6 +634,135 @@ void PromptWidget::historyScroll(int direction)
setDirty();
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
bool PromptWidget::execute()
{
nextLine();
assert(_promptEndPos >= _promptStartPos);
int len = _promptEndPos - _promptStartPos;
if(len > 0)
{
// Copy the user input to command
string command;
for(int i = 0; i < len; i++)
command += buffer(_promptStartPos + i) & 0x7f;
// Add the input to the history
addToHistory(command.c_str());
// Pass the command to the debugger, and print the result
string result = instance().debugger().run(command);
// This is a bit of a hack
// Certain commands remove the debugger dialog from underneath us,
// so we shouldn't print any messages
// Those commands will return '_EXIT_DEBUGGER' as their result
if(result == "_EXIT_DEBUGGER")
{
_exitedEarly = true;
return true;
}
else if(result == "_NO_PROMPT")
return true;
else if(result != "")
print(result + "\n");
}
return false;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
bool PromptWidget::autoComplete(int direction)
{
// Tab completion: we complete either commands or labels, but not
// both at once.
if(_currentPos <= _promptStartPos)
return false; // no input
scrollToCurrent();
int len = _promptEndPos - _promptStartPos;
if(_tabCount != -1)
len = int(strlen(_inputStr));
if(len > 255)
len = 255;
int lastDelimPos = -1;
char delimiter = '\0';
for(int i = 0; i < len; i++)
{
// copy the input at first tab press only
if(_tabCount == -1)
_inputStr[i] = buffer(_promptStartPos + i) & 0x7f;
// whitespace characters
if(strchr("{*@<> =[]()+-/&|!^~%", _inputStr[i]))
{
lastDelimPos = i;
delimiter = _inputStr[i];
}
}
if(_tabCount == -1)
_inputStr[len] = '\0';
StringList list;
if(lastDelimPos == -1)
// no delimiters, do only command completion:
instance().debugger().parser().getCompletions(_inputStr, list);
else
{
size_t strLen = len - lastDelimPos - 1;
// do not show ALL commands/labels without any filter as it makes no sense
if(strLen > 0)
{
// Special case for 'help' command
if(BSPF::startsWithIgnoreCase(_inputStr, "help"))
instance().debugger().parser().getCompletions(_inputStr + lastDelimPos + 1, list);
else
{
// we got a delimiter, so this must be a label or a function
const Debugger& dbg = instance().debugger();
dbg.cartDebug().getCompletions(_inputStr + lastDelimPos + 1, list);
dbg.getCompletions(_inputStr + lastDelimPos + 1, list);
}
}
}
if(list.size() < 1)
return false;
sort(list.begin(), list.end());
if(direction < 0)
{
if(--_tabCount < 0)
_tabCount = int(list.size()) - 1;
}
else
_tabCount = (++_tabCount) % list.size();
nextLine();
_currentPos = _promptStartPos;
killLine(1); // kill whole line
// start with-autocompleted, fixed string...
for(int i = 0; i < lastDelimPos; i++)
putcharIntern(_inputStr[i]);
if(lastDelimPos > 0)
putcharIntern(delimiter);
// ...and add current autocompletion string
print(list[_tabCount]);
putcharIntern(' ');
_promptEndPos = _currentPos;
return true;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void PromptWidget::nextLine()
{
@ -971,29 +927,6 @@ string PromptWidget::saveBuffer(const FilesystemNode& file)
return "unable to save session";
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
string PromptWidget::getCompletionPrefix(const StringList& completions)
{
// Find the number of characters matching for each of the completions provided
for(uInt32 len = 1;; ++len)
{
for(uInt32 i = 0; i < completions.size(); ++i)
{
string s1 = completions[i];
if(s1.length() < len)
{
return s1.substr(0, len - 1);
}
string find = s1.substr(0, len);
for(uInt32 j = i + 1; j < completions.size(); ++j)
{
if(!BSPF::startsWithIgnoreCase(completions[j], find))
return s1.substr(0, len - 1);
}
}
}
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void PromptWidget::clearScreen()

View File

@ -64,7 +64,6 @@ class PromptWidget : public Widget, public CommandSender
void scrollToCurrent();
// Line editing
void specialKeys(StellaKey key);
void nextLine();
void killChar(int direction);
void killLine(int direction);
@ -80,6 +79,9 @@ class PromptWidget : public Widget, public CommandSender
// History
void historyScroll(int direction);
bool execute();
bool autoComplete(int direction);
void handleMouseDown(int x, int y, MouseButton b, int clickCount) override;
void handleMouseWheel(int x, int y, int direction) override;
bool handleText(char text) override;
@ -92,10 +94,6 @@ class PromptWidget : public Widget, public CommandSender
bool wantsFocus() const override { return true; }
void loadConfig() override;
private:
// Get the longest prefix (initially 's') that is in every string in the list
string getCompletionPrefix(const StringList& completions);
private:
enum {
kBufferSize = 32768,

View File

@ -84,6 +84,7 @@ enum class EventMode {
kCompuMateMode, // cannot be remapped
kCommonMode, // mapping common between controllers
kEditMode, // mapping used in editable widgets
kPromptMode, // extra mappings used in debugger's prompt widget
kNumModes
};