chromium/ios/chrome/browser/keyboard/ui_bundled/UIKeyCommand+Chrome.mm

// Copyright 2015 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#import "ios/chrome/browser/keyboard/ui_bundled/UIKeyCommand+Chrome.h"

#import "ios/chrome/browser/keyboard/ui_bundled/key_command_actions.h"

namespace {

UIKeyModifierFlags None = 0;
UIKeyModifierFlags Command = UIKeyModifierCommand;
UIKeyModifierFlags Control = UIKeyModifierControl;
UIKeyModifierFlags AltCommand = UIKeyModifierAlternate | UIKeyModifierCommand;
UIKeyModifierFlags ShiftCommand = UIKeyModifierShift | UIKeyModifierCommand;
UIKeyModifierFlags AltShiftCommand =
    UIKeyModifierAlternate | UIKeyModifierShift | UIKeyModifierCommand;
UIKeyModifierFlags ControlShift = UIKeyModifierControl | UIKeyModifierShift;

}  // namespace

@implementation UIKeyCommand (Chrome)

#pragma mark - Specific Keyboard Commands

+ (UIKeyCommand*)cr_openNewTab {
  return [self cr_commandWithInput:@"t"
                     modifierFlags:Command
                            action:@selector(keyCommand_openNewTab)
                   titleIDAsString:@"IDS_IOS_KEYBOARD_NEW_TAB"];
}

+ (UIKeyCommand*)cr_openNewRegularTab {
  return [self keyCommandWithInput:@"n"
                     modifierFlags:Command
                            action:@selector(keyCommand_openNewRegularTab)];
}

+ (UIKeyCommand*)cr_openNewIncognitoTab {
  return [self cr_commandWithInput:@"n"
                     modifierFlags:ShiftCommand
                            action:@selector(keyCommand_openNewIncognitoTab)
                   titleIDAsString:@"IDS_IOS_KEYBOARD_NEW_INCOGNITO_TAB"];
}

+ (UIKeyCommand*)cr_openNewWindow {
  return [self cr_commandWithInput:@"n"
                     modifierFlags:AltCommand
                            action:@selector(keyCommand_openNewWindow)
                   titleIDAsString:@"IDS_IOS_KEYBOARD_NEW_WINDOW"];
}

+ (UIKeyCommand*)cr_openNewIncognitoWindow {
  return [self cr_commandWithInput:@"n"
                     modifierFlags:AltShiftCommand
                            action:@selector(keyCommand_openNewIncognitoWindow)
                   titleIDAsString:@"IDS_IOS_KEYBOARD_NEW_INCOGNITO_WINDOW"];
}

+ (UIKeyCommand*)cr_reopenLastClosedTab {
  return [self cr_commandWithInput:@"t"
                     modifierFlags:ShiftCommand
                            action:@selector(keyCommand_reopenLastClosedTab)
                   titleIDAsString:@"IDS_IOS_KEYBOARD_REOPEN_CLOSED_TAB"];
}

+ (UIKeyCommand*)cr_find {
  return [self cr_commandWithInput:@"f"
                     modifierFlags:Command
                            action:@selector(keyCommand_find)
                   titleIDAsString:@"IDS_IOS_KEYBOARD_FIND"];
}

+ (UIKeyCommand*)cr_findNext {
  return [self cr_commandWithInput:@"g"
                     modifierFlags:Command
                            action:@selector(keyCommand_findNext)
                   titleIDAsString:@"IDS_IOS_KEYBOARD_FIND_NEXT"];
}

+ (UIKeyCommand*)cr_findPrevious {
  return [self cr_commandWithInput:@"g"
                     modifierFlags:ShiftCommand
                            action:@selector(keyCommand_findPrevious)
                   titleIDAsString:@"IDS_IOS_KEYBOARD_FIND_PREVIOUS"];
}

+ (UIKeyCommand*)cr_openLocation {
  return [self cr_commandWithInput:@"l"
                     modifierFlags:Command
                            action:@selector(keyCommand_openLocation)
                   titleIDAsString:@"IDS_IOS_KEYBOARD_OPEN_LOCATION"];
}

+ (UIKeyCommand*)cr_closeTab {
  return [self cr_commandWithInput:@"w"
                     modifierFlags:Command
                            action:@selector(keyCommand_closeTab)
                   titleIDAsString:@"IDS_IOS_KEYBOARD_CLOSE_TAB"];
}

