maartene
(Maarten Engels)
1
Hi everyone!
I'm working on a macOS Terminal / Linux app that needs to capture keyboard characters on a per key press basis. As its a command line app, I can't rely on NSWindows or NSEvent.
I found the getchar() c function that almost does what I need: it captures character presses, but only after pressing enter:
var c: Int32 = 0
while true {
c = getchar()
print("You entered: \(c)")
}
// output:
// a (+Enter)
// You entered: 97
Apparently this is default getchar() behavior.
Is there any built in function in Foundation or elsewhere that can capture a key press without needing to press enter?
stuchlej
(Mikoláš Stuchlík)
2
I'm no ANSI terminal expert myself, but it appears to me, like you want to read directly from stdin. There is probably some pipe available in Swift somewhere, but I found this article 2. Entering raw mode | Build Your Own Text Editor in C and I assume all the APIs are available in Swift.
If your use-case is some kind of TUI (terminal user interface), I would probably look for some good ncurses (libncurses) Swift wrappers.
Gero
(Gero Herkenrath)
3
Yup, it sounds like you're basically looking for raw mode.
Erica Sadun wrote an article that illustrates this. I haven't tried this myself as the last time I needed it was when I wrote terrible, terrible C code for a uni project...
1 Like
jeremyp
(Jeremy Pereira)
4
There's a Swift package called Linenoise that provides lightweight readline style functionality, also my not very well tested fork which handles UTF-8 better. These rely on reading raw terminal input as it arrives. By default getchar() buffers input until it reads a line ending.
The function Terminal.withRawMode() is the example code you need to put stdin into raw mode (and take it out again).
maartene
(Maarten Engels)
5
Took this approach. Doesn't work for (high) unicode characters such as emoji's, but good enough for now!
jeremyp
(Jeremy Pereira)
6
Apologies. I pointed you at the original code. My version can read UTF-8. Look at LNIO.swift
I wrote it to support a REPL for the Lambda Calculus when I found that the original version couldn't handle a λ character. I've just checked: it is fine with emoji too.
1 Like
tera
7
jeremyp
(Jeremy Pereira)
8
Well I'm pleased to report that my code is better than terminal then!
> (λx.x) 👨👨👧👦
1 reductions in 7.928e-06 = 126135.21695257317 reductions per second
: 👨👨👧👦
I'm not telling the whole truth though: After typing in the expression at the top, there were three spaces after the emoji and before the cursor. The library is erroneously assuming that each UTF-8 code point is exactly one Character/glyph.
maartene
(Maarten Engels)
9
I’ll give it a go! Thanks 