message: Be sensible about handling up/down vs tab/tab-shift
  Fixes
diff: @@ -558,8 +558,27 @@ export default class MessageComposerInput extends React.Component {
  return true;
  }
  - selectHistory = async (completion, delta) => {
  - if (completion == null) {
  + onUpArrow = (e) => {
  + this.onVerticalArrow(e, true);
  + };
  +
  + onDownArrow = (e) => {
  + this.onVerticalArrow(e, false);
  + };
  +
  + onVerticalArrow = (e, up) => {
  + e.preventDefault();
  + // Select history only if we are not currently auto-completing
  + if (this.autocomplete.state.completionList.length === 0) {
  + return this.selectHistory(up);
  + } else {
  + return this.moveAutocompleteSelection(up);
  + }
  + };
  +
  + selectHistory = async (up) => {
  + const delta = up ? -1 : 1;
  +
  const newContent = this.historyManager.getItem(delta, this.state.isRichtextEnabled ? 'html' : 'markdown');
  if (!newContent) return false;
  let editorState = EditorState.push(
  @@ -578,35 +597,25 @@ export default class MessageComposerInput extends React.Component {
  this.setState({editorState});
  return true;
  - }
  - return await this.setDisplayedCompletion(completion);
  - };
  -
  - onUpArrow = async (e) => {
  - e.preventDefault();
  - const completion = this.autocomplete.onUpArrow();
  - return this.selectHistory(completion, -1);
  - };
  -
  - onDownArrow = async (e) => {
  - e.preventDefault();
  - const completion = this.autocomplete.onDownArrow();
  - return this.selectHistory(completion, -1);
  };
  - // tab and shift-tab are mapped to down and up arrow respectively
  onTab = async (e) => {
  - e.preventDefault(); // we *never* want tab's default to happen, but we do want up/down sometimes
  + e.preventDefault();
  if (this.autocomplete.state.completionList.length === 0) {
  - // XXX THIS IS EVIL. We should not be emulating other keys when pressing other keys
  - // This causes issues such as https://github.com/vector-im/riot-web/issues/4445
  + // Force completions to show for the text currently entered
  await this.autocomplete.forceComplete();
  - this.onDownArrow(e);
  + // Select the first item by moving "down"
  + await this.moveAutocompleteSelection(false);
  } else {
  - await (e.shiftKey ? this.onUpArrow : this.onDownArrow)(e);
  + await this.moveAutocompleteSelection(e.shiftKey);
  }
  };
  + moveAutocompleteSelection = (up) => {
  + const completion = up ? this.autocomplete.onUpArrow() : this.autocomplete.onDownArrow();
  + return this.setDisplayedCompletion(completion);
  + };
  +
  onEscape = async (e) => {
  e.preventDefault();
  if (this.autocomplete) {
  