Skip to content

Instantly share code, notes, and snippets.

@PseudoSky
Created October 29, 2015 11:00
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save PseudoSky/601190fe6e8c1cbe0587 to your computer and use it in GitHub Desktop.
Save PseudoSky/601190fe6e8c1cbe0587 to your computer and use it in GitHub Desktop.
import java.util.Arrays;
import java.util.Collections;
import android.view.MotionEvent;
import java.lang.reflect.Method;
class Gestures {
int maxOffset, minLength,st,et,tOff;
String functionName;
PVector startPos, endPos;
PApplet pApp;
Method[] m;
Gestures(int minimum,int offSet,int timeOffset,PApplet theApplet) {
m=new Method[4];
pApp = theApplet;
maxOffset=offSet; //number pixels you are allowed to travel off the axis and still being counted as a swipe
minLength=minimum; // number of pixels you need to move your finger to count as a swipe
tOff=timeOffset;
}
// where did our motion start
void setStartPos(PVector pos) {
startPos=pos;
}
// where did our motion start
void setStartTime(int t) {
st=t;
}
void setEndTime(int t) {
et=t;
}
// where did it end and also call to check if it was a valid swipe
void setEndPos(PVector pos) {
endPos=pos;
checkSwipe();
endPos=new PVector();
startPos=new PVector();
}
// check if it is a valid swipe that has been performed and if soperformthe attached function
void checkSwipe() {
print(et-st);
if (et-st< tOff){
if (abs(startPos.x-endPos.x)>minLength && abs(startPos.y-endPos.y) < maxOffset) {
if (startPos.x < endPos.x) {
performAction(2); // a swipe right
return;
}
else {
performAction(0); // a swipe left
return;
}
}
else {
if (abs(startPos.y-endPos.y)>minLength && abs(startPos.x-endPos.x) < maxOffset) {
if (startPos.y < endPos.y) {
performAction(3); // a swipe downwards
return;
}
else {
performAction(1); // a swipe upwards
return;
}
}
}
}
epx=endPos.x;
epy=endPos.y;
print("mouseX: " + mouseX+" mouseY: "+mouseY+"\n");
if (didMouseClick(0, 200, 215, 400)) //check if click occured in letter area
{
currentLetter = 'a';
}else if (didMouseClick(200+15, 200, 8, 400)){
currentLetter ='b';
}else if (didMouseClick(200+23, 200, 10, 400)){
currentLetter ='c';
}else if (didMouseClick(200+33, 200, 10, 400)){
currentLetter ='d';
}else if (didMouseClick(200+43, 200, 14, 400)){
currentLetter ='e';
}else if (didMouseClick(200+57, 200, 16, 400)){
currentLetter ='f';
}else if (didMouseClick(200+73, 200, 19, 400)){
currentLetter ='g';
}else if (didMouseClick(200+92, 200, 19, 400)){
currentLetter ='h';
}else if (didMouseClick(200+113, 200, 23, 400)){
currentLetter ='i';
}else if (didMouseClick(200+136, 200, 20, 400)){
currentLetter ='j';
}else if (didMouseClick(200+156, 200, 29, 400)){
currentLetter ='k';
}else if (didMouseClick(200+185, 200, 20, 400)){
currentLetter ='l';
}else if (didMouseClick(200+205, 200, 15, 400)){
currentLetter ='m';
}else if (didMouseClick(200+236, 200, 21, 400)){
currentLetter ='n';
}else if (didMouseClick(200+258, 200, 22, 400)){
currentLetter ='o';
}else if (didMouseClick(200+283, 200, 25, 400)){
currentLetter ='p';
}else if (didMouseClick(200+307, 200, 24, 400)){
currentLetter ='q';
}else if (didMouseClick(200+328, 200, 22, 400)){
currentLetter ='r';
}else if (didMouseClick(200+350, 200, 20, 400)){
currentLetter ='s';
}else if (didMouseClick(200+370, 200, 14, 400)){
currentLetter ='t';
}else if (didMouseClick(200+384, 200, 15, 400)){
currentLetter ='u';
}else if (didMouseClick(200+399, 200, 11, 400)){
currentLetter ='v';
}else if (didMouseClick(200+410, 200, 9, 400)){
currentLetter ='w';
}else if (didMouseClick(200+419, 200, 6, 400)){
currentLetter ='x';
}else if (didMouseClick(200+425, 200, 7, 400)){
currentLetter ='y';
}else if (didMouseClick(200+432, 200, 222, 400)){
currentLetter ='z';
}
currentTyped+=currentLetter;
//You are allowed to have a next button outside the 2" area
if (didMouseClick(800, 00, 200, 200)) //check if click is in next button
{
nextTrial(); //if so, advance to next trial
}
}
// call the function that we have defined with setAction
void performAction(int direction) {
if (m[direction] == null)
return;
try {
m[direction].invoke(pApp);
}
catch (Exception e) {
e.printStackTrace();
}
}
// define a function that should get called when the different swipes is done
void setAction(int direction, String method) {
if (method != null && !method.equals("")) {
try {
m[direction] = pApp.getClass().getMethod(method);
}
catch (SecurityException e) {
e.printStackTrace();
}
catch (NoSuchMethodException e) {
e.printStackTrace();
}
}
}
// attach a function to a left swipe
void setSwipeLeft(String _funcName) {
setAction(0, _funcName);
}
void setSwipeUp(String _funcName) {
setAction(1, _funcName);
}
void setSwipeRight(String _funcName) {
setAction(2, _funcName);
}
void setSwipeDown(String _funcName) {
setAction(3, _funcName);
}
}
// android touch event.
public boolean surfaceTouchEvent(MotionEvent event) {
// check what that was triggered
switch(event.getAction()) {
case MotionEvent.ACTION_DOWN: // ACTION_DOWN means we put our finger down on the screen
g.setStartTime(millis());
g.setStartPos(new PVector(event.getX(), event.getY())); // set our start position
break;
case MotionEvent.ACTION_UP: // ACTION_UP means we pulled our finger away from the screen
g.setEndTime(millis());
g.setEndPos(new PVector(event.getX(), event.getY())); // set our end position of the gesture and calculate if it was a valid one
break;
}
return super.surfaceTouchEvent(event);
}
// function that is called when we areswipingupwards
void swipeUp() {
println("a swipe up");
println("a swipe right");
currentTyped = currentTyped+" ";
}
void swipeDown() {
println("a swipe down");
println("a swipe left");
if(currentTyped.length()>0)currentTyped = currentTyped.substring(0,currentTyped.length()-1);
}
void swipeLeft() {
println("a swipe left");
if(currentTyped.length()>0)currentTyped = currentTyped.substring(0,currentTyped.length()-1);
}
void swipeRight() {
println("a swipe right");
currentTyped = currentTyped+" ";
}
Gestures g;
float epy=0;
float epx=0;
String[] phrases; //contains all of the phrases
int totalTrialNum = 4; //the total number of phrases to be tested - set this low for testing. Might be ~10 for the real bakeoff!
int currTrialNum = 0; // the current trial number (indexes into trials array above)
float startTime = 0; // time starts when the first letter is entered
float finishTime = 0; // records the time of when the final trial ends
float lastTime = 0; //the timestamp of when the last trial was completed
float lettersEnteredTotal = 0; //a running total of the number of letters the user has entered (need this for final WPM computation)
float lettersExpectedTotal = 0; //a running total of the number of letters expected (correct phrases)
float errorsTotal = 0; //a running total of the number of errors (when hitting next)
String currentPhrase = ""; //the current target phrase
String currentTyped = ""; //what the user has typed so far
final int DPIofYourDeviceScreen = 441; //you will need to look up the DPI or PPI of your device to make sure you get the right scale!!
//http://en.wikipedia.org/wiki/List_of_displays_by_pixel_density
final float sizeOfInputArea = DPIofYourDeviceScreen*1; //aka, 1.0 inches square!
boolean firstClick = false;
//Variables for my silly implementation. You can delete this:
char currentLetter = 'a';
char selectedLetter = 'a';
//You can modify anything in here. This is just a basic implementation.
void setup()
{
g=new Gestures(70,100,115,this); // iniate the gesture object first value is minimum swipelengthin pixel and second is the diagonal offset allowed
g.setSwipeUp("swipeUp"); // attach the function called swipeUp to the gesture ofswipingupwards
g.setSwipeDown("swipeDown"); // attach the function called swipeDown to the gesture ofswipingdownwards
g.setSwipeLeft("swipeLeft"); // attach the function called swipeLeft to the gesture ofswipingleft
g.setSwipeRight("swipeRight");
phrases = loadStrings("phrases2.txt"); //load the phrase set into memory
Collections.shuffle(Arrays.asList(phrases)); //randomize the order of the phrases
orientation(PORTRAIT); //can also be LANDSCAPE -- sets orientation on android device
size(1000, 1000); //Sets the size of the app. You may want to modify this to your device. Many phones today are 1080 wide by 1920 tall.
textFont(createFont("Arial", 24)); //set the font to arial 24
noStroke(); //my code doesn't use any strokes.
}
//You can modify anything in here. This is just a basic implementation.
void draw()
{
background(0); //clear background
// image(watch,-200,200);
fill(100);
rect(200, 200, sizeOfInputArea, sizeOfInputArea); //input area should be 2" by 2"
if (finishTime!=0)
{
fill(255);
textAlign(CENTER);
text("Finished", 280, 150);
return;
}
if (startTime==0 & !mousePressed)
{
fill(255);
textAlign(CENTER);
text("Click to start time!", 280, 150); //display this messsage until the user clicks!
}
if (startTime==0 & mousePressed)
{
nextTrial(); //start the trials!
firstClick = true;
}
if (startTime!=0)
{
//you will need something like the next 10 lines in your code. Output does not have to be within the 2 inch area!
textAlign(LEFT); //align the text left
fill(128);
textSize(20);
text("Phrase " + (currTrialNum+1) + " of " + totalTrialNum, 70, 50); //draw the trial count
fill(255);
textSize(20);
text("Target: " + currentPhrase, 70, 100); //draw the target string
text("Entered: " + currentTyped, 70, 140); //draw what the user has entered thus far
fill(255, 0, 0);
rect(800, 00, 200, 200); //drag next button
fill(255);
textSize(20);
text("NEXT > ", 850, 100); //draw next label
//my draw code
textAlign(CENTER);
if (didMouseClick(0, 200, 215, 400)) //check if click occured in letter area
{
selectedLetter = 'a';
//if (currentLetter=='_') //if underscore, consider that a space bar
// currentTyped+=" ";
//else if (currentLetter=='`' & currentTyped.length()>0) //if `, treat that as a delete command
// currentTyped = currentTyped.substring(0, currentTyped.length()-1);
//else if (currentLetter!='`') //if not any of the above cases, add the current letter to the typed string
// currentTyped+=currentLetter;
}else if (didMouseClick(200+15, 200, 8, 400)){
selectedLetter ='b';
}else if (didMouseClick(200+23, 200, 10, 400)){
selectedLetter ='c';
}else if (didMouseClick(200+33, 200, 10, 400)){
selectedLetter ='d';
}else if (didMouseClick(200+43, 200, 14, 400)){
selectedLetter ='e';
}else if (didMouseClick(200+57, 200, 16, 400)){
selectedLetter ='f';
}else if (didMouseClick(200+73, 200, 19, 400)){
selectedLetter ='g';
}else if (didMouseClick(200+92, 200, 19, 400)){
selectedLetter ='h';
}else if (didMouseClick(200+113, 200, 23, 400)){
selectedLetter ='i';
}else if (didMouseClick(200+136, 200, 20, 400)){
selectedLetter ='j';
}else if (didMouseClick(200+156, 200, 29, 400)){
selectedLetter ='k';
}else if (didMouseClick(200+185, 200, 20, 400)){
selectedLetter ='l';
}else if (didMouseClick(200+205, 200, 15, 400)){
selectedLetter ='m';
}else if (didMouseClick(200+236, 200, 21, 400)){
selectedLetter ='n';
}else if (didMouseClick(200+258, 200, 22, 400)){
selectedLetter ='o';
}else if (didMouseClick(200+283, 200, 25, 400)){
selectedLetter ='p';
}else if (didMouseClick(200+307, 200, 24, 400)){
selectedLetter ='q';
}else if (didMouseClick(200+328, 200, 22, 400)){
selectedLetter ='r';
}else if (didMouseClick(200+350, 200, 20, 400)){
selectedLetter ='s';
}else if (didMouseClick(200+370, 200, 14, 400)){
selectedLetter ='t';
}else if (didMouseClick(200+384, 200, 15, 400)){
selectedLetter ='u';
}else if (didMouseClick(200+399, 200, 11, 400)){
selectedLetter ='v';
}else if (didMouseClick(200+410, 200, 9, 400)){
selectedLetter ='w';
}else if (didMouseClick(200+419, 200, 6, 400)){
selectedLetter ='x';
}else if (didMouseClick(200+425, 200, 7, 400)){
selectedLetter ='y';
}else if (didMouseClick(200+432, 200, 422, 400)){
selectedLetter ='z';
}
String[] names = {"z","y","x","w","v","u","t","s","r","q","p","o","n","m","l","k","j","i","h","g","f","e","d","c","b","a"};
float delta = -PI / names.length;
int radius = names.length *8;
for(int i = 0; i<names.length; i++) {
if ((""+selectedLetter).equals(names[i])){
fill(0,250,0);
textSize(50);
//fill(209);
//ellipse(width/2+radius * cos(i* delta)-80, height/2+radius * sin(i*delta)-30, 60,60);
}
else{
fill(0,0,0);
textSize(18);
}
text(names[i],width/2+radius * cos(i* delta)-80, height/2+radius * sin(i*delta) -30);
}
fill(0,250,0);
textSize(100);
text("" + selectedLetter, 200+sizeOfInputArea/2, 200+sizeOfInputArea/3); //draw current letter
}
}
boolean didMouseClick(float x, float y, float w, float h) //simple function to do hit testing
{
return (mouseX > x && mouseX<x+w && mouseY>y && mouseY<y+h); //check to see if it is in button bounds
}
void mouseReleased()
{
if(firstClick){
firstClick = false;
return;
}
print("mouseX:" + mouseX+" mouseY:"+mouseY+"\n");
//print("width:" + width);
//print((atan((mouseY*1.0)/(1.0*mouseX) )*180.0)/PI+"\n");
//if (didMouseClick(200, 200+sizeOfInputArea/2, sizeOfInputArea/2, sizeOfInputArea/2)) //check if click in left button
//{
// currentLetter --;
// if (currentLetter<'_') //wrap around to z
// currentLetter = 'z';
//}
//if (didMouseClick(200+sizeOfInputArea/2, 200+sizeOfInputArea/2, sizeOfInputArea/2, sizeOfInputArea/2)) //check if click in right button
//{
// currentLetter ++;
// if (currentLetter>'z') //wrap back to space (aka underscore)
// currentLetter = '_';
//}
//if (didMouseClick(200, 200, sizeOfInputArea, sizeOfInputArea/2)) //check if click occured in letter area
//{
if (didMouseClick(0, 200, 215, 400)) //check if click occured in letter area
{
currentLetter = 'a';
//if (currentLetter=='_') //if underscore, consider that a space bar
// currentTyped+=" ";
//else if (currentLetter=='`' & currentTyped.length()>0) //if `, treat that as a delete command
// currentTyped = currentTyped.substring(0, currentTyped.length()-1);
//else if (currentLetter!='`') //if not any of the above cases, add the current letter to the typed string
// currentTyped+=currentLetter;
}else if (didMouseClick(200+15, 200, 8, 400)){
currentLetter ='b';
}else if (didMouseClick(200+23, 200, 10, 400)){
currentLetter ='c';
}else if (didMouseClick(200+33, 200, 10, 400)){
currentLetter ='d';
}else if (didMouseClick(200+43, 200, 14, 400)){
currentLetter ='e';
}else if (didMouseClick(200+57, 200, 16, 400)){
currentLetter ='f';
}else if (didMouseClick(200+73, 200, 19, 400)){
currentLetter ='g';
}else if (didMouseClick(200+92, 200, 19, 400)){
currentLetter ='h';
}else if (didMouseClick(200+113, 200, 23, 400)){
currentLetter ='i';
}else if (didMouseClick(200+136, 200, 20, 400)){
currentLetter ='j';
}else if (didMouseClick(200+156, 200, 29, 400)){
currentLetter ='k';
}else if (didMouseClick(200+185, 200, 20, 400)){
currentLetter ='l';
}else if (didMouseClick(200+205, 200, 15, 400)){
currentLetter ='m';
}else if (didMouseClick(200+236, 200, 21, 400)){
currentLetter ='n';
}else if (didMouseClick(200+258, 200, 22, 400)){
currentLetter ='o';
}else if (didMouseClick(200+283, 200, 25, 400)){
currentLetter ='p';
}else if (didMouseClick(200+307, 200, 24, 400)){
currentLetter ='q';
}else if (didMouseClick(200+328, 200, 22, 400)){
currentLetter ='r';
}else if (didMouseClick(200+350, 200, 20, 400)){
currentLetter ='s';
}else if (didMouseClick(200+370, 200, 14, 400)){
currentLetter ='t';
}else if (didMouseClick(200+384, 200, 15, 400)){
currentLetter ='u';
}else if (didMouseClick(200+399, 200, 11, 400)){
currentLetter ='v';
}else if (didMouseClick(200+410, 200, 9, 400)){
currentLetter ='w';
}else if (didMouseClick(200+419, 200, 6, 400)){
currentLetter ='x';
}else if (didMouseClick(200+425, 200, 7, 400)){
currentLetter ='y';
}else if (didMouseClick(200+432, 200, 522, 400)){
currentLetter ='z';
}
}
void nextTrial()
{
if (currTrialNum >= totalTrialNum) //check to see if experiment is done
return; //if so, just return
if (startTime!=0 && finishTime==0) //in the middle of trials
{
System.out.println("==================");
System.out.println("Phrase " + (currTrialNum+1) + " of " + totalTrialNum); //output
System.out.println("Target phrase: " + currentPhrase); //output
System.out.println("Phrase length: " + currentPhrase.length()); //output
System.out.println("User typed: " + currentTyped); //output
System.out.println("User typed length: " + currentTyped.length()); //output
System.out.println("Number of errors: " + computeLevenshteinDistance(currentTyped.trim(), currentPhrase.trim())); //trim whitespace and compute errors
System.out.println("Time taken on this trial: " + (millis()-lastTime)); //output
System.out.println("Time taken since beginning: " + (millis()-startTime)); //output
System.out.println("==================");
lettersExpectedTotal+=currentPhrase.length();
lettersEnteredTotal+=currentTyped.length();
errorsTotal+=computeLevenshteinDistance(currentTyped.trim(), currentPhrase.trim());
}
if (currTrialNum == totalTrialNum-1) //check to see if experiment just finished
{
finishTime = millis();
System.out.println("==================");
System.out.println("Trials complete!"); //output
System.out.println("Total time taken: " + (finishTime - startTime)); //output
System.out.println("Total letters entered: " + lettersEnteredTotal); //output
System.out.println("Total letters expected: " + lettersExpectedTotal); //output
System.out.println("Total errors entered: " + errorsTotal); //output
System.out.println("WPM: " + (lettersEnteredTotal/5.0f)/((finishTime - startTime)/60000f)); //output
System.out.println("==================");
currTrialNum++; //increment by one so this mesage only appears once when all trials are done
return;
}
if (startTime==0) //first trial starting now
{
System.out.println("Trials beginning! Starting timer..."); //output we're done
startTime = millis(); //start the timer!
}
else
{
currTrialNum++; //increment trial number
}
lastTime = millis(); //record the time of when this trial ended
currentTyped = ""; //clear what is currently typed preparing for next trial
currentPhrase = phrases[currTrialNum]; // load the next phrase!
//currentPhrase = "abc"; // uncomment this to override the test phrase (useful for debugging)
}
//=========SHOULD NOT NEED TO TOUCH THIS METHOD AT ALL!==============
int computeLevenshteinDistance(String phrase1, String phrase2) //this computers error between two strings
{
int[][] distance = new int[phrase1.length() + 1][phrase2.length() + 1];
for (int i = 0; i <= phrase1.length(); i++)
distance[i][0] = i;
for (int j = 1; j <= phrase2.length(); j++)
distance[0][j] = j;
for (int i = 1; i <= phrase1.length(); i++)
for (int j = 1; j <= phrase2.length(); j++)
distance[i][j] = min(min(distance[i - 1][j] + 1, distance[i][j - 1] + 1), distance[i - 1][j - 1] + ((phrase1.charAt(i - 1) == phrase2.charAt(j - 1)) ? 0 : 1));
return distance[phrase1.length()][phrase2.length()];
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment