diff --git a/src/Keyboard.java b/src/Keyboard.java new file mode 100644 index 0000000..a84cbbd --- /dev/null +++ b/src/Keyboard.java @@ -0,0 +1,141 @@ +/** + * We use an abstract class for Keyboard for future possibilities of different keyboard layouts + * that a user wants to script input for + */ +public class Keyboard { + + /** + * The keyboard mapping to use for scripting the lines from input files + */ + private char[][] keyboardLayout; + + /** + * Constructor for this class, sets value of keyboard + * @param keyboardLayout - the keyboard mapping to be used for this instance of Keyboard + */ + public Keyboard(char[][] keyboardLayout) { + this.keyboardLayout = keyboardLayout; + } + + /** + * Takes the input and determines the script necessary to obtain that input + * @param input - a String to convert into a script + * @return a String with the script representing how to obtain the input for this particular keyboard + */ + String scriptLine(String input) { + // Initializes the builder string and converts input to uppercase to match the keyboard layouts + String result = ""; + String uppercase = input.toUpperCase(); + + // The Point objects we will use to store locations and calculate the paths + Point initial = new Point(); + Point destination = new Point(); + + // Iterate through each character in the string, performing the correct conversions on each + for(int i = 0; i < uppercase.length(); i++) { + char letter = uppercase.charAt(i); + + if(letter == ' ') + // A space + result += 'S'; + else if(keyboardContains(letter)) { + // A character inside the keyboard + result += scriptLetter(letter, initial, destination); + } else { + // Not a character inside the keyboard - error + result += 'E'; + } + + if(i < uppercase.length() - 1) + result += ","; + } + + return result; + } + + /** + * Takes letterToScript and converts it to a sequence of U, D, L and R's, ending with a # + * @param letterToScript - the letter to convert + * @return a string formatted as explained above + */ + private String scriptLetter(char letterToScript, Point initialPoint, Point destinationPoint) { + String script = ""; + + // Sets the correct location of the destination of the letter we are now searching for + setDestinationPoint(letterToScript, destinationPoint); + + // Calculate the displacement (the path) + int verticalDisplacement = destinationPoint.getI() - initialPoint.getI(); + int horizontalDisplacement = destinationPoint.getJ() - initialPoint.getJ(); + + // Based on value of displacement, add appropriate letters to the string we are building + if(verticalDisplacement < 0) { + verticalDisplacement *= -1; + script += addLetters(verticalDisplacement, 'U'); + } else { + script += addLetters(verticalDisplacement, 'D'); + } + + if(horizontalDisplacement < 0) { + horizontalDisplacement *= -1; + script += addLetters(horizontalDisplacement, 'L'); + } else { + script += addLetters(horizontalDisplacement, 'R'); + } + + script += "#"; + + // Current destination point becomes initial point for the next letter (represents the cursor) + initialPoint.setI(destinationPoint.getI()); + initialPoint.setJ(destinationPoint.getJ()); + + return script; + } + + /** + * Builds a string consisting of toAdd repeated numTimes times with commas in following each time + * @param numTimes - the number of times to add the character + * @param toAdd - the character to add to the string we are building + * @return a String formatted as explained above + */ + private String addLetters(int numTimes, char toAdd) { + String builder = ""; + + for(int i = 0; i < numTimes; i++) + builder += toAdd + ","; + + return builder; + } + + /** + * Searches for letterToFind in keyboardLayout and sets the location of it in pointToSet + * @param letterToFind - the letter whose location we are searching for + * @param pointToSet - the Point whose location we will set to match letterToFind, represents the destination + */ + private void setDestinationPoint(char letterToFind, Point pointToSet) { + for(int i = 0; i < keyboardLayout.length; i++) { + for(int j = 0; j < keyboardLayout[0].length; j++) { + if(letterToFind == keyboardLayout[i][j]) { + pointToSet.setI(i); + pointToSet.setJ(j); + } + } + } + } + + /** + * Checks if keyboardLayout contains letterToCheck + * @param letterToCheck - the letter desired in the keyboard + * @return true if keyboardLayout contains letterToCheck, false otherwise + */ + private boolean keyboardContains(char letterToCheck) { + for(char[] row : keyboardLayout) { + for(char c : row) { + if(c == letterToCheck) + return true; + } + } + + return false; + } +} diff --git a/src/KeyboardScripter.java b/src/KeyboardScripter.java new file mode 100644 index 0000000..876dbad --- /dev/null +++ b/src/KeyboardScripter.java @@ -0,0 +1,137 @@ +import java.io.BufferedReader; +import java.io.File; +import java.io.FileReader; +import java.util.ArrayList; +import java.util.Scanner; + +/** + * The driver class for this program, takes file input, reads it + * and outputs scripted version of each line + */ +public class KeyboardScripter { + + public static void main(String[] args) { + + // Strings to be used to access files + String rootPath = "/Users/michaelbarton/IdeaProjects/OnScreenKeyboard/src/"; + String keyboardLayoutsPath = "keyboardLayouts/"; + String inputFilesPath = "inputFiles/"; + String alphabeticalFileName = "alphabeticalLayout.txt"; + String qwertyFileName = "qwertyLayout.txt"; + + // Other attributes needed for main + Scanner sc = new Scanner(System.in); + String keyboardType, scriptFileName; + char[][] keyboardLayout; + Keyboard keyboard; + + // Print welcome message and determine keyboard type + System.out.println("Welcome to KeyboardScripter!"); + + do { + System.out.print("Enter which kind of keyboard you'd like to use (\'alphabetical\' or \'qwerty\'): "); + keyboardType = sc.nextLine(); + } while (!keyboardType.equals("alphabetical") && !keyboardType.equals("qwerty")); + + // Create Keyboard based on keyboard type inputted from user + if(keyboardType.equals("alphabetical")) { + keyboardLayout = createKeyboardLayout(rootPath + keyboardLayoutsPath + alphabeticalFileName); + } else { + keyboardLayout = createKeyboardLayout(rootPath + keyboardLayoutsPath + qwertyFileName); + } + + keyboard = new Keyboard(keyboardLayout); + + System.out.println("\nHere's what your keyboard looks like!"); + print2DArray(keyboardLayout); + + // Obtain file name to read through and script + System.out.print("\nEnter the file name that you would like to script: "); + scriptFileName = sc.nextLine(); + + System.out.println("\nResults:\n"); + + // Open file, read through and script each line + try { + BufferedReader br = new BufferedReader(new FileReader(new File(rootPath + inputFilesPath + scriptFileName))); + + String str; + while ((str = br.readLine()) != null) { + System.out.println("\"" + str + "\" scripts to: "); + System.out.println(keyboard.scriptLine(str) + "\n"); + } + + } catch (Exception e) { + e.printStackTrace(); + } + + } + + /** + * Reads in the keyboard layout from the file and converts it into a double array of characters + * @param fileName - name of the file to read from + * @return double array of characters + */ + static char[][] createKeyboardLayout(String fileName) { + + // Must use a list as we don't know the size yet + ArrayList> table = new ArrayList<>(); + + // Read the lines into "table" + try { + BufferedReader br = new BufferedReader(new FileReader(new File(fileName))); + + String str; + while ((str = br.readLine()) != null) + table.add(parseCharacters(str)); + + } catch (Exception e) { + e.printStackTrace(); + } + + // Create the double char array based on dimensions of "table" + int rows = table.size(); + int columns = table.get(0).size(); + char[][] layout = new char[rows][columns]; + + // Extract out all characters from table into the double char array "layout" + for(int i = 0; i < rows; i++) { + for(int j = 0; j < columns; j++) { + layout[i][j] = table.get(i).get(j); + } + } + + return layout; + } + + /** + * Splits up a line of characters into a list based on a space regex + * @param str - the line of characters to split up, each token should be a string of length 1 + * @return an ArrayList of characters representing a split version of str + */ + private static ArrayList parseCharacters(String str) { + ArrayList characters = new ArrayList<>(); + + String[] splitString = str.split(" "); + + for(String s : splitString) { + characters.add(s.charAt(0)); + } + + return characters; + } + + /** + * Prints out any char[][] array + * @param array - the double array to print out + */ + private static void print2DArray(char[][] array) { + for(char[] row : array) { + for (char element : row) { + System.out.print(element + " "); + } + System.out.println(); + } + } + +} diff --git a/src/KeyboardTester.java b/src/KeyboardTester.java new file mode 100644 index 0000000..c6f7757 --- /dev/null +++ b/src/KeyboardTester.java @@ -0,0 +1,160 @@ +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +class KeyboardTester { + + private static Keyboard alphabeticalKeyboard; + private static Keyboard qwertyKeyboard; + + @BeforeAll + static void setUpKeyboards() { + String rootPath = "/Users/michaelbarton/IdeaProjects/OnScreenKeyboard/src/keyboardLayouts/"; + String alphabeticalFileName = "alphabeticalLayout.txt"; + String qwertyFileName = "qwertyLayout.txt"; + + // Create both Keyboards + char[][] alphabeticalKeyboardLayout = KeyboardScripter.createKeyboardLayout(rootPath + + alphabeticalFileName); + char[][] qwertyKeyboardLayout = KeyboardScripter.createKeyboardLayout(rootPath + qwertyFileName); + + alphabeticalKeyboard = new Keyboard(alphabeticalKeyboardLayout); + qwertyKeyboard = new Keyboard(qwertyKeyboardLayout); + } + + /** + * All Alphabetical keyboard tests + */ + @Test + void emptyLineAlphabetical() { + assertEquals("", alphabeticalKeyboard.scriptLine("")); + } + + @Test + void selectAndDoneAlphabetical() { + assertEquals("#", alphabeticalKeyboard.scriptLine("A")); + } + + @Test + void bottomRightAlphabetical() { + assertEquals("D,D,D,D,D,R,R,R,R,R,#", alphabeticalKeyboard.scriptLine("0")); + } + + @Test + void singleErrorAlphabetical() { + assertEquals("E", alphabeticalKeyboard.scriptLine("+")); + } + + @Test + void singleSpaceAlphabetical() { + assertEquals("S", alphabeticalKeyboard.scriptLine(" ")); + } + + @Test + void allLettersAlphabetical() { + assertEquals("D,D,#,U,R,R,#,U,#,D,L,#,U,L,#,R,R,R,R,#,D,R,#", + alphabeticalKeyboard.scriptLine("Michael")); + } + + @Test + void lettersAndSpacesAlphabetical() { + assertEquals("D,R,#,U,R,R,R,#,D,D,R,#,U,U,L,#,S,D,D,D,#,U,U,U,#,S,D,L,L,L,L,#,D,R,R,#,S,D,L,L,#,R,#" + + ",U,U,U,R,R,R,#,#,D,R,#,U,L,#,D,D,R,#,D,L,L,L,L,L,#", + alphabeticalKeyboard.scriptLine("Here we go Steelers")); + } + + @Test + void lettersAndErrorsAlphabetical() { + assertEquals("D,D,R,R,R,#,U,L,#,D,R,R,R,#,U,U,L,L,L,L,L,#,D,D,D,R,#,U,U,U,R,R,R,#,D,D,D,L,L,L,L,#," + + "E,U,R,R,R,#,U,U,R,#,D,D,L,L,L,#,U,L,#,D,D,R,R,#,U,U,#,D,L,#,D,L,#", + alphabeticalKeyboard.scriptLine("Pirates/Penguins")); + } + + @Test + void spacesAndErrorsAlphabetical() { + assertEquals("E,E,E,E,E,S,E,E,E,E,E,E,E", alphabeticalKeyboard.scriptLine("@@#$! #@$%^*%")); + } + + @Test + void lettersSpacesAndErrorsAlphabetical() { + assertEquals("D,R,R,R,R,R,#,U,L,#,D,D,D,L,L,L,#,E,L,#,S,U,U,#,D,R,R,#,S,R,#,U,U,R,#,D,D,L,L,L,#" + + ",D,L,#,E", alphabeticalKeyboard.scriptLine("Let's go Pens!")); + } + + @Test + void lettersSpacesAndNumbersAlphabetical() { + assertEquals("D,D,D,#,R,#,U,U,U,R,R,R,#,#,D,R,#,U,L,#,D,D,R,#,D,L,L,L,L,L,#,S,U,U,U,#,D,D,R,R,R," + + "R,R,#,U,U,L,#,S,D,D,L,L,L,#,D,R,#,U,L,L,#,U,U,R,#,R,R,R,#,D,D,R,#,S,D,D,L,L,L,#", + alphabeticalKeyboard.scriptLine("Steelers are number 1")); + } + + + + /** + * All Qwerty keyboard tests + */ + @Test + void emptyLineQwerty() { + assertEquals("", qwertyKeyboard.scriptLine("")); + } + + @Test + void selectAndDoneQwerty() { + assertEquals("#", qwertyKeyboard.scriptLine("Q")); + } + + @Test + void bottomRightQwerty() { + assertEquals("D,D,R,R,R,R,R,R,R,R,R,R,R,#", qwertyKeyboard.scriptLine("9")); + } + + @Test + void singleErrorQwerty() { + assertEquals("E", qwertyKeyboard.scriptLine("+")); + } + + @Test + void singleSpaceQwerty() { + assertEquals("S", qwertyKeyboard.scriptLine(" ")); + } + + @Test + void allLettersQwerty() { + assertEquals("D,D,R,R,R,R,R,R,#,U,U,R,#,D,D,L,L,L,L,L,#,U,R,R,R,#,L,L,L,L,L,#,U,R,R,#,D,R,R,R,R,R,R,#", + qwertyKeyboard.scriptLine("Michael")); + } + + @Test + void lettersAndSpacesQwerty() { + assertEquals("D,R,R,R,R,R,#,U,L,L,L,#,R,#,L,#,S,L,#,R,#,S,D,R,R,#,U,R,R,R,R,#,S,D,L,L,L,L,L,L,L," + + "#,U,R,R,R,#,L,L,#,#,D,R,R,R,R,R,R,#,U,L,L,L,L,L,L,#,R,#,D,L,L,#", + qwertyKeyboard.scriptLine("Here we go Steelers")); + } + + @Test + void lettersAndErrorsQwerty() { + assertEquals("R,R,R,R,R,R,R,R,R,#,L,L,#,L,L,L,L,#,D,L,L,L,#,U,R,R,R,R,#,L,L,#,D,L,#,E,U,R,R,R,R,R," + + "R,R,R,#,L,L,L,L,L,L,L,#,D,D,R,R,R,#,U,L,#,U,R,R,#,R,#,D,D,L,L,#,U,L,L,L,L,#", + qwertyKeyboard.scriptLine("Pirates/Penguins")); + } + + @Test + void spacesAndErrorsQwerty() { + assertEquals("E,E,E,E,E,S,E,E,E,E,E,E,E", qwertyKeyboard.scriptLine("@@#$! #@$%^*%")); + } + + @Test + void lettersSpacesAndErrorsQwerty() { + assertEquals("D,R,R,R,R,R,R,R,R,#,U,L,L,L,L,L,L,#,R,R,#,E,D,L,L,L,#,S,R,R,R,#,U,R,R,R,R,#,S,R," + + "#,L,L,L,L,L,L,L,#,D,D,R,R,R,#,U,L,L,L,L,#,E", qwertyKeyboard.scriptLine("Let's go Pens!")); + } + + @Test + void lettersSpacesAndNumbersQwerty() { + assertEquals("D,R,#,U,R,R,R,#,L,L,#,#,D,R,R,R,R,R,R,#,U,L,L,L,L,L,L,#,R,#,D,L,L,#,S,L,#,U,R,R,R" + + ",#,L,#,S,D,D,R,R,R,#,U,U,R,#,D,D,#,L,L,#,U,U,L,L,#,R,#,S,R,R,R,R,R,R,R,R,#", + qwertyKeyboard.scriptLine("Steelers are number 1")); + } + +} diff --git a/src/Point.java b/src/Point.java new file mode 100644 index 0000000..ac46a25 --- /dev/null +++ b/src/Point.java @@ -0,0 +1,35 @@ +public class Point { + + /** + * The coordinate pair of this object + */ + private int i; + private int j; + + /** + * Default constructor initializes both to 0 + */ + public Point() { + i = 0; + j = 0; + } + + /** + * Getters and setters for both i and j + */ + int getI() { + return i; + } + + int getJ() { + return j; + } + + void setI(int i) { + this.i = i; + } + + void setJ(int j) { + this.j = j; + } +} diff --git a/src/inputFiles/testInput.txt b/src/inputFiles/testInput.txt new file mode 100644 index 0000000..4f6cbed --- /dev/null +++ b/src/inputFiles/testInput.txt @@ -0,0 +1,6 @@ +Michael +Here we go Steelers +Pirates/Penguins +@@#$! #@$%^*% +Let's go Pens! +Steelers are number 1 diff --git a/src/keyboardLayouts/alphabeticalLayout.txt b/src/keyboardLayouts/alphabeticalLayout.txt new file mode 100644 index 0000000..da60cc4 --- /dev/null +++ b/src/keyboardLayouts/alphabeticalLayout.txt @@ -0,0 +1,6 @@ +A B C D E F +G H I J K L +M N O P Q R +S T U V W X +Y Z 1 2 3 4 +5 6 7 8 9 0 \ No newline at end of file diff --git a/src/keyboardLayouts/qwertyLayout.txt b/src/keyboardLayouts/qwertyLayout.txt new file mode 100644 index 0000000..d75e77f --- /dev/null +++ b/src/keyboardLayouts/qwertyLayout.txt @@ -0,0 +1,3 @@ +Q W E R T Y U I O P 0 1 +A S D F G H J K L 2 3 4 +Z X C V B N M 5 6 7 8 9 \ No newline at end of file diff --git a/src/plan.txt b/src/plan.txt new file mode 100644 index 0000000..995ca7a --- /dev/null +++ b/src/plan.txt @@ -0,0 +1,46 @@ +1. Have a Keyboard class that will accept a keyboard as a double array of chars (can be any kind of keyboard) + a. Make this keyboard layout come from a file like how the input will +2. Create a class called KeyboardScripter that will act as the driver to read in the file, create the Keyboard object + with the appropriate keyboard and output the scripted result. + +Keyboard components: + Attributes: + private char[][] keyboard + + Functions: + public Keyboard() + public String scriptLine(String input) + * any helper functions for scriptLine() + +Steps to implement this: +1. Create classes and skeletons - done +2. Implement Driver.java + a. Create Keyboard object from file + b. Get file input, read through each line + c. Pass each line to keyboard.scriptLine() + d. Print out the result +3. Implement scriptLine() in Keyboard.java + - Initial idea is to have starting index be (0,0). + - Then, find the destination index (i, j). + - Perform arithmetic to find vertical and horizontal distances and use that to convert to 'U', 'D', 'L', 'R' + and just append a '#' on the end. + - Then, repeat starting index being the (i, j) you were just at. + + - Note: you must first test if we are converting a letter or a space. If it's a space, just do 'S'. + - Note: if a letter, make sure we can do both upper and lower case letters. + + - Forseeable helper functions: + Point doubleIndexOf(Char c) + String convertToScript(Point origin, Point destination) + + Point will be a very small object containing an i and j pair of coordinates representing a location + in the double array of chars + Attributes: + int i, int j + Functions: + Point(i, j) + int getI() + int getJ() + + +** NOTE: Not all of the above mentioned points were used in the final design, made some changes along the way ** \ No newline at end of file