+ (UIKeyCommand*)cr_showNextTab {
  UIKeyCommand* keyCommand =
      [self cr_commandWithInput:@"\t"
                  modifierFlags:Control
                         action:@selector(keyCommand_showNextTab)
                titleIDAsString:@"IDS_IOS_KEYBOARD_NEXT_TAB"];
  keyCommand.wantsPriorityOverSystemBehavior = YES;
  return keyCommand;
}

+ (UIKeyCommand*)cr_showPreviousTab {
  UIKeyCommand* keyCommand =
      [self cr_commandWithInput:@"\t"
                  modifierFlags:ControlShift
                         action:@selector(keyCommand_showPreviousTab)
                titleIDAsString:@"IDS_IOS_KEYBOARD_PREVIOUS_TAB"];
  keyCommand.wantsPriorityOverSystemBehavior = YES;
  return keyCommand;
}

+ (UIKeyCommand*)cr_showNextTab_2 {
  // iOS 15+ supports -[UIKeyCommand allowsAutomaticMirroring], which is true
  // by default. It handles flipping the direction of braces.
  return [self keyCommandWithInput:@"}"
                     modifierFlags:Command
                            action:@selector(keyCommand_showNextTab)];
}

+ (UIKeyCommand*)cr_showPreviousTab_2 {
  // iOS 15+ supports -[UIKeyCommand allowsAutomaticMirroring], which is true
  // by default. It handles flipping the direction of braces.
  return [self keyCommandWithInput:@"{"
                     modifierFlags:Command
                            action:@selector(keyCommand_showPreviousTab)];
}

+ (UIKeyCommand*)cr_showNextTab_3 {
  // iOS 15+ supports -[UIKeyCommand allowsAutomaticMirroring], which is true
  // by default. It handles flipping the direction of arrows.
  return [self keyCommandWithInput:UIKeyInputRightArrow
                     modifierFlags:AltCommand
                            action:@selector(keyCommand_showNextTab)];
}

+ (UIKeyCommand*)cr_showPreviousTab_3 {
  // iOS 15+ supports -[UIKeyCommand allowsAutomaticMirroring], which is true
  // by default. It handles flipping the direction of arrows.
  return [self keyCommandWithInput:UIKeyInputLeftArrow
                     modifierFlags:AltCommand
                            action:@selector(keyCommand_showPreviousTab)];
}

+ (UIKeyCommand*)cr_showBookmarks {
  return [self cr_commandWithInput:@"b"
                     modifierFlags:AltCommand
                            action:@selector(keyCommand_showBookmarks)
                   titleIDAsString:@"IDS_IOS_KEYBOARD_SHOW_BOOKMARKS"];
}

+ (UIKeyCommand*)cr_addToBookmarks {
  return [self cr_commandWithInput:@"d"
                     modifierFlags:Command
                            action:@selector(keyCommand_addToBookmarks)
                   titleIDAsString:@"IDS_IOS_KEYBOARD_ADD_TO_BOOKMARKS"];
}

+ (UIKeyCommand*)cr_reload {
  return [self cr_commandWithInput:@"r"
                     modifierFlags:Command
                            action:@selector(keyCommand_reload)
                   titleIDAsString:@"IDS_IOS_KEYBOARD_RELOAD"];
}

+ (UIKeyCommand*)cr_back {
  // iOS 15+ supports -[UIKeyCommand allowsAutomaticMirroring], which is true
  // by default. It handles flipping the direction of brackets.
  return [self cr_commandWithInput:@"["
                     modifierFlags:Command
                            action:@selector(keyCommand_back)
                   titleIDAsString:@"IDS_IOS_KEYBOARD_HISTORY_BACK"];
}

+ (UIKeyCommand*)cr_forward {
  // iOS 15+ supports -[UIKeyCommand allowsAutomaticMirroring], which is true
  // by default. It handles flipping the direction of brackets.
  return [self cr_commandWithInput:@"]"
                     modifierFlags:Command
                            action:@selector(keyCommand_forward)
                   titleIDAsString:@"IDS_IOS_KEYBOARD_HISTORY_FORWARD"];
}

+ (UIKeyCommand*)cr_back_2 {
  // iOS 15+ supports -[UIKeyCommand allowsAutomaticMirroring], which is
  // true by default. It handles flipping the direction of arrows.
  return [self keyCommandWithInput:UIKeyInputLeftArrow
                     modifierFlags:Command
                            action:@selector(keyCommand_back)];
}

+ (UIKeyCommand*)cr_forward_2 {
  // iOS 15+ supports -[UIKeyCommand allowsAutomaticMirroring], which is
  // true by default. It handles flipping the direction of arrows.
  return [self keyCommandWithInput:UIKeyInputRightArrow
                     modifierFlags:Command
                            action:@selector(keyCommand_forward)];
}

