docs: public static KeyStroke fromString(String keyStr) {
          String keyStrLC = keyStr.toLowerCase();
          KeyStroke k;
          if (keyStr.length() == 1) {
              k = new KeyStroke(KeyType.Character, keyStr.charAt(0), false, false, false);
          } else if (keyStr.startsWith("<") && keyStr.endsWith(">")) {
              if (keyStrLC.equals("<s-tab>")) {
                  k = new KeyStroke(KeyType.ReverseTab);
              } else if (keyStr.contains("-")) {
                  ArrayList<String> segments = new ArrayList<String>(Arrays.asList(keyStr.substring(1, keyStr.length() - 1).split("-")));
                  if (segments.size() < 2) {
                      throw new IllegalArgumentException("Invalid vim notation: " + keyStr);
                  }
                  String characterStr = segments.remove(segments.size() - 1);
                  boolean altPressed = false;
                  boolean ctrlPressed = false;
                  for (String modifier : segments) {
                      if ("c".equals(modifier.toLowerCase())) {
                          ctrlPressed = true;
                      } else if ("a".equals(modifier.toLowerCase())) {
                          altPressed = true;
                      } else if ("s".equals(modifier.toLowerCase())) {
                          characterStr = characterStr.toUpperCase();
                      }
                  }
                  k = new KeyStroke(characterStr.charAt(0), ctrlPressed, altPressed);
              } else {
                  if (keyStrLC.startsWith("<esc")) {
                      k = new KeyStroke(KeyType.Escape);
                  } else if (keyStrLC.equals("<cr>") || keyStrLC.equals("<enter>") || keyStrLC.equals("<return>")) {
                      k = new KeyStroke(KeyType.Enter);
                  } else if (keyStrLC.equals("<bs>")) {
                      k = new KeyStroke(KeyType.Backspace);
                  } else if (keyStrLC.equals("<tab>")) {
                      k = new KeyStroke(KeyType.Tab);
                  } else if (keyStrLC.equals("<space>")) {
                      k = new KeyStroke(' ', false, false);
                  } else if (keyStrLC.equals("<up>")) {
                      k = new KeyStroke(KeyType.ArrowUp);
                  } else if (keyStrLC.equals("<down>")) {
                      k = new KeyStroke(KeyType.ArrowDown);
                  } else if (keyStrLC.equals("<left>")) {
                      k = new KeyStroke(KeyType.ArrowLeft);
                  } else if (keyStrLC.equals("<right>")) {
                      k = new KeyStroke(KeyType.ArrowRight);
                  } else if (keyStrLC.equals("<insert>")) {
                      k = new KeyStroke(KeyType.Insert);
                  } else if (keyStrLC.equals("<del>")) {
                      k = new KeyStroke(KeyType.Delete);
                  } else if (keyStrLC.equals("<home>")) {
                      k = new KeyStroke(KeyType.Home);
                  } else if (keyStrLC.equals("<end>")) {
                      k = new KeyStroke(KeyType.End);
                  } else if (keyStrLC.equals("<pageup>")) {
                      k = new KeyStroke(KeyType.PageUp);
                  } else if (keyStrLC.equals("<pagedown>")) {
                      k = new KeyStroke(KeyType.PageDown);
                  } else if (keyStrLC.equals("<f1>")) {
                      k = new KeyStroke(KeyType.F1);
                  } else if (keyStrLC.equals("<f2>")) {
                      k = new KeyStroke(KeyType.F2);
                  } else if (keyStrLC.equals("<f3>")) {
                      k = new KeyStroke(KeyType.F3);
                  } else if (keyStrLC.equals("<f4>")) {
                      k = new KeyStroke(KeyType.F4);
                  } else if (keyStrLC.equals("<f5>")) {
                      k = new KeyStroke(KeyType.F5);
                  } else if (keyStrLC.equals("<f6>")) {
                      k = new KeyStroke(KeyType.F6);
                  } else if (keyStrLC.equals("<f7>")) {
                      k = new KeyStroke(KeyType.F7);
                  } else if (keyStrLC.equals("<f8>")) {
                      k = new KeyStroke(KeyType.F8);
                  } else if (keyStrLC.equals("<f9>")) {
                      k = new KeyStroke(KeyType.F9);
                  } else if (keyStrLC.equals("<f10>")) {
                      k = new KeyStroke(KeyType.F10);
                  } else if (keyStrLC.equals("<f11>")) {
                      k = new KeyStroke(KeyType.F11);
                  } else if (keyStrLC.equals("<f12>")) {
                      k = new KeyStroke(KeyType.F12);
                  } else {
                      throw new IllegalArgumentException("Invalid vim notation: " + keyStr);
                  }
              }
          } else {
              throw new IllegalArgumentException("Invalid vim notation: " + keyStr);
          }
          return k;
      }