Làm thế nào để đọc một ký tự đơn từ bảng điều khiển trong Java (khi người dùng nhập nó)?


110

Có cách nào dễ dàng để đọc một ký tự đơn lẻ từ bảng điều khiển khi người dùng nhập ký tự đó bằng Java không? Nó có khả thi không? Tôi đã thử với các phương pháp này nhưng tất cả chúng đều đợi người dùng nhấn phím enter :

char tmp = (char) System.in.read();
char tmp = (char) new InputStreamReader(System.in).read ();
char tmp = (char) System.console().reader().read();           // Java 6

Tôi bắt đầu nghĩ rằng System.in không biết người dùng nhập cho đến khi nhấn enter .

Câu trả lời:


57

Những gì bạn muốn làm là đặt bảng điều khiển ở chế độ "thô" (bỏ qua chỉnh sửa dòng và không yêu cầu phím enter) trái ngược với chế độ "nấu" (chỉnh sửa dòng bằng phím enter.) Trên hệ thống UNIX, lệnh 'stty' có thể thay đổi các chế độ.

Bây giờ, đối với Java ... hãy xem Đầu vào bảng điều khiển không chặn trong Python và Java . Trích:

Nếu chương trình của bạn phải dựa trên bảng điều khiển, bạn phải chuyển thiết bị đầu cuối ra khỏi chế độ dòng sang chế độ ký tự và nhớ khôi phục nó trước khi chương trình của bạn thoát. Không có cách di động nào để thực hiện việc này trên các hệ điều hành.

Một trong những gợi ý là sử dụng JNI. Một lần nữa, nó không phải là rất di động. Một gợi ý khác ở cuối luồng, và điểm chung với bài đăng ở trên, là xem xét việc sử dụng jCurses .


4
JCurses cũng không phải là di động cho lắm .... Từ JCurses README: "JCurses bao gồm hai phần: phần độc lập plattform và phần phụ thuộc plattform, bao gồm một thư viện được chia sẻ nguyên bản làm cho các hoạt động đầu vào và đầu ra nguyên thủy có sẵn cho phần đầu tiên . "
Ryan Fernandes

6
@RyanFernandes âm thanh khá cầm tay với tôi - công cụ duy nhất mà có thể chạy trên nhiều hệ điều (sử dụng phụ thuộc khác nhau)
Antoniossss

25

Bạn cần chuyển giao diện điều khiển của mình sang chế độ thô. Không có cách nào độc lập với nền tảng tích hợp sẵn để đến đó. jCurses có thể thú vị.

Trên hệ thống Unix, điều này có thể hoạt động:

String[] cmd = {"/bin/sh", "-c", "stty raw </dev/tty"};
Runtime.getRuntime().exec(cmd).waitFor();

Ví dụ: nếu bạn muốn tính đến thời gian giữa các lần nhấn phím, đây là mã mẫu để đạt được điều đó.


Làm việc tốt cho tôi trong Linux
MrSmith42

4
Hoạt động trên Mac. Bạn có thể muốn đề cập rằng stty cooked </dev/ttynên chạy khi chương trình cần trở lại chế độ đệm, và chắc chắn trước khi chương trình thoát.
Kelvin

15

Không có cách di động nào để đọc các ký tự thô từ bảng điều khiển Java.

Một số cách giải quyết phụ thuộc vào nền tảng đã được trình bày ở trên. Nhưng để thực sự di động, bạn phải từ bỏ chế độ bảng điều khiển và sử dụng chế độ cửa sổ, ví dụ như AWT hoặc Swing.


22
Tôi không hiểu tại sao ví dụ như Mono (hoặc CLR) có tính System.Console.ReadKeynăng hoạt động trên tất cả các nền tảng. Java cũng phân phối JVM và JRE cho mọi nền tảng với các thư viện và triển khai phụ thuộc vào nền tảng, vì vậy không có lý do gì.
Martin Macak

13

Tôi đã viết một lớp Java RawConsoleInput sử dụng JNA để gọi các chức năng hệ điều hành của Windows và Unix / Linux.

  • Trên Windows, nó sử dụng _kbhit()_getwch()từ msvcrt.dll.
  • Trên Unix, nó sử dụng tcsetattr()để chuyển bảng điều khiển sang chế độ không chuẩn, System.in.available()để kiểm tra xem dữ liệu có sẵn hay không và System.in.read()đọc các byte từ bảng điều khiển. A CharsetDecoderđược sử dụng để chuyển đổi byte thành ký tự.

Nó hỗ trợ đầu vào không chặn và chế độ trộn thô và đầu vào chế độ dòng bình thường.


Điều này đã được kiểm tra / kiểm tra căng thẳng đến mức nào?
Vụ kiện của Fund Monica

2
@QPaysTaxes Khó kiểm tra căng thẳng đối với đầu vào bảng điều khiển. Tôi nghĩ, trong trường hợp này, điều quan trọng hơn là kiểm tra nó trong các môi trường khác nhau (các phiên bản Windows / Linux khác nhau, 64/32 bit, Linux qua SSH, Telnet, cổng nối tiếp hoặc bảng điều khiển máy tính để bàn, v.v.). Cho đến nay tôi chỉ sử dụng nó trong các công cụ kiểm tra riêng tư của mình. Nhưng mã nguồn tương đối nhỏ so với các giải pháp khác (như JLine2 sử dụng Jansi). Vì vậy, không có nhiều điều có thể xảy ra sai sót. Tôi đã viết nó, vì JLine2 không hỗ trợ nhập ký tự đơn mà không bị chặn.
Christian d'Heureuse

Đó là những gì tôi có nghĩa là khi kiểm tra căng thẳng - nó có thể là từ sai; lỗi của tôi. Dù sao, tốt đẹp! Tôi đã đánh cắp ^ H ^ H ^ H ^ H ^ H ^ Đã sử dụng nó trong một dự án của tôi cho trường học và nó đã giúp ích rất nhiều.
Vụ kiện của Fund Monica vào

Này - lớp học này trông rất tuyệt. Tuy nhiên: Tôi không thể làm cho nó hoạt động được .. tôi phải sử dụng nó như thế nào? Tôi đã gặp phải việc chặn System.in cho đến khi tôi nhấn CTRL + D (trên Linux) và bây giờ tôi đã đọc về các chế độ bảng điều khiển và những thứ thích. Tôi nghĩ RawConsoleInput của bạn là thứ tôi đang tìm kiếm - nhưng làm cách nào để sử dụng nó?
Igor

@Igor Chỉ cần gọi RawConsoleInput.read (boolean) để đọc một ký tự bàn phím. Nó được ghi lại trong mã nguồn (RawConsoleInput.java).
Christian d'Heureuse

8

Sử dụng jline3 :

Thí dụ:

Terminal terminal = TerminalBuilder.builder()
    .jna(true)
    .system(true)
    .build();

// raw mode means we get keypresses rather than line buffered input
terminal.enterRawMode();
reader = terminal .reader();
...
int read = reader.read();
....
reader.close();
terminal.close();

Tôi thấy rằng các giải pháp dựa trên RawConsoleInput không hoạt động trên MacOS High Sierra; tuy nhiên, điều này hoạt động hoàn hảo.
RawToast

jline thực tế có tất cả những gì bạn cần để tạo một hệ thống giao diện điều khiển / thiết bị đầu cuối tương tác. Nó hoạt động tốt trên Linux. Để có ví dụ đầy đủ hơn, hãy xem tại: github.com/jline/jline3/blob/master/builtins/src/test/java/org/… . Nó có autocomplete, lịch sử, mặt nạ mật khẩu, vv
Lepe
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.