+ (UIKeyCommand*)cr_showHistory {
  return [self cr_commandWithInput:@"y"
                     modifierFlags:Command
                            action:@selector(keyCommand_showHistory)
                   titleIDAsString:@"IDS_IOS_KEYBOARD_SHOW_HISTORY"];
}

+ (UIKeyCommand*)cr_voiceSearch {
  return [self cr_commandWithInput:@"."
                     modifierFlags:ShiftCommand
                            action:@selector(keyCommand_voiceSearch)
                   titleIDAsString:@"IDS_IOS_KEYBOARD_VOICE_SEARCH"];
}

+ (UIKeyCommand*)cr_close {
  return [self keyCommandWithInput:UIKeyInputEscape
                     modifierFlags:None
                            action:@selector(keyCommand_close)];
}

+ (UIKeyCommand*)cr_showSettings {
  return [self cr_commandWithInput:@","
                     modifierFlags:Command
                            action:@selector(keyCommand_showSettings)
                   titleIDAsString:@"IDS_IOS_KEYBOARD_SHOW_SETTINGS"];
}

+ (UIKeyCommand*)cr_stop {
  return [self cr_commandWithInput:@"."
                     modifierFlags:Command
                            action:@selector(keyCommand_stop)
                   titleIDAsString:@"IDS_IOS_KEYBOARD_STOP"];
}

+ (UIKeyCommand*)cr_showHelp {
  return [self cr_commandWithInput:@"?"
                     modifierFlags:AltCommand
                            action:@selector(keyCommand_showHelp)
                   titleIDAsString:@"IDS_IOS_KEYBOARD_SHOW_HELP"];
}

+ (UIKeyCommand*)cr_showDownloads {
  return [self cr_commandWithInput:@"l"
                     modifierFlags:AltCommand
                            action:@selector(keyCommand_showDownloads)
                   titleIDAsString:@"IDS_IOS_KEYBOARD_SHOW_DOWNLOADS"];
}

+ (UIKeyCommand*)cr_showDownloads_2 {
  return [self keyCommandWithInput:@"j"
                     modifierFlags:ShiftCommand
                            action:@selector(keyCommand_showDownloads)];
}

+ (UIKeyCommand*)cr_select1 {
  return [self keyCommandWithInput:@"1"
                     modifierFlags:Command
                            action:@selector(keyCommand_select1)];
}

+ (UIKeyCommand*)cr_select2 {
  return [self keyCommandWithInput:@"2"
                     modifierFlags:Command
                            action:@selector(keyCommand_select2)];
}

+ (UIKeyCommand*)cr_select3 {
  return [self keyCommandWithInput:@"3"
                     modifierFlags:Command
                            action:@selector(keyCommand_select3)];
}

+ (UIKeyCommand*)cr_select4 {
  return [self keyCommandWithInput:@"4"
                     modifierFlags:Command
                            action:@selector(keyCommand_select4)];
}

+ (UIKeyCommand*)cr_select5 {
  return [self keyCommandWithInput:@"5"
                     modifierFlags:Command
                            action:@selector(keyCommand_select5)];
}

+ (UIKeyCommand*)cr_select6 {
  return [self keyCommandWithInput:@"6"
                     modifierFlags:Command
                            action:@selector(keyCommand_select6)];
}

+ (UIKeyCommand*)cr_select7 {
  return [self keyCommandWithInput:@"7"
                     modifierFlags:Command
                            action:@selector(keyCommand_select7)];
}

+ (UIKeyCommand*)cr_select8 {
  return [self keyCommandWithInput:@"8"
                     modifierFlags:Command
                            action:@selector(keyCommand_select8)];
}

+ (UIKeyCommand*)cr_select9 {
  return [self cr_commandWithInput:@"9"
                     modifierFlags:Command
                            action:@selector(keyCommand_select9)
                   titleIDAsString:@"IDS_IOS_KEYBOARD_LAST_TAB"];
}

+ (UIKeyCommand*)cr_reportAnIssue {
  return [self cr_commandWithInput:@"i"
                     modifierFlags:ShiftCommand
                            action:@selector(keyCommand_reportAnIssue)
                   titleIDAsString:@"IDS_IOS_KEYBOARD_REPORT_AN_ISSUE"];
}

+ (UIKeyCommand*)cr_reportAnIssue_2 {
  return [self keyCommandWithInput:@"i"
                     modifierFlags:AltShiftCommand
                            action:@selector(keyCommand_reportAnIssue)];
}

