macOS • Windows • Web • Ubuntu • tvOS • iOS • Android • Amazon Linux • watchOS

文档

SDGKeyboardDesign

SDGKeyboardDesign 提供了用于生成键盘布局的工具。

עַתָּה בּוֹא כׇתְבָהּ עַל־לוּחַ אִתָּם וְעַל־סֵפֶר חֻקָּהּ וּתְהִי לְיוֹם אַחֲרוֹן לָעַד עַד־עוֹלָם׃

现在去,为他们在平板上写下这些话,并将它们记录在书上,以便它们能存留到末日,直到永远。

―⁧יהוה⁩/Yehova

功能特性

使用示例

SDGKeyboardDesign 是一个 Swift 库,可以通过多种方式使用,但即使您不熟悉 Swift,您仍然应该能够通过修改以下示例为自己创建一个键盘。

  1. 请确保您已安装 Swift
  2. 下载 此仓库 的源代码。(点击“Clone or download”,然后点击“Download ZIP”。)
  3. 在 “Tests/SDGKeyboardDocumentationExampleTests/ReadMeExampleTests.swift” 下找到包含以下示例的文件,并根据您的需要进行编辑。
    • 不要忘记给 bundle 一个真实的名称。(如果您将其保留为 “Example Keyboards”,它将无法工作。)
  4. 打开终端并导航到仓库根目录。
    1. 输入 cd 和一个空格。
    2. 将主下载目录拖到终端中。
    3. 按回车键。提示符现在应包含目录名称。
  5. 将以下命令粘贴到终端中。完成后,Downloads 目录中应该会有一个键盘 bundle。
    swift test --filter ./testReadMeExample
  6. 将键盘 bundle 移动到 “System/Library/Keyboard Layouts”。(如果该目录尚不存在,请创建它。)
  7. 打开“系统偏好设置”,转到“键盘”,然后转到“输入法”,然后单击加号。您的自定义键盘应该在列表中的某个位置。
enum ExampleLocalization: String, InputLocalization {
  // This is the list of localizations to provide metadata for.
  case englishCanada = "en\u{2D}CA"
  case françaisCanada = "fr\u{2D}CA"
  // This localization will be used when none match the user’s preferences.
  static let fallbackLocalization = ExampleLocalization.englishCanada
}

