You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在无框架的原生Swift(MacOS命令行环境)中获取键盘输入?

Hey there! I totally get where you're coming from—building a native Swift CLI Pong game without any UI frameworks, and needing to catch individual keystrokes (like detecting when "A" is pressed and outputting something like "A pressed") can feel tricky when most resources focus on SwiftUI or Cocoa. Let's fix that with a POSIX-based approach that works directly in the macOS command line, no extra frameworks required.

The Problem with Default CLI Input

By default, macOS terminals use line buffering—meaning your program won't receive any input until you hit Enter. We need to tweak terminal settings to disable line buffering and echo (so the key you press doesn't show up automatically in the terminal), then read characters one at a time.

Working Swift Implementation

Here's a complete, self-contained example that does exactly what you need:

import Foundation

// Store the original terminal settings to restore later
var originalTerminalSettings = termios()

func configureTerminalForRawInput() {
    // Grab the current terminal attributes
    tcgetattr(STDIN_FILENO, &originalTerminalSettings)
    var modifiedSettings = originalTerminalSettings
    
    // Disable line buffering (ICANON) and input echo (ECHO)
    modifiedSettings.c_lflag &= ~(UInt(ICANON) | UInt(ECHO))
    
    // Apply the new settings immediately
    tcsetattr(STDIN_FILENO, TCSANOW, &modifiedSettings)
}

func restoreTerminalSettings() {
    // Put the terminal back to its original state
    tcsetattr(STDIN_FILENO, TCSANOW, &originalTerminalSettings)
}

// Make sure we restore terminal settings when the program exits
atexit(restoreTerminalSettings)

// Set up the terminal for raw input
configureTerminalForRawInput()

print("Press any key (type 'q' to quit)...")

// Main loop to read keystrokes
while true {
    let inputChar = getchar()
    guard inputChar != EOF else { break }
    
    // Convert the raw C char to a Unicode scalar for easy handling
    if let key = UnicodeScalar(UInt32(inputChar)) {
        print("\(key) pressed")
        
        // Exit condition: press 'q' to quit
        if key == "q" {
            print("Exiting game...")
            break
        }
    }
}

How This Works

Let's break down the key parts:

  • configureTerminalForRawInput(): Uses POSIX tcgetattr and tcsetattr functions to modify terminal behavior. Disabling ICANON turns off line buffering (so we get keys immediately), and disabling ECHO stops the terminal from printing the key you press.
  • restoreTerminalSettings(): Critical! If we don't reset the terminal when the program exits, your terminal will stay in raw mode (no echo, no line buffering) which is annoying. We use atexit() to ensure this runs automatically when the program quits.
  • Main Loop: getchar() reads a single character from standard input. We convert it to a UnicodeScalar to easily check which key was pressed, then print your desired message.

Compiling & Running

Just save this code to a file (e.g., KeyReader.swift) then compile and run it with:

swiftc KeyReader.swift
./KeyReader

Bonus: Handling Special Keys (Optional)

If you later want to handle arrow keys, function keys, etc., note that these send multi-character escape sequences (e.g., the up arrow sends \u{1B}[A). You'd need to add logic to read and parse these sequences, but for basic letter keys like "A", the code above works perfectly.

内容的提问来源于stack exchange,提问作者Victor Morel

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.30 19:32:45