This site requires JavaScript, please enable it in your browser!
Greenfoot back
444Jam444
444Jam444 wrote ...

2020/4/14

Help with multi-key macro

1
2
3
444Jam444 444Jam444

2020/4/14

#
Hi, I'm looking to create macros for the user so that the user can type their desired commands (as an alternative to clicking on-screen buttons) so that 'the user can have a more streamlined experience' Macros: 0-9 (no problems here) operators (no problems here) Holding CTRL and typing in (up to) 4 characters, eg CTRL+root code so far (don't mind the multitude of multi-line comments, those are notes to myself):
public class checkKeyPress extends Actor
{
    //This class was intended to be a method. However, due to the...
    //...'method' being designed to suit multiple worlds, it was...
    //...decided that checkKeyPress should be a publicly-accessible...
    //...actor, to simplify and shorten code length and increase...
    //...coding efficiency and code simplicity.
    
    //some code may be externally sourced.
    //Credit: Greenfoot Discussions,danpost, 2011
    //Name of post: "Greenfoot.isKeyDown(any) ???"
    
    private String keyPress;
    private boolean ctrlHeld;
    private String returnValue;
    
    public final String numbers = "0123456789";
    public final String symbols = "!^*x()+-=|./";
    public String txtString = "";
    
    Button buttonClass = new Button();
 
    public checkKeyPress(){
        /**numbers*/
        /** +-/x=. */
        /** | CTRLroot ^ CTRLfrac CTRLsincostan CTRLans () ! */
        /** CTRLs CTRLa CTRLc CTRLm backspace */
        
    }
    
    /**
     * Act - do whatever the checkKeyPress wants to do. This method is called whenever
     * the 'Act' or 'Run' button gets pressed in the environment.
     */
    public void act() 
    {
        if (Greenfoot.isKeyDown("ctrl")){
            ctrlHeld = true;
        }
        else{
            ctrlHeld = false;
        }
        /**move this code to a separate method because different worlds have different input*/
        keyPress = Greenfoot.getKey();
        
        if (keyPress == null) { return; }
        
        if (! ctrlHeld){
            if (keyPress == "backspace") /**change == to .equals("") for each*/
            {
                /**Code for when 'backspace' is pressed*/
            }
            /**for the following if statements, call checkkeypress in 'buttonClass'*/
            if (numbers.contains(keyPress)){/***/}
            if (symbols.contains(keyPress)){/***/} /** '*' and 'x' both mean multiply*/
            
        }
        if (ctrlHeld){
            //code here...
        }
    } 
the contents of the constructor can be ignored, (i was a little indecisive between act and constructor) but the constructor contains the full list of all the macros I have explained why 'checkKeyPress' is an actor in the comments (first few lines) Thanks
444Jam444 444Jam444

2020/4/14

#
(it may or may not be for a complex calculator)
444Jam444 444Jam444

2020/4/14

#
I intend to do something along the lines of: if ctrl is held then <--- (key must be HELD) check the next key press <--- (following key(s) must be PRESSED) add the key press to txtString if ctrl WAS held but isn't held anymore then (as in; ctrl was JUST released) compare the final string with available macros //code that follows according to what macro was done (don't worry about this) clear txtString ctrlHeld = false
danpost danpost

2020/4/14

#
The following structure should work:
if (ctrlHeld != Greenfoot.isKeyDown("ctrl"))
{  // ctrl was just pressed or released
    ctrlHeld = ! ctrlHeld;
    if ( ! ctrlHeld )
    { // ctrl was just released
        // if not "", compare txtString to macros; execute if found)
        txtString = "";
    }
}
else if (ctrlHeld)
{
    // add any key to txtString
}
Line 49 will always end up false as the literal string is not the same String object as that contained by keyPrress. Use the following to compare the internal contents of the objects:
if ("backspace".equals(keyPress))
I just now saw the comment at the end of the line. I decided to leave the above in the reply.
444Jam444 444Jam444

2020/4/15