let exampleLayout = KeyboardLayout<ExampleLocalization>(
  name: UserFacing<StrictString, ExampleLocalization>({ localization in
    switch localization {
    // These are the names of the keyboard layout in each localization.
    case .englishCanada:
      return "Example Keyboard"
    case .françaisCanada:
      return "Clavier exemple"
    }
  }),
  // This URL points to a local “.icns” file to use as the icon.
  icon: URL(fileURLWithPath: #filePath)  // Starts at this file.
    .deletingLastPathComponent()  // Backs out to the directory.
    .deletingLastPathComponent()  // Backs out another directory.
    .appendingPathComponent("Test Specifications")  // Enters a directory.
    .appendingPathComponent("MockIcon.icns"),  // Specifies the file.
  layers: [
    // These are the character arrangements.
    // (Keys can be safely omitted, and the order doesn’t matter.)
    .noModifiers: [
      .leftOutsideTopISO: "",

      .leftLittleTop: "1",
      .leftRingTop: "2",
      .leftMiddleTop: "3",
      .leftIndexTop: "4",
      .leftInsideTop: "5",

      .rightInsideTop: "٥",
      .rightIndexTop: "٤",
      .rightMiddleTop: "٣",
      .rightRingTop: "٢",
      .rightLittleTop: "١",

      .rightOutsideTop: "",
      .rightDoubleOutsideTop: "",

      .leftLittleUpper: "α",
      .leftRingUpper: "β",
      .leftMiddleUpper: "γ",
      .leftIndexUpper: "δ",
      .leftInsideUpper: "ε",

      .rightInsideUpper: "ה",
      .rightIndexUpper: "ד",
      .rightMiddleUpper: "ג",
      .rightRingUpper: "ב",
      .rightLittleUpper: "א",

      .rightOutsideUpper: "",
      .rightDoubleOutsideUpper: "",

      .leftLittleHome: "a",
      .leftRingHome: "b",
      .leftMiddleHome: "c",
      .leftIndexHome: "d",
      .leftInsideHome: "e",

      .rightInsideHome: "",
      .rightIndexHome: "丿",
      .rightMiddleHome: "",
      .rightRingHome: "",
      .rightLittleHome: "",

      .rightOutsideHome: "",
      .rightDoubleOutsideHomeISO_JIS_RightTripleOutsideUpperANSI: "",

      .leftOutsideLowerISO_LeftOutsideTopANSI_JIS: "",

      .leftLittleLower: "а",
      .leftRingLower: "б",
      .leftMiddleLower: "в",
      .leftIndexLower: "г",
      .leftInsideLower: "д",

      .rightInsideLower: "ر",
      .rightIndexLower: "د",
      .rightMiddleLower: "ج",
      .rightRingLower: "ب",
      .rightLittleLower: "ا",
    ],
    .shift: [
      // In many cases, uppercase characters will be inferred automatically.
      // But where it is ambiguous, or there is none, the shift layer can done manually.
      // Explicit entries will override automated values.
      .leftIndexHome: "I",
      .rightIndexHome: "",
    ],
    .option: [
      // These are the characters produced when option (⌥) is pressed.

      // Characters can be specified either directly...
      .leftIndexUpper: ".",  // ← A full stop.
      // ...or with their Unicode hexadecimal identifier:
      .leftInsideUpper: "\u{002E}",  // ← Also a full stop.

      // Unicode combining characters are better than dead keys...
      // (These are pressed after the character they modify.)
      .leftLittleHome: "\u{300}",  // ◌́ (acute)
      .leftRingHome: "\u{301}",  // ◌̀ (grave)
      .leftMiddleHome: "\u{302}",  // ◌̂ (circumflex)
      .leftIndexHome: "\u{303}",  // ◌̃ (tilde)
      .leftInsideHome: "\u{304}",  // ◌̄ (macron)

      // ...but dead keys are also possible when Unicode provides no combining character.
      // (These are pressed before the character they modify.)
      // Several common dead keys are provided.
      .rightInsideHome: DeadKey.stroke,
      .rightIndexHome: DeadKey.hook,
      .rightMiddleHome: DeadKey.descender,
      .rightRingHome: "Inversion",  // Custom. See below.

      // The symbol key allows inserting symbols by spelling their names.
      .rightDoubleOutsideHomeISO_JIS_RightTripleOutsideUpperANSI: Symbol.key,
    ],
    // More layers are available:
    .shiftOption: [
      .leftIndexHome: "⇧⌥"
    ],
    .capsLock: [
      .leftIndexHome: ""
    ],
    .capsLockShift: [
      .leftIndexHome: "⇪⇧"
    ],
    .capsLockOption: [
      .leftIndexHome: "⇪⌥"
    ],
    .capsLockShiftOption: [
      .leftIndexHome: "⇪⇧⌥"
    ],
    // Beware that rearranging the command layers affects hotkeys!
    // (If omitted, they will be automatically filled in according to ANSII.)
    .command: [
      .leftIndexHome: ""
    ],
    .shiftCommand: [
      .leftIndexHome: "⇧⌘"
    ],
  ],
  deadKeyLabels: DeadKey.defaultLabels.mergedByOverwriting(from: [
    // This specifies a label for the custom dead key above.
    "Inversion": ""
  ]),
  deadKeyMappings: DeadKey.defaultMappings.mergedByOverwriting(from: [
    // This specifies the mapping for the custom dead key above.
    "Inversion": [
      "a": "ɐ",
      "c": "ɔ",
      "e": "ə",
    ]
  ]),
  symbols: Symbol.defaultDictionary.mergedByOverwriting(from: [
    // This adds symbols to the default symbol key list (or overrides them).
    // To use the symbol key, press it once, then start typing the name of the symbol.
    // You won’t usually have to type the whole name.
    // It will be replaced with the symbol as soon as it is unambiguous.
    "euros": "",
    "dollars": "$",
    "roubles": "",
    "pounds": "£",
  ]),
  // This must be a unique identifier for the layout.
  uniqueIdentifier: 1_234_567,
  // This is the encoding that will be used in non‐Unicode applications.
  script: .latinWestern,
  // Optional. This requests that the operating system associate the layout with a particular language.
  targetedLanguage: .englishCanada
)

let exampleBundle = KeyboardLayoutBundle(
  name: UserFacing<StrictString, ExampleLocalization>({ localization in
    switch localization {
    // These are the names of the bundle in each localization.
    case .englishCanada:
      return "Example Keyboards"
    case .françaisCanada:
      return "Claviers exemples"
    }
  }),
  // A bundle can contain multiple layouts.
  // (But this only includes the layout above.)
  layouts: [exampleLayout],
  copyright: UserFacing<StrictString, ExampleLocalization>({ localization in
    switch localization {
    // These are the copyright notices in each localization.
    case .englishCanada:
      return "©0000 John Doe"
    case .françaisCanada:
      return "©0000 Jean Dupont"
    }
  }),
  // This is a unique identifier for the bundle.
  // (Apple recommends using reversed domain name notation.)
  bundleIdentifier: "tld.domain.example"
)

// This specifies the directory where the exported bundle should be saved.
let exportURL = URL(fileURLWithPath: NSHomeDirectory())
  .appendingPathComponent("Downloads")
// This exports the layout bundle.
try exampleBundle.generate(in: exportURL)

某些平台缺少某些功能。文档中出现的编译条件定义如下

.define("PLATFORM_LACKS_FOUNDATION_FILE_MANAGER", .when(platforms: [.wasi])),
.define(
  "PLATFORM_LACKS_FOUNDATION_PROPERTY_LIST_SERIALIZATION_DATA_FROM_PROPERTY_LIST_FORMAT_OPTIONS",
  .when(platforms: [.wasi])
),

导入

SDGKeyboardDesign 提供了一个库,用于 Swift Package Manager。

只需在 Package.swift 中将 SDGKeyboardDesign 添加为依赖项

let package = Package(
  name: "MyPackage",
  dependencies: [
    .package(
      url: "https://github.com/SDGGiesbrecht/SDGKeyboardDesign",
      from: Version(2, 1, 3)
    ),
  ],
  targets: [
    .target(
      name: "MyTarget",
      dependencies: [
        .product(name: "SDGKeyboardDesign", package: "SDGKeyboardDesign"),
      ]
    )
  ]
)

然后可以在源文件中导入该模块

import SDGKeyboardDesign

关于

SDGKeyboardDesign 项目由 Jeremy David Giesbrecht 维护。

如果 SDGKeyboardDesign 为您节省了金钱,请考虑将其中的一部分作为 捐赠

如果 SDGKeyboardDesign 为您节省了时间,请考虑将其中的一部分用于 回馈项目

Ἄξιος γὰρ ὁ ἐργάτης τοῦ μισθοῦ αὐτοῦ ἐστι.

因为工人理当得工价。

―‎ישוע/Yeshuʼa