+ (UIKeyCommand*)cr_addToReadingList {
  return [self cr_commandWithInput:@"d"
                     modifierFlags:ShiftCommand
                            action:@selector(keyCommand_addToReadingList)
                   titleIDAsString:@"IDS_IOS_KEYBOARD_ADD_TO_READING_LIST"];
}

+ (UIKeyCommand*)cr_showReadingList {
  return [self cr_commandWithInput:@"r"
                     modifierFlags:AltCommand
                            action:@selector(keyCommand_showReadingList)
                   titleIDAsString:@"IDS_IOS_KEYBOARD_SHOW_READING_LIST"];
}

+ (UIKeyCommand*)cr_goToTabGrid {
  return [self cr_commandWithInput:@"\\"
                     modifierFlags:ShiftCommand
                            action:@selector(keyCommand_goToTabGrid)
                   titleIDAsString:@"IDS_IOS_KEYBOARD_GO_TO_TAB_GRID"];
}

+ (UIKeyCommand*)cr_clearBrowsingData {
  return [self cr_commandWithInput:UIKeyInputDelete
                     modifierFlags:ShiftCommand
                            action:@selector(keyCommand_clearBrowsingData)
                   titleIDAsString:@"IDS_IOS_KEYBOARD_CLEAR_BROWSING_DATA"];
}

+ (UIKeyCommand*)cr_closeAll {
  return [self cr_commandWithInput:@"w"
                     modifierFlags:ShiftCommand
                            action:@selector(keyCommand_closeAll)
                   titleIDAsString:@"IDS_IOS_KEYBOARD_CLOSE_ALL"];
}

+ (UIKeyCommand*)cr_undo {
  UIKeyCommand* keyCommand =
      [self keyCommandWithInput:@"z"
                  modifierFlags:Command
                         action:@selector(keyCommand_undo)];
  keyCommand.wantsPriorityOverSystemBehavior = YES;
  return keyCommand;
}

#pragma mark - Symbolic Description

- (NSString*)cr_symbolicDescription {
  NSMutableString* description = [NSMutableString string];

  if (self.modifierFlags & UIKeyModifierNumericPad) {
    [description appendString:@"Num lock "];
  }
  if (self.modifierFlags & UIKeyModifierControl) {
    [description appendString:@"⌃"];
  }
  if (self.modifierFlags & UIKeyModifierAlternate) {
    [description appendString:@"⌥"];
  }
  if (self.modifierFlags & UIKeyModifierShift) {
    [description appendString:@"⇧"];
  }
  if (self.modifierFlags & UIKeyModifierAlphaShift) {
    [description appendString:@"⇪"];
  }
  if (self.modifierFlags & UIKeyModifierCommand) {
    [description appendString:@"⌘"];
  }

  if ([self.input isEqualToString:UIKeyInputDelete]) {
    [description appendString:@"⌫"];
  } else if ([self.input isEqualToString:@"\r"]) {
    [description appendString:@"↵"];
  } else if ([self.input isEqualToString:@"\t"]) {
    [description appendString:@"⇥"];
  } else if ([self.input isEqualToString:UIKeyInputUpArrow]) {
    [description appendString:@"↑"];
  } else if ([self.input isEqualToString:UIKeyInputDownArrow]) {
    [description appendString:@"↓"];
  } else if ([self.input isEqualToString:UIKeyInputLeftArrow]) {
    [description appendString:@"←"];
  } else if ([self.input isEqualToString:UIKeyInputRightArrow]) {
    [description appendString:@"→"];
  } else if ([self.input isEqualToString:UIKeyInputEscape]) {
    [description appendString:@"⎋"];
  } else if ([self.input isEqualToString:@" "]) {
    [description appendString:@"␣"];
  } else {
    [description appendString:[self.input uppercaseString]];
  }
  return description;
}

#pragma mark - Private

// The title ID string is used as a key to NSLocalizedString because key
// commands can be requested by the OS very early on, before the resource bundle
// of the localized strings is loaded.
+ (instancetype)cr_commandWithInput:(NSString*)input
                      modifierFlags:(UIKeyModifierFlags)modifierFlags
                             action:(SEL)action
                    titleIDAsString:(NSString*)messageID {
  UIKeyCommand* keyCommand =
      [self commandWithTitle:NSLocalizedString(messageID, @"")
                       image:nil
                      action:action
                       input:input
               modifierFlags:modifierFlags
                propertyList:nil];
  keyCommand.discoverabilityTitle = keyCommand.title;
  return keyCommand;
}

@end