Created
February 10, 2013 18:56
-
-
Save NeatMonster/74f2d1debe03d4699697 to your computer and use it in GitHub Desktop.
A proof of concept class showing that it's easy to replicate the Windows command line interface.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package fr.neatmonster.console; | |
import java.awt.Color; | |
import java.awt.EventQueue; | |
import java.awt.Font; | |
import java.awt.Image; | |
import java.awt.Toolkit; | |
import java.awt.event.InputEvent; | |
import java.awt.event.KeyAdapter; | |
import java.awt.event.KeyEvent; | |
import java.io.File; | |
import java.util.ArrayList; | |
import java.util.Arrays; | |
import java.util.Timer; | |
import java.util.TimerTask; | |
import javax.swing.ImageIcon; | |
import javax.swing.JFrame; | |
import javax.swing.JScrollPane; | |
import javax.swing.JTextArea; | |
import javax.swing.ScrollPaneConstants; | |
import javax.swing.UIManager; | |
/* | |
* MM'""""'YMM dP | |
* M' .mmm. `M 88 | |
* M MMMMMooM .d8888b. 88d888b. .d8888b. .d8888b. 88 .d8888b. | |
* M MMMMMMMM 88' `88 88' `88 Y8ooooo. 88' `88 88 88ooood8 | |
* M. `MMM' .M 88. .88 88 88 88 88. .88 88 88. ... | |
* MM. .dM `88888P' dP dP `88888P' `88888P' dP `88888P' | |
* MMMMMMMMMMM | |
*/ | |
/** | |
* A proof of concept class showing that it's easy to replicate the Windows command line interface. | |
* | |
* @author NeatMonster. | |
*/ | |
public class Console { | |
/** The special characters allowed in the console. */ | |
private static final String SPECIAL_CHARACTERS = " ²&~\"#'{([|`_\\^@)°]=+}€^¨$£¤ù%*µ<>,?;.:!§/*-+"; | |
/** | |
* The method called when the application starts. | |
* | |
* @param args | |
* the arguments | |
*/ | |
public static void main(final String[] args) { | |
EventQueue.invokeLater(new Runnable() { | |
@Override | |
public void run() { | |
try { | |
final Console console = new Console(); | |
console.frame.setVisible(true); | |
} catch (final Exception e) { | |
e.printStackTrace(); | |
} | |
} | |
}); | |
} | |
private String consoleText = ""; | |
private File currentDirectory = new File(System.getProperty("user.home")); | |
private int cursorDisplayed = 0; | |
private boolean cursorEnabled = false; | |
private int cursorPosition = 0; | |
private JFrame frame; | |
private JScrollPane scrollPane; | |
private JTextArea textArea; | |
private Timer timer; | |
private String userText = ""; | |
/** | |
* Instantiates a new console. | |
*/ | |
public Console() { | |
initialize(); | |
} | |
/** | |
* Adds the specified character to the console. | |
* | |
* @param c | |
* the caracter | |
*/ | |
public void addCharacter(final String c) { | |
String userText = this.userText + c; | |
if (cursorEnabled && cursorPosition < this.userText.length()) { | |
userText = this.userText.substring(0, cursorPosition) + c; | |
if (cursorPosition < this.userText.length() - 1) | |
userText += this.userText.substring(cursorPosition, this.userText.length()); | |
} | |
this.userText = userText; | |
cursorPosition++; | |
update(); | |
} | |
/** | |
* Simulate an user pressing backspace. | |
*/ | |
public void backspace() { | |
if (cursorPosition > 0) { | |
String userText = this.userText.substring(0, cursorPosition - 1); | |
if (cursorPosition < this.userText.length() - 1) | |
userText += this.userText.substring(cursorPosition, this.userText.length()); | |
this.userText = userText; | |
if (cursorPosition > 0) | |
cursorPosition--; | |
update(); | |
} | |
} | |
/** | |
* Simulate an user pressing delete. | |
*/ | |
public void delete() { | |
if (cursorEnabled && cursorPosition < userText.length()) { | |
String userText = this.userText.substring(0, cursorPosition); | |
if (cursorPosition < this.userText.length() - 1) | |
userText += this.userText.substring(cursorPosition + 1, this.userText.length()); | |
this.userText = userText; | |
update(); | |
} | |
} | |
/** | |
* Handle a key event. | |
* | |
* @param e | |
* the event | |
*/ | |
public void handleKeyEvent(final KeyEvent e) { | |
if ((e.getModifiers() & InputEvent.CTRL_MASK) == InputEvent.CTRL_MASK && e.getKeyCode() != KeyEvent.VK_LEFT | |
&& e.getKeyCode() != KeyEvent.VK_RIGHT) | |
return; | |
if (e.getKeyChar() == '\n') { | |
cursorEnabled = false; | |
final String userText = this.userText; | |
println(userText); | |
this.userText = ""; | |
if (!userText.isEmpty()) { | |
String[] args = userText.trim().replaceAll(" {2,}", " ").split(" "); | |
if (args.length > 0) { | |
final String command = args[0]; | |
if (args.length == 1) | |
args = new String[0]; | |
else | |
args = Arrays.copyOfRange(args, 1, args.length); | |
if (command.equalsIgnoreCase("cd")) { | |
if (args.length > 0) { | |
final File currentDirectory = this.currentDirectory.toPath().resolve(args[0]).normalize().toFile(); | |
if (currentDirectory.exists() && currentDirectory.isDirectory()) { | |
this.currentDirectory = currentDirectory; | |
} else | |
println("Le chemin d'accès spécifié est introuvable."); | |
} else | |
try { | |
println(currentDirectory.getCanonicalPath()); | |
} catch (final Exception e1) { | |
println(currentDirectory.getAbsolutePath()); | |
} | |
println(""); | |
} else if (command.equalsIgnoreCase("exit")) { | |
int status = 0; | |
if (args.length > 0) | |
try { | |
status = Integer.parseInt(args[0]); | |
} catch (final Exception e1) { | |
} | |
System.exit(status); | |
} else { | |
println("'" + command + "' n'est pas reconnu en tant que commande interne"); | |
println("ou externe, un programme exécutable ou un fichier de commandes."); | |
println(""); | |
} | |
} | |
} | |
requestUserInput(); | |
} else if (e.getKeyCode() == KeyEvent.VK_BACK_SPACE) { | |
if (cursorPosition > 0) { | |
e.consume(); | |
backspace(); | |
} | |
} else if (e.getKeyCode() == KeyEvent.VK_DELETE) { | |
if (cursorPosition < userText.length()) { | |
e.consume(); | |
delete(); | |
} | |
} else if (e.getKeyCode() == KeyEvent.VK_LEFT && (e.getModifiers() & InputEvent.CTRL_MASK) == InputEvent.CTRL_MASK) { | |
if (cursorPosition > 0) { | |
e.consume(); | |
cursorPosition = userText.substring(0, cursorPosition - 1).lastIndexOf(" ") >= 0 ? userText.substring(0, cursorPosition - 1) | |
.lastIndexOf(" ") + 1 : 0; | |
cursorDisplayed = 0; | |
update(); | |
} | |
} else if (e.getKeyCode() == KeyEvent.VK_LEFT) { | |
if (cursorPosition > 0) { | |
cursorPosition--; | |
cursorDisplayed = 0; | |
update(); | |
} | |
} else if (e.getKeyCode() == KeyEvent.VK_RIGHT && (e.getModifiers() & InputEvent.CTRL_MASK) == InputEvent.CTRL_MASK) { | |
if (cursorPosition < userText.length() - 1) { | |
e.consume(); | |
cursorPosition += userText.substring(cursorPosition + 1, userText.length()).indexOf(" ") >= 0 ? userText.substring( | |
cursorPosition + 1, userText.length()).indexOf(" ") + 2 : userText.substring(cursorPosition + 1, userText.length()).length(); | |
cursorDisplayed = 0; | |
update(); | |
} | |
} else if (e.getKeyCode() == KeyEvent.VK_RIGHT) { | |
if (cursorPosition < userText.length()) { | |
cursorPosition++; | |
cursorDisplayed = 0; | |
update(); | |
} | |
} else if (e.getKeyCode() == KeyEvent.VK_HOME) { | |
cursorPosition = 0; | |
cursorDisplayed = 0; | |
update(); | |
} else if (e.getKeyCode() == KeyEvent.VK_END) { | |
cursorPosition = userText.length(); | |
cursorDisplayed = 0; | |
update(); | |
} else if (e.getKeyCode() == KeyEvent.VK_ESCAPE) { | |
userText = ""; | |
cursorPosition = 0; | |
cursorDisplayed = 0; | |
update(); | |
} else if (Character.isUnicodeIdentifierPart(e.getKeyChar()) || SPECIAL_CHARACTERS.contains(Character.toString(e.getKeyChar()))) | |
addCharacter(Character.toString(e.getKeyChar())); | |
} | |
/** | |
* Initialize the console. | |
*/ | |
public void initialize() { | |
initializeFrame(); | |
initializeTimer(); | |
initializeTextArea(); | |
initializeScrollPane(); | |
} | |
/** | |
* Initialize the frame. | |
*/ | |
public void initializeFrame() { | |
try { | |
UIManager.setLookAndFeel("com.sun.java.swing.plaf.windows.WindowsLookAndFeel"); | |
} catch (final Exception e) { | |
} | |
frame = new JFrame(); | |
final int width = 675; | |
final int screenWidth = Toolkit.getDefaultToolkit().getScreenSize().width; | |
final int height = 342; | |
final int screenHeight = Toolkit.getDefaultToolkit().getScreenSize().height; | |
frame.setBounds((screenWidth - width) / 2, (screenHeight - height) / 2, width, height); | |
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); | |
frame.setTitle("Administateur : C:\\Windows\\system32\\cmd.exe"); | |
final ArrayList<Image> icons = new ArrayList<Image>(); | |
icons.add(new ImageIcon(getClass().getResource("/resources/cmd_x16.png")).getImage()); | |
icons.add(new ImageIcon(getClass().getResource("/resources/cmd_x32.png")).getImage()); | |
icons.add(new ImageIcon(getClass().getResource("/resources/cmd_x48.png")).getImage()); | |
icons.add(new ImageIcon(getClass().getResource("/resources/cmd_x256.png")).getImage()); | |
frame.setIconImages(icons); | |
frame.setResizable(false); | |
} | |
/** | |
* Initialize the scrollpane. | |
*/ | |
public void initializeScrollPane() { | |
scrollPane = new JScrollPane(textArea, ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS, ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER); | |
frame.setContentPane(scrollPane); | |
} | |
/** | |
* Initialize the text area. | |
*/ | |
public void initializeTextArea() { | |
textArea = new JTextArea(); | |
textArea.addKeyListener(new KeyAdapter() { | |
@Override | |
public void keyPressed(final KeyEvent e) { | |
handleKeyEvent(e); | |
} | |
}); | |
textArea.setEditable(false); | |
textArea.setBackground(Color.BLACK); | |
textArea.setForeground(Color.WHITE); | |
textArea.setFont(new Font("Lucida Console", Font.PLAIN, 13)); | |
textArea.setLineWrap(true); | |
println("Microsoft Windows [version 6.1.7601]"); | |
println("Copyright (c) 2009 Microsoft Corporation. Tous droits réservés."); | |
println(""); | |
requestUserInput(); | |
} | |
/** | |
* Initialize the timer responsible for the blinking cursor. | |
*/ | |
public void initializeTimer() { | |
timer = new Timer(); | |
timer.scheduleAtFixedRate(new TimerTask() { | |
@Override | |
public void run() { | |
if (cursorEnabled) { | |
cursorDisplayed = (cursorDisplayed + 1) % 4; | |
update(); | |
} | |
} | |
}, 0L, 250L); | |
} | |
/** | |
* Prints the String on the console. | |
* | |
* @param s | |
* the string to print | |
*/ | |
public void print(final String s) { | |
consoleText += s; | |
update(); | |
} | |
/** | |
* Print the screen to the console and add a new line. | |
* | |
* @param s | |
* the string to print | |
*/ | |
public void println(final String s) { | |
print(s + "\n"); | |
} | |
/** | |
* Request an input of the user. | |
*/ | |
public void requestUserInput() { | |
try { | |
print(currentDirectory.getCanonicalPath() + ">"); | |
} catch (final Exception e) { | |
print(currentDirectory.getAbsolutePath() + ">"); | |
} | |
cursorEnabled = true; | |
cursorDisplayed = 0; | |
cursorPosition = 0; | |
userText = ""; | |
} | |
/** | |
* Update the console display. | |
*/ | |
public synchronized void update() { | |
String userText = this.userText; | |
if (cursorEnabled) { | |
if (cursorDisplayed < 3) { | |
userText = this.userText.substring(0, cursorPosition) + "_"; | |
if (cursorPosition < this.userText.length() - 1) | |
userText += this.userText.substring(cursorPosition + 1, this.userText.length()); | |
} | |
} | |
textArea.setText(consoleText + userText); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment