0

I am not sure where to go with shift and caps key, I don't know whether I can make different values on what I am already working on for this or not. I am new to Jpanel, so any help would be much appreciated.

This is my current code in VSCode right now. It will pull up a 5 by 12 keyboard that reads inputs and will output into the console on enter. Tab, Caps, Shift, and delete currently don't work. I am mostly focused on caps and shift right now, as I can get the other two pretty easily.

import java.awt.BorderLayout;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.ArrayList;
import java.util.Arrays;

import javax.lang.model.util.ElementScanner6;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.plaf.ComponentUI;

public class Keyboard extends JFrame implements ActionListener {
    private JButton[] buttons;
    private JPanel keyboardPanel;
    public String userInput = "";
    public ArrayList<String> keyboardKeys = new ArrayList<>(Arrays.asList("1", "2", "3", "4", "5", "6", "7", "8", "9", "0", "-", "=",
    "q", "w", "e", "r", "t", "y", "u", "i", "o", "p", "\\", "delete",
    "a", "s", "d", "f", "g", "h", "j", "k", "l", ";", "'", "enter",
    "shift", "z", "x", "c", "v", "b", "n", "m", ",", ".", "/", "shift",
    "caps", "tab", "space", "`", "~", "!", "@", "(", ")", "?", "[", "]"));
    public static ComponentUI newUI = new ComponentUI() {
        
    };

    public Keyboard() {
        super("Keyboard");
        keyboardPanel = new JPanel();
        keyboardPanel.setLayout(new GridLayout(5, 12));
        buttons = new JButton[60];
        for (int i = 0; i < buttons.length; i++) {
            buttons[i] = new JButton(keyboardKeys.get(i));
            buttons[i].addActionListener(this);
            keyboardPanel.add(buttons[i]);
        }
        add(keyboardPanel, BorderLayout.CENTER);
        setSize(900, 300);
        setLocationRelativeTo(null);
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        setVisible(true);
    }

    public void actionPerformed(ActionEvent event) {
        JButton source = (JButton) event.getSource();
        //System.out.println(source.getText());
        //collect inputs into a String
        if(source.getText() == "shift")
        {
            //change keyboard for shift and caps keystrokes
            System.out.println("shift key");
        }
        else if(source.getText() == "caps")
        {
             //change keyboard for caps keystrokes
             System.out.println("caps key");
        }
        else if((source.getText() == "enter"))
        {
            //on enter, send the input array out
            //System.out.println("enter key");
            System.out.println(userInput);
        }
        else if(source.getText() == "space")
        {
            System.out.println("space bar");
            userInput = userInput + " ";
        }
        else
        {
            userInput = userInput + source.getText();
        }
        // Do something with the button press, such as sending a value to the PLC or
        // updating a display
    }

    public static void main(String[] args) {
        new Keyboard();
    }
}
Zee Man
  • 3
  • 2
  • So what _is_ the problem? – tkausl Mar 01 '23 at 16:52
  • @tkausl The problem I am having is I have not clue how to make it to where the shift or caps key works. any insight would be very helpful :) – Zee Man Mar 01 '23 at 17:00
  • 1
    A flag for shift/caps lock keys, an conditional conversion to uppercase letters. That would be a start, at least. – tkausl Mar 01 '23 at 17:01
  • `boolean shiftOn = false; boolean capsLockOn = false;` When someone touches one, toggle the value: `if (source.getText.equals("shift")) { shiftOn = ! shiftOn;}` for example. You would want to add code to change the look of the key to indicate its state. – Old Dog Programmer Mar 01 '23 at 17:11
  • By the way, you might (or might not) have a problem with the way you are comparing `String` Objects. https://stackoverflow.com/questions/513832/how-do-i-compare-strings-in-java – Old Dog Programmer Mar 01 '23 at 17:12
  • @OldDogProgrammer, Thanks for the input, I understand that part but Don't know where to start as for the key values being uppercase or how to implement that part. And I don't have a problem comparing the objects, I tested that earlier on. – Zee Man Mar 01 '23 at 17:17
  • So, the question is about how to handle the shift / caps booleans in the part of the code where you have `userInput = userInput + source.getText(); // Do something with the button press, such as sending a value to the PLC or // updating a display` ? – Old Dog Programmer Mar 01 '23 at 17:21
  • 1
    @OldDogProgrammer yes, Ideally I would be able to change the value of the key grid to make a = A, 1 = !, ect. on a shift press or caps press. That is the part I am struggling with. – Zee Man Mar 01 '23 at 17:29
  • Do you want to redraw the keyboard when `shift` and or `caps lock` status is / are changed or do you just want to get the correct character when the following letter / number / punctuation key is pressed? – Old Dog Programmer Mar 01 '23 at 17:31
  • @OldDogProgrammer I want both to happen. Redraw and get the correct character. – Zee Man Mar 01 '23 at 17:46

