├── .gitignore
├── LICENSE
├── README.md
├── pom.xml
└── src
└── main
├── java
└── jp
│ └── uphy
│ └── javafx
│ ├── console
│ ├── ConsoleApplication.java
│ ├── ConsoleView.java
│ ├── KeyBindingUtils.java
│ └── TextInputControlStream.java
│ └── example
│ ├── JavaFXMyCliApplication.java
│ └── MyCliApplication.java
└── resources
└── jp
└── uphy
└── javafx
└── console
└── style.css
/.gitignore:
--------------------------------------------------------------------------------
1 | ### OSX template
2 | .DS_Store
3 | .AppleDouble
4 | .LSOverride
5 |
6 | # Icon must end with two \r
7 | Icon
8 |
9 | # Thumbnails
10 | ._*
11 |
12 | # Files that might appear in the root of a volume
13 | .DocumentRevisions-V100
14 | .fseventsd
15 | .Spotlight-V100
16 | .TemporaryItems
17 | .Trashes
18 | .VolumeIcon.icns
19 |
20 | # Directories potentially created on remote AFP share
21 | .AppleDB
22 | .AppleDesktop
23 | Network Trash Folder
24 | Temporary Items
25 | .apdisk
26 | ### Emacs template
27 | # -*- mode: gitignore; -*-
28 | *~
29 | \#*\#
30 | /.emacs.desktop
31 | /.emacs.desktop.lock
32 | *.elc
33 | auto-save-list
34 | tramp
35 | .\#*
36 |
37 | # Org-mode
38 | .org-id-locations
39 | *_archive
40 |
41 | # flymake-mode
42 | *_flymake.*
43 |
44 | # eshell files
45 | /eshell/history
46 | /eshell/lastdir
47 |
48 | # elpa packages
49 | /elpa/
50 |
51 | # reftex files
52 | *.rel
53 |
54 | # AUCTeX auto folder
55 | /auto/
56 |
57 | # cask packages
58 | .cask/
59 |
60 | # Created by .ignore support plugin (hsz.mobi)
61 | ### Eclipse template
62 | *.pydevproject
63 | .metadata
64 | .gradle
65 | bin/
66 | tmp/
67 | *.tmp
68 | *.bak
69 | *.swp
70 | *~.nib
71 | local.properties
72 | .settings/
73 | .loadpath
74 |
75 | # Eclipse Core
76 | .project
77 |
78 | # External tool builders
79 | .externalToolBuilders/
80 |
81 | # Locally stored "Eclipse launch configurations"
82 | *.launch
83 |
84 | # CDT-specific
85 | .cproject
86 |
87 | # JDT-specific (Eclipse Java Development Tools)
88 | .classpath
89 |
90 | # Java annotation processor (APT)
91 | .factorypath
92 |
93 | # PDT-specific
94 | .buildpath
95 |
96 | # sbteclipse plugin
97 | .target
98 |
99 | # TeXlipse plugin
100 | .texlipse
101 | ### JetBrains template
102 | # Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio
103 |
104 | *.iml
105 |
106 | ## Directory-based project format:
107 | .idea/
108 | # if you remove the above rule, at least ignore the following:
109 |
110 | # User-specific stuff:
111 | # .idea/workspace.xml
112 | # .idea/tasks.xml
113 | # .idea/dictionaries
114 |
115 | # Sensitive or high-churn files:
116 | # .idea/dataSources.ids
117 | # .idea/dataSources.xml
118 | # .idea/sqlDataSources.xml
119 | # .idea/dynamic.xml
120 | # .idea/uiDesigner.xml
121 |
122 | # Gradle:
123 | # .idea/gradle.xml
124 | # .idea/libraries
125 |
126 | # Mongo Explorer plugin:
127 | # .idea/mongoSettings.xml
128 |
129 | ## File-based project format:
130 | *.ipr
131 | *.iws
132 |
133 | ## Plugin-specific files:
134 |
135 | # IntelliJ
136 | /out/
137 |
138 | # mpeltonen/sbt-idea plugin
139 | .idea_modules/
140 |
141 | # JIRA plugin
142 | atlassian-ide-plugin.xml
143 |
144 | # Crashlytics plugin (for Android Studio and IntelliJ)
145 | com_crashlytics_export_strings.xml
146 | crashlytics.properties
147 | crashlytics-build.properties
148 | ### Maven template
149 | target/
150 | pom.xml.tag
151 | pom.xml.releaseBackup
152 | pom.xml.versionsBackup
153 | pom.xml.next
154 | release.properties
155 | dependency-reduced-pom.xml
156 | buildNumber.properties
157 | .mvn/timing.properties
158 | ### Java template
159 | *.class
160 |
161 | # Mobile Tools for Java (J2ME)
162 | .mtj.tmp/
163 |
164 | # Package Files #
165 | *.jar
166 | *.war
167 | *.ear
168 |
169 | # virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
170 | hs_err_pid*
171 |
172 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Apache License
2 | Version 2.0, January 2004
3 | http://www.apache.org/licenses/
4 |
5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
6 |
7 | 1. Definitions.
8 |
9 | "License" shall mean the terms and conditions for use, reproduction,
10 | and distribution as defined by Sections 1 through 9 of this document.
11 |
12 | "Licensor" shall mean the copyright owner or entity authorized by
13 | the copyright owner that is granting the License.
14 |
15 | "Legal Entity" shall mean the union of the acting entity and all
16 | other entities that control, are controlled by, or are under common
17 | control with that entity. For the purposes of this definition,
18 | "control" means (i) the power, direct or indirect, to cause the
19 | direction or management of such entity, whether by contract or
20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the
21 | outstanding shares, or (iii) beneficial ownership of such entity.
22 |
23 | "You" (or "Your") shall mean an individual or Legal Entity
24 | exercising permissions granted by this License.
25 |
26 | "Source" form shall mean the preferred form for making modifications,
27 | including but not limited to software source code, documentation
28 | source, and configuration files.
29 |
30 | "Object" form shall mean any form resulting from mechanical
31 | transformation or translation of a Source form, including but
32 | not limited to compiled object code, generated documentation,
33 | and conversions to other media types.
34 |
35 | "Work" shall mean the work of authorship, whether in Source or
36 | Object form, made available under the License, as indicated by a
37 | copyright notice that is included in or attached to the work
38 | (an example is provided in the Appendix below).
39 |
40 | "Derivative Works" shall mean any work, whether in Source or Object
41 | form, that is based on (or derived from) the Work and for which the
42 | editorial revisions, annotations, elaborations, or other modifications
43 | represent, as a whole, an original work of authorship. For the purposes
44 | of this License, Derivative Works shall not include works that remain
45 | separable from, or merely link (or bind by name) to the interfaces of,
46 | the Work and Derivative Works thereof.
47 |
48 | "Contribution" shall mean any work of authorship, including
49 | the original version of the Work and any modifications or additions
50 | to that Work or Derivative Works thereof, that is intentionally
51 | submitted to Licensor for inclusion in the Work by the copyright owner
52 | or by an individual or Legal Entity authorized to submit on behalf of
53 | the copyright owner. For the purposes of this definition, "submitted"
54 | means any form of electronic, verbal, or written communication sent
55 | to the Licensor or its representatives, including but not limited to
56 | communication on electronic mailing lists, source code control systems,
57 | and issue tracking systems that are managed by, or on behalf of, the
58 | Licensor for the purpose of discussing and improving the Work, but
59 | excluding communication that is conspicuously marked or otherwise
60 | designated in writing by the copyright owner as "Not a Contribution."
61 |
62 | "Contributor" shall mean Licensor and any individual or Legal Entity
63 | on behalf of whom a Contribution has been received by Licensor and
64 | subsequently incorporated within the Work.
65 |
66 | 2. Grant of Copyright License. Subject to the terms and conditions of
67 | this License, each Contributor hereby grants to You a perpetual,
68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
69 | copyright license to reproduce, prepare Derivative Works of,
70 | publicly display, publicly perform, sublicense, and distribute the
71 | Work and such Derivative Works in Source or Object form.
72 |
73 | 3. Grant of Patent License. Subject to the terms and conditions of
74 | this License, each Contributor hereby grants to You a perpetual,
75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
76 | (except as stated in this section) patent license to make, have made,
77 | use, offer to sell, sell, import, and otherwise transfer the Work,
78 | where such license applies only to those patent claims licensable
79 | by such Contributor that are necessarily infringed by their
80 | Contribution(s) alone or by combination of their Contribution(s)
81 | with the Work to which such Contribution(s) was submitted. If You
82 | institute patent litigation against any entity (including a
83 | cross-claim or counterclaim in a lawsuit) alleging that the Work
84 | or a Contribution incorporated within the Work constitutes direct
85 | or contributory patent infringement, then any patent licenses
86 | granted to You under this License for that Work shall terminate
87 | as of the date such litigation is filed.
88 |
89 | 4. Redistribution. You may reproduce and distribute copies of the
90 | Work or Derivative Works thereof in any medium, with or without
91 | modifications, and in Source or Object form, provided that You
92 | meet the following conditions:
93 |
94 | (a) You must give any other recipients of the Work or
95 | Derivative Works a copy of this License; and
96 |
97 | (b) You must cause any modified files to carry prominent notices
98 | stating that You changed the files; and
99 |
100 | (c) You must retain, in the Source form of any Derivative Works
101 | that You distribute, all copyright, patent, trademark, and
102 | attribution notices from the Source form of the Work,
103 | excluding those notices that do not pertain to any part of
104 | the Derivative Works; and
105 |
106 | (d) If the Work includes a "NOTICE" text file as part of its
107 | distribution, then any Derivative Works that You distribute must
108 | include a readable copy of the attribution notices contained
109 | within such NOTICE file, excluding those notices that do not
110 | pertain to any part of the Derivative Works, in at least one
111 | of the following places: within a NOTICE text file distributed
112 | as part of the Derivative Works; within the Source form or
113 | documentation, if provided along with the Derivative Works; or,
114 | within a display generated by the Derivative Works, if and
115 | wherever such third-party notices normally appear. The contents
116 | of the NOTICE file are for informational purposes only and
117 | do not modify the License. You may add Your own attribution
118 | notices within Derivative Works that You distribute, alongside
119 | or as an addendum to the NOTICE text from the Work, provided
120 | that such additional attribution notices cannot be construed
121 | as modifying the License.
122 |
123 | You may add Your own copyright statement to Your modifications and
124 | may provide additional or different license terms and conditions
125 | for use, reproduction, or distribution of Your modifications, or
126 | for any such Derivative Works as a whole, provided Your use,
127 | reproduction, and distribution of the Work otherwise complies with
128 | the conditions stated in this License.
129 |
130 | 5. Submission of Contributions. Unless You explicitly state otherwise,
131 | any Contribution intentionally submitted for inclusion in the Work
132 | by You to the Licensor shall be under the terms and conditions of
133 | this License, without any additional terms or conditions.
134 | Notwithstanding the above, nothing herein shall supersede or modify
135 | the terms of any separate license agreement you may have executed
136 | with Licensor regarding such Contributions.
137 |
138 | 6. Trademarks. This License does not grant permission to use the trade
139 | names, trademarks, service marks, or product names of the Licensor,
140 | except as required for reasonable and customary use in describing the
141 | origin of the Work and reproducing the content of the NOTICE file.
142 |
143 | 7. Disclaimer of Warranty. Unless required by applicable law or
144 | agreed to in writing, Licensor provides the Work (and each
145 | Contributor provides its Contributions) on an "AS IS" BASIS,
146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
147 | implied, including, without limitation, any warranties or conditions
148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
149 | PARTICULAR PURPOSE. You are solely responsible for determining the
150 | appropriateness of using or redistributing the Work and assume any
151 | risks associated with Your exercise of permissions under this License.
152 |
153 | 8. Limitation of Liability. In no event and under no legal theory,
154 | whether in tort (including negligence), contract, or otherwise,
155 | unless required by applicable law (such as deliberate and grossly
156 | negligent acts) or agreed to in writing, shall any Contributor be
157 | liable to You for damages, including any direct, indirect, special,
158 | incidental, or consequential damages of any character arising as a
159 | result of this License or out of the use or inability to use the
160 | Work (including but not limited to damages for loss of goodwill,
161 | work stoppage, computer failure or malfunction, or any and all
162 | other commercial damages or losses), even if such Contributor
163 | has been advised of the possibility of such damages.
164 |
165 | 9. Accepting Warranty or Additional Liability. While redistributing
166 | the Work or Derivative Works thereof, You may choose to offer,
167 | and charge a fee for, acceptance of support, warranty, indemnity,
168 | or other liability obligations and/or rights consistent with this
169 | License. However, in accepting such obligations, You may act only
170 | on Your own behalf and on Your sole responsibility, not on behalf
171 | of any other Contributor, and only if You agree to indemnify,
172 | defend, and hold each Contributor harmless for any liability
173 | incurred by, or claims asserted against, such Contributor by reason
174 | of your accepting any such warranty or additional liability.
175 |
176 | END OF TERMS AND CONDITIONS
177 |
178 | APPENDIX: How to apply the Apache License to your work.
179 |
180 | To apply the Apache License to your work, attach the following
181 | boilerplate notice, with the fields enclosed by brackets "[]"
182 | replaced with your own identifying information. (Don't include
183 | the brackets!) The text should be enclosed in the appropriate
184 | comment syntax for the file format. We also recommend that a
185 | file or class name and description of purpose be included on the
186 | same "printed page" as the copyright notice for easier
187 | identification within third-party archives.
188 |
189 | Copyright [yyyy] [name of copyright owner]
190 |
191 | Licensed under the Apache License, Version 2.0 (the "License");
192 | you may not use this file except in compliance with the License.
193 | You may obtain a copy of the License at
194 |
195 | http://www.apache.org/licenses/LICENSE-2.0
196 |
197 | Unless required by applicable law or agreed to in writing, software
198 | distributed under the License is distributed on an "AS IS" BASIS,
199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
200 | See the License for the specific language governing permissions and
201 | limitations under the License.
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # JavaFX Console
2 |
3 | This library provides JavaFX console view class "jp.uphy.javafx.console.ConsoleView".
4 | The ConsoleView provides PrintStream and InputStream which linked to the console text.
5 | Therefore, you can replace System.in and System.out with console view.
6 |
7 | Also, you can wrap CLI application with JavaFX console.
8 | It is convenient when you use javapackager command to your CLI applications.
9 |
10 | # Replacing System.in and System.out with Console View
11 |
12 | ```
13 | final ConsoleView console = new ConsoleView();
14 |
15 | System.setOut(console.getOut());
16 | System.setIn(console.getIn());
17 | System.setErr(console.getOut());
18 | ```
19 |
20 | # Wrapping your CLI Application
21 |
22 | ```
23 | public class CliApplicationWrapper extends ConsoleApplication {
24 |
25 | @Override
26 | protected void invokeMain(final String[] args) {
27 | YourCLIApplication.main(args);
28 | }
29 |
30 | public static void main(String[] args) {
31 | launch(args);
32 | }
33 |
34 | }
35 | ```
--------------------------------------------------------------------------------
/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 | 4.0.0
6 |
7 | jp.uphy.javafx
8 | javafx-console
9 | 1.0-SNAPSHOT
10 |
11 |
12 | UTF-8
13 | 1.8
14 | 1.8
15 |
16 |
17 |
18 |
19 | demo
20 |
21 |
22 |
23 | com.zenjava
24 | javafx-maven-plugin
25 | 8.1.4
26 |
27 | jp.uphy.javafx.example.JavaFXMyCliApplication
28 | jpe
29 | uphy.jp
30 | true
31 |
32 |
33 |
34 | create-jfxjar
35 | package
36 |
37 | build-jar
38 |
39 |
40 |
41 | create-native
42 | package
43 |
44 | build-native
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
--------------------------------------------------------------------------------
/src/main/java/jp/uphy/javafx/console/ConsoleApplication.java:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright (C) 2015 uphy.jp
3 | * Licensed under the Apache License, Version 2.0 (the "License");
4 | * you may not use this file except in compliance with the License.
5 | * You may obtain a copy of the License at
6 | * http://www.apache.org/licenses/LICENSE-2.0
7 | * Unless required by applicable law or agreed to in writing, software
8 | * distributed under the License is distributed on an "AS IS" BASIS,
9 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
10 | * See the License for the specific language governing permissions and
11 | * limitations under the License.
12 | */
13 | package jp.uphy.javafx.console;
14 |
15 | import javafx.application.Application;
16 | import javafx.application.Platform;
17 | import javafx.scene.Scene;
18 | import javafx.stage.Stage;
19 |
20 | import java.io.BufferedReader;
21 | import java.io.IOException;
22 | import java.io.InputStreamReader;
23 | import java.net.URL;
24 |
25 |
26 | /**
27 | * @author Yuhi Ishikura
28 | */
29 | public abstract class ConsoleApplication extends Application {
30 |
31 | private boolean pauseBeforeExit = true;
32 | private Stage stage;
33 |
34 | @Override
35 | public final void start(final Stage primaryStage) throws Exception {
36 | this.stage = primaryStage;
37 | final String[] args = getParameters().getRaw().toArray(new String[0]);
38 | final ConsoleView console = new ConsoleView();
39 | final Scene scene = new Scene(console);
40 | final URL styleSheetUrl = getStyleSheetUrl();
41 | if (styleSheetUrl != null) {
42 | scene.getStylesheets().add(styleSheetUrl.toString());
43 | }
44 | primaryStage.setTitle(getClass().getSimpleName());
45 | primaryStage.setScene(scene);
46 | primaryStage.setOnCloseRequest(e -> System.exit(0));
47 | primaryStage.show();
48 |
49 | System.setOut(console.getOut());
50 | System.setIn(console.getIn());
51 | System.setErr(console.getOut());
52 | final Thread thread = new Thread(() -> {
53 | Throwable throwable = null;
54 | try {
55 | invokeMain(args);
56 | } catch (Throwable e) {
57 | throwable = e;
58 | }
59 | final int result = throwable == null ? 0 : 1;
60 | if (this.pauseBeforeExit) {
61 | System.out.print("Press enter key to exit.");
62 | try {
63 | new BufferedReader(new InputStreamReader(System.in)).readLine();
64 | } catch (IOException e) {
65 | // ignore
66 | }
67 | }
68 | System.exit(result);
69 | });
70 | thread.setName("Console Application Main Thread");
71 | thread.start();
72 | }
73 |
74 | protected URL getStyleSheetUrl() {
75 | final String styleSheetName = "style.css";
76 | URL url = getClass().getResource(styleSheetName);
77 | if (url != null) {
78 | return url;
79 | }
80 | url = ConsoleApplication.class.getResource(styleSheetName);
81 | if (url != null) {
82 | return url;
83 | }
84 | return null;
85 | }
86 |
87 | protected final void setPauseBeforeExit(final boolean pauseBeforeExit) {
88 | this.pauseBeforeExit = pauseBeforeExit;
89 | }
90 |
91 | public void setTitle(final String title) {
92 | Platform.runLater(() -> this.stage.setTitle(title));
93 | }
94 |
95 | protected abstract void invokeMain(String[] args);
96 |
97 | }
98 |
--------------------------------------------------------------------------------
/src/main/java/jp/uphy/javafx/console/ConsoleView.java:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright (C) 2015 uphy.jp
3 | * Licensed under the Apache License, Version 2.0 (the "License");
4 | * you may not use this file except in compliance with the License.
5 | * You may obtain a copy of the License at
6 | * http://www.apache.org/licenses/LICENSE-2.0
7 | * Unless required by applicable law or agreed to in writing, software
8 | * distributed under the License is distributed on an "AS IS" BASIS,
9 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
10 | * See the License for the specific language governing permissions and
11 | * limitations under the License.
12 | */
13 | package jp.uphy.javafx.console;
14 |
15 | import javafx.event.ActionEvent;
16 | import javafx.event.EventHandler;
17 | import javafx.scene.control.ContextMenu;
18 | import javafx.scene.control.MenuItem;
19 | import javafx.scene.control.TextArea;
20 | import javafx.scene.layout.BorderPane;
21 |
22 | import java.io.IOException;
23 | import java.io.InputStream;
24 | import java.io.PrintStream;
25 | import java.io.UnsupportedEncodingException;
26 | import java.nio.charset.Charset;
27 |
28 |
29 | /**
30 | * @author Yuhi Ishikura
31 | */
32 | public class ConsoleView extends BorderPane {
33 |
34 | private final PrintStream out;
35 | private final TextArea textArea;
36 | private final InputStream in;
37 |
38 | public ConsoleView() {
39 | this(Charset.defaultCharset());
40 | }
41 |
42 | public ConsoleView(Charset charset) {
43 | getStyleClass().add("console");
44 | this.textArea = new TextArea();
45 | this.textArea.setWrapText(true);
46 | KeyBindingUtils.installEmacsKeyBinding(this.textArea);
47 | setCenter(this.textArea);
48 |
49 | final TextInputControlStream stream = new TextInputControlStream(this.textArea, Charset.defaultCharset());
50 | try {
51 | this.out = new PrintStream(stream.getOut(), true, charset.name());
52 | } catch (UnsupportedEncodingException e) {
53 | throw new RuntimeException(e);
54 | }
55 | this.in = stream.getIn();
56 |
57 | final ContextMenu menu = new ContextMenu();
58 | menu.getItems().add(createItem("Clear console", e -> {
59 | try {
60 | stream.clear();
61 | this.textArea.clear();
62 | } catch (IOException e1) {
63 | throw new RuntimeException(e1);
64 | }
65 | }));
66 | this.textArea.setContextMenu(menu);
67 |
68 | setPrefWidth(600);
69 | setPrefHeight(400);
70 | }
71 |
72 | private MenuItem createItem(String name, EventHandler a) {
73 | final MenuItem menuItem = new MenuItem(name);
74 | menuItem.setOnAction(a);
75 | return menuItem;
76 | }
77 |
78 | public PrintStream getOut() {
79 | return out;
80 | }
81 |
82 | public InputStream getIn() {
83 | return in;
84 | }
85 |
86 | }
87 |
--------------------------------------------------------------------------------
/src/main/java/jp/uphy/javafx/console/KeyBindingUtils.java:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright (C) 2015 uphy.jp
3 | * Licensed under the Apache License, Version 2.0 (the "License");
4 | * you may not use this file except in compliance with the License.
5 | * You may obtain a copy of the License at
6 | * http://www.apache.org/licenses/LICENSE-2.0
7 | * Unless required by applicable law or agreed to in writing, software
8 | * distributed under the License is distributed on an "AS IS" BASIS,
9 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
10 | * See the License for the specific language governing permissions and
11 | * limitations under the License.
12 | */
13 | package jp.uphy.javafx.console;
14 |
15 | import javafx.scene.control.TextInputControl;
16 | import javafx.scene.input.KeyCode;
17 | import javafx.scene.input.KeyEvent;
18 |
19 |
20 | /**
21 | * @author Yuhi Ishikura
22 | */
23 | class KeyBindingUtils {
24 |
25 | static void installEmacsKeyBinding(TextInputControl textInputControl) {
26 | textInputControl.addEventHandler(KeyEvent.KEY_PRESSED, e -> {
27 | if (e.isControlDown()) {
28 | switch (e.getCode()) {
29 | case F:
30 | textInputControl.fireEvent(new KeyEvent(KeyEvent.KEY_PRESSED, "", "", KeyCode.RIGHT, false, false, false, false));
31 | e.consume();
32 | break;
33 | case B:
34 | textInputControl.fireEvent(new KeyEvent(KeyEvent.KEY_PRESSED, "", "", KeyCode.LEFT, false, false, false, false));
35 | e.consume();
36 | break;
37 | case N:
38 | textInputControl.fireEvent(new KeyEvent(KeyEvent.KEY_PRESSED, "", "", KeyCode.DOWN, false, false, false, false));
39 | e.consume();
40 | break;
41 | case P:
42 | textInputControl.fireEvent(new KeyEvent(KeyEvent.KEY_PRESSED, "", "", KeyCode.UP, false, false, false, false));
43 | e.consume();
44 | break;
45 | case E:
46 | textInputControl.fireEvent(new KeyEvent(KeyEvent.KEY_PRESSED, "", "", KeyCode.END, false, false, false, false));
47 | e.consume();
48 | break;
49 | case A:
50 | textInputControl.fireEvent(new KeyEvent(KeyEvent.KEY_PRESSED, "", "", KeyCode.HOME, false, false, false, false));
51 | e.consume();
52 | break;
53 | case K:
54 | textInputControl.fireEvent(new KeyEvent(KeyEvent.KEY_PRESSED, "", "", KeyCode.END, true, false, false, false));
55 | textInputControl.fireEvent(new KeyEvent(KeyEvent.KEY_RELEASED, "", "", KeyCode.END, true, false, false, false));
56 | textInputControl.copy();
57 | textInputControl.fireEvent(new KeyEvent(KeyEvent.KEY_PRESSED, "", "", KeyCode.DELETE, true, false, false, false));
58 | e.consume();
59 | break;
60 | case Y:
61 | textInputControl.paste();
62 | e.consume();
63 | break;
64 | }
65 | } else if (e.isAltDown()) {
66 | switch (e.getCode()) {
67 | case W:
68 | textInputControl.copy();
69 | e.consume();
70 | break;
71 | }
72 | }
73 | });
74 | }
75 |
76 | }
77 |
--------------------------------------------------------------------------------
/src/main/java/jp/uphy/javafx/console/TextInputControlStream.java:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright (C) 2015 uphy.jp
3 | * Licensed under the Apache License, Version 2.0 (the "License");
4 | * you may not use this file except in compliance with the License.
5 | * You may obtain a copy of the License at
6 | * http://www.apache.org/licenses/LICENSE-2.0
7 | * Unless required by applicable law or agreed to in writing, software
8 | * distributed under the License is distributed on an "AS IS" BASIS,
9 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
10 | * See the License for the specific language governing permissions and
11 | * limitations under the License.
12 | */
13 | package jp.uphy.javafx.console;
14 |
15 | import javafx.application.Platform;
16 | import javafx.scene.control.TextInputControl;
17 | import javafx.scene.input.KeyCode;
18 | import javafx.scene.input.KeyEvent;
19 |
20 | import java.io.ByteArrayOutputStream;
21 | import java.io.IOException;
22 | import java.io.InputStream;
23 | import java.io.OutputStream;
24 | import java.io.PipedInputStream;
25 | import java.io.PipedOutputStream;
26 | import java.nio.ByteBuffer;
27 | import java.nio.CharBuffer;
28 | import java.nio.charset.Charset;
29 | import java.nio.charset.CharsetDecoder;
30 |
31 |
32 | /**
33 | * @author Yuhi Ishikura
34 | */
35 | class TextInputControlStream {
36 |
37 | private final TextInputControlInputStream in;
38 | private final TextInputControlOutputStream out;
39 | private final Charset charset;
40 |
41 | TextInputControlStream(final TextInputControl textInputControl, Charset charset) {
42 | this.charset = charset;
43 | this.in = new TextInputControlInputStream(textInputControl);
44 | this.out = new TextInputControlOutputStream(textInputControl);
45 |
46 | textInputControl.addEventFilter(KeyEvent.KEY_PRESSED, e -> {
47 | if (e.getCode() == KeyCode.ENTER) {
48 | getIn().enterKeyPressed();
49 | return;
50 | }
51 |
52 | if (textInputControl.getCaretPosition() <= getIn().getLastLineBreakIndex()) {
53 | e.consume();
54 | }
55 | });
56 | textInputControl.addEventFilter(KeyEvent.KEY_TYPED, e -> {
57 | if (textInputControl.getCaretPosition() < getIn().getLastLineBreakIndex()) {
58 | e.consume();
59 | }
60 | });
61 | }
62 |
63 | void clear() throws IOException {
64 | this.in.clear();
65 | this.out.clear();
66 | }
67 |
68 | TextInputControlInputStream getIn() {
69 | return this.in;
70 | }
71 |
72 | TextInputControlOutputStream getOut() {
73 | return this.out;
74 | }
75 |
76 | void startProgramInput() {
77 | // do nothing
78 | }
79 |
80 | void endProgramInput() {
81 | getIn().moveLineStartToEnd();
82 | }
83 |
84 | Charset getCharset() {
85 | return this.charset;
86 | }
87 |
88 | /**
89 | * @author Yuhi Ishikura
90 | */
91 | class TextInputControlInputStream extends InputStream {
92 |
93 | private final TextInputControl textInputControl;
94 | private final PipedInputStream outputTextSource;
95 | private final PipedOutputStream inputTextTarget;
96 | private int lastLineBreakIndex = 0;
97 |
98 | /**
99 | * {@link TextInputControlInputStream}オブジェクトを構築します。
100 | *
101 | * @param textInputControl 入力元のテキストコンポーネント
102 | */
103 | public TextInputControlInputStream(TextInputControl textInputControl) {
104 | this.textInputControl = textInputControl;
105 | this.inputTextTarget = new PipedOutputStream();
106 | try {
107 | this.outputTextSource = new PipedInputStream(this.inputTextTarget);
108 | } catch (IOException e1) {
109 | throw new RuntimeException(e1);
110 | }
111 | }
112 |
113 | int getLastLineBreakIndex() {
114 | return this.lastLineBreakIndex;
115 | }
116 |
117 | void moveLineStartToEnd() {
118 | this.lastLineBreakIndex = this.textInputControl.getLength();
119 | }
120 |
121 | void enterKeyPressed() {
122 | synchronized (this) {
123 | try {
124 | // 文字を入力した後で、←を押してキャレットを戻したあとでEnterを押された場合の対策
125 | // Enterを押した時は、強制的にキャレットを末尾に移動する。
126 | this.textInputControl.positionCaret(this.textInputControl.getLength());
127 |
128 | final String lastLine = getLastLine();
129 | // イベントの発生は、ドキュメントの変更よりも先であるため、この時点では改行文字列が最終行に含まれない
130 | // 従って、改行を追加する。
131 | final ByteBuffer buf = getCharset().encode(lastLine + "\r\n"); //$NON-NLS-1$
132 | this.inputTextTarget.write(buf.array(), 0, buf.remaining());
133 | this.inputTextTarget.flush();
134 | this.lastLineBreakIndex = this.textInputControl.getLength() + 1;
135 | } catch (IOException e) {
136 | if ("Read end dead".equals(e.getMessage())) {
137 | return;
138 | }
139 | throw new RuntimeException(e);
140 | }
141 | }
142 | }
143 |
144 | /**
145 | * 最終行文字列を取得します。
146 | *
147 | * @return 最終行文字列
148 | */
149 | private String getLastLine() {
150 | synchronized (this) {
151 | return this.textInputControl.getText(this.lastLineBreakIndex, this.textInputControl.getLength());
152 | }
153 | }
154 |
155 | @Override
156 | public int available() throws IOException {
157 | return this.outputTextSource.available();
158 | }
159 |
160 | /**
161 | * {@inheritDoc}
162 | */
163 | @Override
164 | public int read() throws IOException {
165 | try {
166 | return this.outputTextSource.read();
167 | } catch (IOException ex) {
168 | return -1;
169 | }
170 | }
171 |
172 | @Override
173 | public int read(final byte[] b, final int off, final int len) throws IOException {
174 | try {
175 | return this.outputTextSource.read(b, off, len);
176 | } catch (IOException ex) {
177 | return -1;
178 | }
179 | }
180 |
181 | @Override
182 | public int read(final byte[] b) throws IOException {
183 | try {
184 | return this.outputTextSource.read(b);
185 | } catch (IOException ex) {
186 | return -1;
187 | }
188 | }
189 |
190 | @Override
191 | public void close() throws IOException {
192 | super.close();
193 | }
194 |
195 | void clear() throws IOException {
196 | this.inputTextTarget.flush();
197 | this.lastLineBreakIndex = 0;
198 | }
199 | }
200 |
201 | /**
202 | * テキストコンポーネントに対し書きだす{@link OutputStream}実装です。
203 | *
204 | * @author Yuhi Ishikura
205 | */
206 | final class TextInputControlOutputStream extends OutputStream {
207 |
208 | private final TextInputControl textInputControl;
209 | private final CharsetDecoder decoder;
210 | private ByteArrayOutputStream buf;
211 |
212 | /**
213 | * {@link TextInputControlOutputStream}オブジェクトを構築します。
214 | *
215 | * @param textInputControl 文字の出力先
216 | */
217 | TextInputControlOutputStream(TextInputControl textInputControl) {
218 | this.textInputControl = textInputControl;
219 | this.decoder = getCharset().newDecoder();
220 | }
221 |
222 | /**
223 | * {@inheritDoc}
224 | */
225 | @Override
226 | public synchronized void write(int b) throws IOException {
227 | synchronized (this) {
228 | if (this.buf == null) {
229 | this.buf = new ByteArrayOutputStream();
230 | }
231 | this.buf.write(b);
232 | }
233 | }
234 |
235 | /**
236 | * {@inheritDoc}
237 | */
238 | @Override
239 | public void flush() throws IOException {
240 | Platform.runLater(() -> {
241 | try {
242 | flushImpl();
243 | } catch (IOException e) {
244 | throw new RuntimeException(e);
245 | }
246 | });
247 | }
248 |
249 | private void flushImpl() throws IOException {
250 | synchronized (this) {
251 | if (this.buf == null) {
252 | return;
253 | }
254 | startProgramInput();
255 | final ByteBuffer byteBuffer = ByteBuffer.wrap(this.buf.toByteArray());
256 | final CharBuffer charBuffer = this.decoder.decode(byteBuffer);
257 | try {
258 | this.textInputControl.appendText(charBuffer.toString());
259 | this.textInputControl.positionCaret(this.textInputControl.getLength());
260 | } finally {
261 | this.buf = null;
262 | endProgramInput();
263 | }
264 | }
265 | }
266 |
267 | /**
268 | * {@inheritDoc}
269 | */
270 | @Override
271 | public void close() throws IOException {
272 | flush();
273 | }
274 |
275 | void clear() throws IOException {
276 | this.buf = null;
277 | }
278 |
279 | }
280 |
281 | }
282 |
--------------------------------------------------------------------------------
/src/main/java/jp/uphy/javafx/example/JavaFXMyCliApplication.java:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright (C) 2015 uphy.jp
3 | * Licensed under the Apache License, Version 2.0 (the "License");
4 | * you may not use this file except in compliance with the License.
5 | * You may obtain a copy of the License at
6 | * http://www.apache.org/licenses/LICENSE-2.0
7 | * Unless required by applicable law or agreed to in writing, software
8 | * distributed under the License is distributed on an "AS IS" BASIS,
9 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
10 | * See the License for the specific language governing permissions and
11 | * limitations under the License.
12 | */
13 | package jp.uphy.javafx.example;
14 |
15 | import jp.uphy.javafx.console.ConsoleApplication;
16 |
17 | import java.io.IOException;
18 |
19 |
20 | /**
21 | * JavaFXのコンソールで、CLIアプリケーションを実行するクラスです。
22 | *
23 | * @author Yuhi Ishikura
24 | */
25 | public class JavaFXMyCliApplication extends ConsoleApplication {
26 |
27 | @Override
28 | protected void invokeMain(final String[] args) {
29 | MyCliApplication.main(args);
30 | }
31 |
32 | public static void main(String[] args) throws IOException, InterruptedException {
33 | launch(args);
34 | }
35 |
36 | }
37 |
--------------------------------------------------------------------------------
/src/main/java/jp/uphy/javafx/example/MyCliApplication.java:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright (C) 2015 uphy.jp
3 | * Licensed under the Apache License, Version 2.0 (the "License");
4 | * you may not use this file except in compliance with the License.
5 | * You may obtain a copy of the License at
6 | * http://www.apache.org/licenses/LICENSE-2.0
7 | * Unless required by applicable law or agreed to in writing, software
8 | * distributed under the License is distributed on an "AS IS" BASIS,
9 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
10 | * See the License for the specific language governing permissions and
11 | * limitations under the License.
12 | */
13 | package jp.uphy.javafx.example;
14 |
15 | /**
16 | * 任意のCLIアプリケーション
17 | *
18 | * @author Yuhi Ishikura
19 | */
20 | public class MyCliApplication {
21 |
22 | public static void main(String[] args) {
23 | System.out.println("Before sleep");
24 | try {
25 | Thread.sleep(5000);
26 | } catch (InterruptedException e) {
27 | throw new RuntimeException(e);
28 | }
29 | System.out.println("After sleep");
30 | }
31 |
32 | }
33 |
--------------------------------------------------------------------------------
/src/main/resources/jp/uphy/javafx/console/style.css:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright (C) 2015 uphy.jp
3 | * Licensed under the Apache License, Version 2.0 (the "License");
4 | * you may not use this file except in compliance with the License.
5 | * You may obtain a copy of the License at
6 | * http://www.apache.org/licenses/LICENSE-2.0
7 | * Unless required by applicable law or agreed to in writing, software
8 | * distributed under the License is distributed on an "AS IS" BASIS,
9 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
10 | * See the License for the specific language governing permissions and
11 | * limitations under the License.
12 | */
13 | .console .content {
14 | -fx-background-color: black;
15 | -fx-text-fill: white;
16 | }
17 |
18 | .console .text-area {
19 | -fx-text-fill: lightgray;
20 | -fx-font-family: monospace;
21 | -fx-font-size:14;
22 | -fx-border-color: black;
23 | }
24 |
--------------------------------------------------------------------------------