Skip to content

Commit

Permalink
Vim Keybindings (#115)
Browse files Browse the repository at this point in the history
* initial commit

* make keybinds more complete

* fix tab bug and some names

* remove log statement
  • Loading branch information
thkim1011 authored Sep 13, 2020
1 parent e42fb88 commit e0cec81
Show file tree
Hide file tree
Showing 4 changed files with 113 additions and 2 deletions.
29 changes: 28 additions & 1 deletion src/components/Game/Game.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ export default class Game extends Component {
this.state = {
pencilMode: false,
screenWidth: 0,
vimMode: false,
vimInsert: false,
};
}

Expand Down Expand Up @@ -132,6 +134,24 @@ export default class Game extends Component {
this.props.gameModel.reset(scope);
};

handleKeybind = (mode) => {
this.setState({
vimMode: mode === 'vim',
});
};

handleVimInsert = () => {
this.setState({
vimInsert: true,
});
};

handleVimNormal = () => {
this.setState({
vimInsert: false,
});
};

handleTogglePencil = () => {
this.setState({
pencilMode: !this.state.pencilMode,
Expand Down Expand Up @@ -232,6 +252,10 @@ export default class Game extends Component {
addPing={this.handleAddPing}
onPressEnter={this.handlePressEnter}
onPressPeriod={this.handlePressPeriod}
vimMode={this.state.vimMode}
vimInsert={this.state.vimInsert}
onVimInsert={this.handleVimInsert}
onVimNormal={this.handleVimNormal}
mobile={mobile}
pickups={this.props.pickups}
optimisticCounter={optimisticCounter}
Expand All @@ -244,7 +268,7 @@ export default class Game extends Component {
if (!this.game) return;
const {clock} = this.game;
const {mobile} = this.props;
const {pencilMode} = this.state;
const {pencilMode, vimMode, vimInsert} = this.state;
const {lastUpdated: startTime, totalTime: pausedTime, paused: isPaused} = clock;
return (
<Toolbar
Expand All @@ -254,12 +278,15 @@ export default class Game extends Component {
pausedTime={pausedTime}
isPaused={isPaused}
pencilMode={pencilMode}
vimMode={vimMode}
vimInsert={vimInsert}
onStartClock={this.handleStartClock}
onPauseClock={this.handlePauseClock}
onResetClock={this.handleResetClock}
onCheck={this.handleCheck}
onReveal={this.handleReveal}
onReset={this.handleReset}
onKeybind={this.handleKeybind}
onTogglePencil={this.handleTogglePencil}
onToggleChat={this.handleToggleChat}
onRefocus={this.handleRefocus}
Expand Down
59 changes: 58 additions & 1 deletion src/components/Player/GridControls.js
Original file line number Diff line number Diff line change
Expand Up @@ -154,12 +154,69 @@ export default class GridControls extends Component {
}
};

_handleKeyDownVim = (key, shiftKey) => {
const actionKeys = {
ArrowLeft: 'left',
ArrowUp: 'up',
ArrowDown: 'down',
ArrowRight: 'right',
Backspace: 'backspace',
'{del}': 'backspace',
Delete: 'delete',
Tab: 'tab',
' ': 'space',
'[': 'backward',
']': 'forward',
};

const normalModeActionKeys = {
h: 'left',
j: 'down',
k: 'up',
l: 'right',
x: 'delete',
};

const {onVimNormal, onVimInsert, vimInsert, onPressEnter, onPressPeriod} = this.props;
if (key in actionKeys) {
this.handleAction(actionKeys[key], shiftKey);
return true;
} else if (!vimInsert) {
if (key in normalModeActionKeys) {
this.handleAction(normalModeActionKeys[key], shiftKey);
} else if (key === 'w') {
this.selectNextClue(false);
} else if (key === 'b') {
this.selectNextClue(true);
} else if (key === 'i') {
onVimInsert && onVimInsert();
}
} else if (key === '.') {
onPressPeriod && onPressPeriod();
return true;
} else if (key === 'Enter') {
onPressEnter && onPressEnter();
return true;
} else if (key === 'Escape') {
onVimNormal && onVimNormal();
} else if (vimInsert && !this.props.frozen) {
const letter = key.toUpperCase();
if (this.validLetter(letter)) {
this.typeLetter(letter, shiftKey);
return true;
}
}
};

// takes in a Keyboard Event
handleKeyDown(ev) {
const {vimMode} = this.props;
const _handleKeyDown = vimMode ? this._handleKeyDownVim : this._handleKeyDown;

if (ev.target.tagName === 'INPUT' || ev.metaKey || ev.ctrlKey) {
return;
}
if (this._handleKeyDown(ev.key, ev.shiftKey)) {
if (_handleKeyDown(ev.key, ev.shiftKey)) {
ev.preventDefault();
ev.stopPropagation();
}
Expand Down
8 changes: 8 additions & 0 deletions src/components/Player/Player.js
Original file line number Diff line number Diff line change
Expand Up @@ -269,6 +269,10 @@ export default class Player extends Component {
mobile,
onPressEnter,
onPressPeriod,
vimMode,
vimInsert,
onVimNormal,
onVimInsert,
grid,
clues,
circles,
Expand Down Expand Up @@ -359,6 +363,10 @@ export default class Player extends Component {
ref="gridControls"
onPressEnter={onPressEnter}
onPressPeriod={onPressPeriod}
vimMode={vimMode}
vimInsert={vimInsert}
onVimInsert={onVimInsert}
onVimNormal={onVimNormal}
selected={selected}
direction={direction}
onSetDirection={this._setDirection}
Expand Down
19 changes: 19 additions & 0 deletions src/components/Toolbar/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,20 @@ export default class Toolbar extends Component {
);
}

renderKeybindMenu() {
const {vimMode, vimInsert} = this.props;
return (
<ActionMenu
label={vimMode ? `Vim${vimInsert ? ' (Insert)' : ''}` : 'Normal'}
onBlur={this.handleBlur}
actions={{
Normal: this.keybind.bind(this, 'normal'),
Vim: this.keybind.bind(this, 'vim'),
}}
/>
);
}

renderChatButton() {
return <MdChatBubble onClick={this.handleToggleChat} className="toolbar--chat" />;
}
Expand Down Expand Up @@ -207,6 +221,10 @@ export default class Toolbar extends Component {
this.props.onReset(scopeString);
}

keybind(mode) {
this.props.onKeybind(mode);
}

resetPuzzleAndTimer() {
this.reset('puzzle');
this.props.onResetClock();
Expand Down Expand Up @@ -253,6 +271,7 @@ export default class Toolbar extends Component {
{solved ? null : this.renderCheckMenu()}
{solved ? null : this.renderRevealMenu()}
<div className="toolbar--menu reset">{this.renderResetMenu()}</div>
{this.renderKeybindMenu()}
{this.renderPencil()}
{this.renderInfo()}
</div>
Expand Down

1 comment on commit e0cec81

@vercel
Copy link

@vercel vercel bot commented on e0cec81 Sep 13, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please sign in to comment.