teratail header banner
teratail header banner
質問するログイン新規登録

回答編集履歴

1

コメントに対する追記

2020/09/14 00:42

投稿

nobonobo
nobonobo

スコア3367

answer CHANGED
@@ -1,3 +1,6 @@
1
+ 注意:ここに書いたのは連続する標準入力を一文字づつ処理する方法です。
2
+ ターミナルは基本の挙動がEnter押すごとに標準入力に投入します。
3
+
1
4
  ASCII文字しか扱わないなら1バイト長のbyteスライスを引数にしたReadでOKです。
2
5
  ```go
3
6
  b := []byte{0}
@@ -33,4 +36,58 @@
33
36
  fmt.Println(string(r))
34
37
  }
35
38
  }
39
+ ```
40
+
41
+ ## 追記
42
+
43
+ 質問者のコメントにあるような文字単位の入力をプログラムで受け取るには
44
+ OSのAPIを利用するか、以下のようにターミナルの動作モードを変えるしかなさそうです。
45
+ (以下の例はmacOSまたはLinux向けの方法です)
46
+ また、このモードではターミナルがCtrl+Cを受け取ってプロセスにSIGINTを送る機能も無効になるので
47
+ 止めるには外部からシグナルを投げるかプログラム自身に終了処理が必要です。
48
+
49
+ [https://play.golang.org/p/75GhzqTfV4_L](https://play.golang.org/p/75GhzqTfV4_L)
50
+ ```go
51
+ package main
52
+
53
+ import (
54
+ "bufio"
55
+ "fmt"
56
+ "io"
57
+ "log"
58
+ "os"
59
+ "os/exec"
60
+ "os/signal"
61
+ )
62
+
63
+ func main() {
64
+ cmd := exec.Command("stty", "raw")
65
+ cmd.Stdin = os.Stdin
66
+ cmd.Run()
67
+ defer func() {
68
+ cmd := exec.Command("stty", "-raw")
69
+ cmd.Stdin = os.Stdin
70
+ cmd.Run()
71
+ }()
72
+ reader := bufio.NewReader(os.Stdin)
73
+ sig := make(chan os.Signal, 1)
74
+ signal.Notify(sig, os.Interrupt)
75
+ go func() {
76
+ defer close(sig)
77
+ for {
78
+ r, _, err := reader.ReadRune()
79
+ if err != nil {
80
+ if err == io.EOF {
81
+ return
82
+ }
83
+ log.Fatal(err)
84
+ }
85
+ if r == 'q' {
86
+ break
87
+ }
88
+ fmt.Println(string(r))
89
+ }
90
+ }()
91
+ <-sig
92
+ }
36
93
  ```