#
danpost wrote...
Line 49 will always end up false as the literal string is not the same String object as that contained by keyPrress. Use the following to compare the internal contents of the objects:
if ("backspace".equals(keyPress))
I just now saw the comment at the end of the line. I decided to leave the above in the reply.
Haha yeah, some of this code was sourced from a 2011 post in which you first discovered .equals was better than == for strings :) (I credited some of my code to said post, on lines 9-11 in my code, if you would like to have a mini-nostalgia trip... I'm joking of course) That code is quite interesting... Might take me a while to understand it, but I'm confident enough in my coding abilities to understand it, thanks for introducing a new concept to me! (I'm referring to the syntax of lines 1-7, lines 3-4 especially interest me) And for holding ctrl and typing in a message, would it be something like:
if (ctrlHeld){
    keyPress = Greenfoot.getKey();
    //ctrlHeld uses .isKeyDown
    //keyPress uses .getKey
    if (txtString.length() >= 5){
        txtString = "";
    }
    txtString = txtString + keyPress;
}
The reason why I ask if the code would look like this is because I'm not sure my understanding of isKeyDown and getKey is correct. The way I understand them is: isKeyDown - can register multiple key presses (but multiple isKeyDown statements are required to do so), or can continuously register a single key press/key held down, will return true if the given key is pressed/held even if other keys are pressed/held, requires a parameter to work (parameter being the desired key press), will perform a statement and its contents multiple times for the duration of the key press (an if statement, for example) getKey - can only register one key at a time, will change/overwrite its previous return value if a new key is pressed (eg for the macros, while ctrl is held and 'root' is typed, it will return ctrl, then r, then o, then o, then t), will perform a statement and its contents only once even if the key is held (unless in an act method or loop) Because this is in an act method, will getKey return the same value multiple times or not? Do I need like 'if (keyPress.equals("ctrl") == false)' or something to stop getKey from doing ctrl+rrrrooooooooooottttt instead of ctrl+root? What will getKey return if ctrl is held and a key was pressed, but ctrl is still held after and no further keys are pressed? I have more experience with isKeyDown than getKey, clearly...
danpost danpost

2020/4/15

#
With getKey, a character is only returned when a character is sent to the input buffer. Think of it like when you are in a text editor -- when characters are put to the screen or the cursor changes location ("enter" and "backspace"). As in a text editor, holding down a key can cause the same character to be repeatedly registered with a short delay between them. The "ctrl" key, in itself is not registered by getKey as another key would have to be used with it.
444Jam444 wrote...
What will getKey return if ctrl is held and a key was pressed
Well, it will return a control code. The letters a-z will return char(1)-char(26) instead of char(97)-char(112) which represent "a"-"z". So, yeah -- you will need to find a different way about it.
444Jam444 444Jam444

2020/4/16

#
danpost wrote...
444Jam444 wrote...
What will getKey return if ctrl is held and a key was pressed
Well, it will return a control code. The letters a-z will return char(1)-char(26) instead of char(97)-char(112) which represent "a"-"z". So, yeah -- you will need to find a different way about it.
Huh. Interesting. That sure does complicate things, especially since the documentation that I submitted at least a month ago stated that ctrl would be held and certain keywords would be typed... There is a way around this though, isn't there? I could register the control code if possible and it would only affect the intrinsic documentation. Is there a way to do this?
danpost danpost

2020/4/16

#
444Jam444 wrote...
There is a way around this though, isn't there? I could register the control code if possible and it would only affect the intrinsic documentation. Is there a way to do this?
Sorry. I just tested it. I got these sample behaviors: ctrl-b : Debug window opens ctrl-t : scenario resets ctrl-i : import class window opens ctrl-a : "1" sent to terminal (as programmed) ctrl-d : "99" sent to terminal ("4" was expected; (char)99 = 'd' ) Obviously, it will not work as you had intended.
444Jam444 444Jam444

2020/4/16

#
That is unfortunate. I'll come back to this in a few days or something, when I might have something figured out. For now, the buttons themselves have functionality, so I'm able to do work in other areas in the meantime. I will be revisit this thread soon enough. Thanks for your help for now danpost!
danpost danpost

2020/4/16

#
danpost wrote...
ctrl-d : "99" sent to terminal ("4" was expected; (char)99 = 'd' )
I was mistaken. This one did not return anything. Apparently, a press of the control key sent the "99" and (char)100 = 'd' (but not sent)
444Jam444 444Jam444

2020/4/16

#
Maybe shift will work? It seems like maybe a much simpler solution, with the same initial concept (except shift+ROOT instead of ctrl+root). Am I correct in saying that shift is just registered as "shift" by getKey/isKeyDown?
danpost danpost

2020/4/16

#
444Jam444 wrote...
Maybe shift will work? It seems like maybe a much simpler solution, with the same initial concept (except shift+ROOT instead of ctrl+root). Am I correct in saying that shift is just registered as "shift" by getKey/isKeyDown?
The getKey method will not register shift by itself. Any letter key with shift down will produce an upper case character, which is not the same as its lower case counterpart. However, that is fine, as you would not need to even test for the shift key at all. You can use something simple, like this:
String key = Greenfoot.getKey();
if (key != null)
{
    if ("enter".equals(key) && !"".equals(txtString))
    {
        /***/
        return;
    }
    if ("backspace".equals(key) && txtString.length() > 0)
    {
        txtString = txtString.substring(0, txtString.length()-1);
        return;
    }
    if (key.length() == 1)
    {
        char c = key.charAt(0);
        if (c >= 'A' && c <= 'Z')
        {
            txtString += key;
            return;
        }
        if (c >= 'a' && c <= 'z')
        {
            txtString = "";
            /***/
            return;
        }
        if (symbols.indexOf(key) >= 0 || numbers.indexOf(key) >= 0)
        {
            txtString = "";
            /***/
            return;
        }
    }
}
444Jam444 444Jam444

2020/4/16

#
Ok thanks. I think I'll modify it to make it more like this structure;
private String[] letters = { /**(capital letters A-Z)*/ };

//in act method
String key = Greenfoot.getKey();

if (key != null){
    //removing "if key.length() == 1) unless there
    //are other keys that are not length of 1?
    char c = key.charAt(0);
    if (letters.indexOf(c) >= 0){ //to eliminate confusion between capital letters and other keys
        txtString += key;
    }
    if (!Greenfoot.isKeyDown("shift") && !txtString.equals("")){
        //compare to valid macros and call a method
        txtString = "";
    }
}
(I might have missed something out; I wrote that on the spot) I intend for the string to be registered when shift is no longer held, rather than the user pressing enter and backspace (if they make a typo they can retype the macro by letting go of shift or backspace the outcome of the macro)
444Jam444 444Jam444

2020/4/18

#
Is there a demo for testing getKey/isKeyDown outputs? It's a lot of effort repetitively making and calling various temporary methods in the program just to test the result... I want to test if getKey will return '*' or 'shift' then '8' when the user inputs shift+8 (desired output is asterisk). (alternatively, there is documentation for this, isn't there? If so, I have not been able to find it yet... other than Greenfoot API which doesn't seem to go into detail about key names or outputs, unless I'm blind which is likely)
444Jam444 444Jam444

2020/4/18

#
I currently am having 2 more issues that I cannot solve... namely an int not increasing in value, and text not properly displaying... It's very confusing because the output of the terminal shows that they are processed. Issue #1: 'currentIndex' not increasing
Actor class Calculate
private int currentIndex = 0;

public void add(String chars){
        /**check if chars == mode alpha store. if so, then 'return;'*/
        if (processingCalculation == false){
            holder = chars;
            //check to see if input is a number
            if (checkIfNumber(holder)){
                currentCalculation = insert(currentCalculation, currentIndex, holder);
            }
            else if (holder.equals("Clear")){
                currentCalculation = "";
                currentIndex = -1; //+1 is added at end of method
                System.out.println("CLEARED");
                System.out.println("_______");
            }
            else if (holder.equals("Delete")){
                if (! currentCalculation.equals("")){
                    currentCalculation = delete(currentCalculation, currentIndex);
                }
                if (currentIndex > 0){
                    currentIndex = currentIndex - 2;
                    //currentIndex - 2 + 1 = intended currentIndex
                    //will not matter if currentIndex results as -1...
                    //...because +1 is added at the end of the method
                }
            }
        }
        /**make sure subclasses of button arent registered!*/

        //problem area
        currentIndex = currentIndex + 1;
        System.out.println("a"); //shows up in terminal,
        //so it is definitely processed
        //but the terminal says currentIndex is zero
        //(there is a 'get' method in this class for currentIndex,
        //and the 'get' method is called in the world)
        //the 'get' method is definitely called, as the terminal shows
    }


public int getCurrentIndex(){
        System.out.println(currentIndex);
        return currentIndex;
    }
//terminal shows '0' when button is pressed, without increment
//it is supposed to increment per button press

World
public void updateDisplay(){
        Calculate calculate = new Calculate();
        String displayCalculation = calculate.getCurrentCalculation();
        String cursor = ":";
        int index = calculate.getCurrentIndex();
        if (!displayCalculation.equals("")){
            displayCalculation = calculate.insert(displayCalculation, index, cursor);
        }
        else{
            displayCalculation = "0";
        }
        System.out.println(displayCalculation);
        showText(displayCalculation, xCoord4, yCoord4);
    }
Terminal shows this (after 956= was entered) a 0 :9 0 :9 9 a 0 :59 0 :59 5 a 0 :659 0 :659 6 a 0 :659 = supposed to be (minus error-checking line prints) 0 9: 1 95: 2 956: 3 956=: Also, problem #2: Text not updating (remaining '0' despite the string changing) world class
public void updateDisplay(){
        Calculate calculate = new Calculate();
        String displayCalculation = calculate.getCurrentCalculation();
        String cursor = ":";
        int index = calculate.getCurrentIndex();
        if (!displayCalculation.equals("")){
            displayCalculation = calculate.insert(displayCalculation, index, cursor);
        }
        else{
            displayCalculation = "0";
        }
        System.out.println(displayCalculation);
        showText(displayCalculation, xCoord4, yCoord4);
    }
There are more replies on the next page.
1
2
3