【问题标题】:Listening to stdin in Swift在 Swift 中收听标准输入
【发布时间】:2018-04-10 08:08:21
【问题描述】:

目前我正在尝试在我的 swift 应用程序中从命令行监听用户输入。

我知道readLine() 方法,但它并不真正适合我的需要。我想监听命令行中插入的数据。就像用户在终端内按下“向上键”一样。

类似在 Node.js 中可以做的事情:

stdin.on( 'data', function( key ){ 
    if (key === '\u0003' ) {
        process.exit();   
    }   // write the key to stdout all normal like                 

    process.stdout.write( key ); 
});

我尝试搜索,但在 Swift 中找不到与此等效的内容。我想也许是“输入流”的东西,但也没有找到合适的解决方案。

如果有人能给我一些关于如何在 Swift 中执行类似操作的提示,我将不胜感激。

【问题讨论】:

    标签: swift swift4 stdin


    【解决方案1】:

    通常标准输入会缓冲所有内容,直到输入换行符,这就是典型标准输入按行读取的原因:

    while let line = readLine() {
       print(line)
    }
    

    (按CTRL+D发送EOF,即结束输入)

    要真正单独读取每个字符,您需要进入原始模式,这意味着使用低级终端功能:

    // see https://stackoverflow.com/a/24335355/669586
    func initStruct<S>() -> S {
        let struct_pointer = UnsafeMutablePointer<S>.allocate(capacity: 1)
        let struct_memory = struct_pointer.pointee
        struct_pointer.deallocate() 
        return struct_memory
    }
    
    func enableRawMode(fileHandle: FileHandle) -> termios {
        var raw: termios = initStruct()
        tcgetattr(fileHandle.fileDescriptor, &raw)
    
        let original = raw
    
        raw.c_lflag &= ~(UInt(ECHO | ICANON))
        tcsetattr(fileHandle.fileDescriptor, TCSAFLUSH, &raw);
    
        return original
    }
    
    func restoreRawMode(fileHandle: FileHandle, originalTerm: termios) {
        var term = originalTerm
        tcsetattr(fileHandle.fileDescriptor, TCSAFLUSH, &term);
    }
    
    let stdIn = FileHandle.standardInput
    let originalTerm = enableRawMode(fileHandle: stdIn)
    
    var char: UInt8 = 0
    while read(stdIn.fileDescriptor, &char, 1) == 1 {
        if char == 0x04 { // detect EOF (Ctrl+D)
            break
        }
        print(char)
    }
    
    // It would be also nice to disable raw input when exiting the app.
    restoreRawMode(fileHandle: stdIn, originalTerm: originalTerm)
    

    参考https://viewsourcecode.org/snaptoken/kilo/02.enteringRawMode.html

    【讨论】:

    • 这是我想阅读标准输入的方式。谢谢你给我这个sn-p。不,我只需要解析箭头按键,因为它们会产生 3 个字符。此外,您的参考非常有帮助!
    • @grahan 我只翻译了基础知识,因为我不是终端专家。不过,在这个层面上,C 和 Swift 不会有太大区别。
    • 不用担心,您的回答给了我正确的方向。我想我可以完成剩下的。
    【解决方案2】:

    你可能想要FileHandle.standardInput

    类似:

    let file = FileHandle.standardInput
    
    while true {
        let data = file.availableData
        print("\(String(bytes: data, encoding: .utf8))")
    }
    

    将以我认为您想要的方式回显输入。关于小心输入的标准免责声明,这可能是一项危险的活动,清理您的输入等等。

    我不确定你会如何匹配特定的控制键和箭头键,但这是一个开始。

    【讨论】:

    • 感谢您的回答。我试过了,看起来很有希望!但我只在按下Enter 键时打印。所以我假设 availableData 只有在看到行尾时才会返回?每次击键后有什么要打印的吗?
    • @grahan 这不是标准输入的工作方式。如果你需要,你必须听键盘,而不是标准输入。这通常是使用readLine() 函数实现的。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-10-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多