1 Answers1

0

As was mentioned in the comments, have boolean variables to represent the states of the Caps Lock and Shift keys.

For letters, it's easy to shift a letter to uppercase or lowercase. For punctuation, my suggestion is to have code that maps characters between lowercase and uppercase for punctuation and digits. A Map would be useful:

private boolean shiftOn = false, capsLockOn = false;
private final String [] shifted = {"1!","2@","3#","4$","5%","6^","7&","8*"
      ,"9(","0)","-_","=+","`~","[{","]}","\\|",";:","'\"",",<",".>","/?"};
private Map <Character, Character> shiftMap;

with a method:

    private void loadShiftMap () {
       shiftMap = new HashMap <> ();
       for (String c: shifted) { 
           shiftMap.put (c.charAt(0), c.charAt(1));
       }
    }

Call loadShiftMap () within the constructor.

Note: You will have make changes to match your keyboard layout. For example, to type !, I use (<shift> 1). But you have a separate key for ! and other characters for your keyboard. This solution, therefore, has to be adapted.

If the String passed to the following method contains exaclty one character, it will return a result based on that character and the state of the Shift and Caps Lock keys. Otherwise, it will return what was passed:

private String getShiftedCharacter (String input) { 
    if (input.length() != 1) return input;
    char theChar = input.charAt(0);
    char result = theChar;
    if (Character.isLetter(theChar)) { 
        if (shiftOn || capsLockOn) { 
            result = Character.toUpperCase(theChar);
        } else { 
            result = Character.toLowerCase(theChar);            
        }
    } else { 
        if (shiftOn) { 
            result = shiftMap.get(theChar);
        }
    }
    return Character.toString (result);
}

When the Shift key or Caps Lock key is pressed, toggle the state of the appropriate Boolean variable. For example, shiftOn = ! shiftOn;. In addition, after any letter, digit, or punctuation key is pressed, clear shiftOn to false. Otherwise, it will act as the Caps Lock key.

If you want to redraw the keyboard whenever the state of the Shift key or Caps Lock key is changed, change the labels on the buttons, and then repaint:

private void showShift () { 
    for (int i = 0; i < buttons.length; ++i) {
        buttons [i].setText(getshiftedCharacter(keyboardKeys.get(i)));
    }
    getContentPane().repaint();
}

Because the "source" comes from the label (text) on the button, and the labels on the button are updated when the state of a Shift Key or Caps Lock key is changed, the only place getShiftedCharacter is called is within the showShift method.

Note: This code uses char / Character autoboxing and autounboxing.

Comment: I don't like parallel arrays. I might avoid parallel arrays by doing something like this:

 String [][] keyboardKeys = {{"`","~"}, {"1","!"}, {"2","@"}, {"3","#"}, ... 
 ,{"Tab","Tab"},{"q","Q"},{"w","W"}, ... {"[","{"},{"]","}"},{"\","|"}
 ,{"Caps","Caps"},{"a","A"},{"s","S"}, ... };
Old Dog Programmer
  • 901
  • 1
  • 7
  • 9
  • This was exactly what I was looking for!! Thank you so much for the insight and help! I avoided the parallel arrays aswell! – Zee Man Mar 07 '23 at 00:40