KlikiMouse5.ino (Source)

/*
Klikimouse5 aneb objects forever! + RX/TX LEDs
3 tlacitka a LED+330 Ohm odpor proti zemi
Macros for Mouse and Keyboard (ArduinoMicro)
Based on:
ButtonMouseControl
For Leonardo and Due boards only.
http://www.arduino.cc/en/Tutorial/ButtonMouseControl
https://www.arduino.cc/en/Tutorial/KeyboardAndMouseControl
*/
#include <Keyboard.h>
#include <Mouse.h>
// set pin numbers for the buttons and led:
const int button_B = 4;
const int button_C = 3;
const int button_A = 2;
const int led = 8; // led proti GND
const int RXled = 17; // led proti VCC
const int TXled = 30; // led proti VCC
const int C_led = 10; // led proti GND
#define UNUSED(x) (void)(x)
#define FAST_MOUSE 25
#define SLOW_MOUSE 1000
#define T_RUNC 80
#define T_RUN 128
#define T_CLIMBC 96
#define T_CLIMB1 900
#define T_CLIMB2 250
#define MOUSE_STEP_MAX 125
class Point { // {{{ int x; int y };  // Beware, Mouse can move only -128..127
  public:
int x;
int y;
Point():x(0),y(0){}; // zero constructor
Point(const Point &cp):x(cp.x),y(cp.y) {}; // copy constructor
Point(int _x, int _y):x(_x),y(_y) {}; // from int
bool isZero() {return (x==0 && y==0);};
void set(int _x, int _y) {x=_x;y=_y;};
void set(const Point &val) {x=val.x;y=val.y;};
void add(const Point &val) {x+=val.x;y+=val.y;};
void sub(const Point &val) {x-=val.x;y-=val.y;};
void negate() {x=-x;y=-y;};
void negX() {x=-x;};
void negY() {y=-y;};
void clipBy(int val) { // {{{ if val <0 set (0,0)
if (val <0) val=0;
x=(x>=0)?min(x,val):max(x,-val);
y=(y>=0)?min(y,val):max(y,-val);
}; // }}}
}; // }}}
Point DFS(2*275, 2*342); // DAGGERFALL Full_Screen
Point DFS2(275, 342); // DAGGERFALL Full_Screen / 2 = Center
Point DFS4(275/2, 342/2); // DAGGERFALL Full_Screen / 4 = moves
Point Mouse_at(0,0);  // Supposed position of mouse, updated by MouseMoveHere, could/should be set to (0,0) at start of any sequence of more movements
Point tgt; // temp variable for target of moving
bool MouseMoveHere( Point &tgt ) { // {{{ RELATIVE, TRUE=target reached, tgt=={0,0}; MODIFIES tgt,Mouse_at; Move mouse tovard tgt by moving MOUSE_STEP_MAX on each axe max : Point here={1234,-321}; while (!MouseMoveHere(here)){}; if (here.x==0 && here.y==0) {print("OK");};
if (tgt.isZero()) return true;
Point step(tgt);
step.clipBy(MOUSE_STEP_MAX);
tgt.sub(step);
Mouse_at.add(step);
//Serial.print(step.x);Serial.print(",");Serial.print(step.y);Serial.print(" => ");
//Serial.print(tgt.x);Serial.print(",");Serial.print(tgt.y);Serial.print(" => ");
//Serial.print(Mouse_at.x);Serial.print(",");Serial.print(Mouse_at.y);Serial.println();
Mouse.move(step.x,step.y);
return tgt.isZero();
}; //}}}
class Base{ // {{{
public:
virtual void start(){ stop_me=false;};                                    // initialise class for next round of cycles
virtual void restart(){ stop();};                                         // class button was pressed again, maybe stop it?
virtual void stop(){ stop_me=true;};                                      // prepare class for finishing as soon as possible
virtual unsigned long long pause(unsigned long x){ UNUSED(x); return 1;}; // pause ms before next cycle, 0..not changed; x=current internal state (nonzero)
virtual unsigned long next(unsigned long x){ UNUSED(x); return 0;};       // next internal state; x=current internal state (nonzero)
protected:
bool stop_me; // true = finish as soon as possible
}; // }}}
class Blink : public Base { // {{{
public:
virtual void start(){ stop_me=false; count=0;};
virtual void stop(){ stop_me=true; count=0;};
virtual unsigned long long pause(unsigned long x){ UNUSED(x); return 100;};
virtual unsigned long next(unsigned long x){ // {{{
if (x == 1) return 2;
if (stop_me) x=0; else if (!count) x=0; else {--count; x=1;};
return x;
}; // }}}
void set_count(byte x){ if (x) count=x-1; else count=0;};
private:
byte count;
}; // }}}
/* {{{ FAPCEO
// {{{ ROUTES
#define ROUTES 5
struct T_routes { Point go_there; long clicks; int wait; };
T_routes routes[ROUTES] = {
{ Point(800,0), 10, 0 }, // 11->case
{ Point(-200,150), 1, 0 }, // case->floor
{ Point(-600,-150), 1, 0 }, // floor->11
{ Point(800,400), 2, 0 }, // 11->upgrade
{ Point(-800,-400), 20*60-14, 0 }, // and back to 11 (~60 sec, -14 = other clicks)
};
// }}}
class FastClickLearn : public Base {  // {{{ 20 clicku/sec, ROUTE: 1 min fast click; 11->case; 10 click; case-> floor; click; floor -> 11; click; 11-> upgrade; click; upgrade ->11
public:
virtual void start(){ stop_me=false; Mouse_at.set(0,0); route_at=0; };
virtual unsigned long long pause(unsigned long x){ UNUSED(x); return 25;};
virtual unsigned long next(unsigned long x){  // {{{
T_routes *r; // temp
if (route_at>ROUTES) stop_me=true; // ERROR
if (stop_me) {x=0; Mouse.release(MOUSE_LEFT); tgt.set(Mouse_at); tgt.negate(); while (!MouseMoveHere(tgt)){}; return 0;}
switch (x) {
case 1: ++x; r=&routes[route_at];
wait=r->wait*4;
clicks=r->clicks;
tgt.set(r->go_there);
while (!MouseMoveHere(tgt)){}; // Move to current target
// break; // fall thru !!!
case 2: ++x; if (--clicks<0) { ++x; } else { Mouse.press(MOUSE_LEFT); }; break;
case 3: (clicks >0)? --x:++x; Mouse.release(MOUSE_LEFT); break;
case 4: if (--wait <0) ++x; else break; // if wait <=0 fall thru !!!
case 5: ++route_at; if (route_at >=ROUTES) route_at=0; x=1; break;
default: x=0;break;
};
return x;
}; // }}}
// case 2: MouseMoveHere(tgt);if (tgt.isZero()) ++x; break; // Move to next target
private:
unsigned int route_at;
int wait; long clicks;
}; // }}}
}}} */
class Recast : public Base { // {{{
public:
virtual void start(){ stop_me=false; count=20;};
virtual void restart(){ count+=20;};
virtual void stop(){ stop_me=true; count=0;};
virtual unsigned long long pause(unsigned long x){ UNUSED(x); return 70;};
virtual unsigned long next(unsigned long x){ // {{{
switch (x) {
case 1: ++x;Keyboard.press(KEY_END);break;
case 2: ++x;Keyboard.release(KEY_END);break;
case 3: ++x;Mouse.press(MOUSE_LEFT);break;
case 4:
if (stop_me) x=0; else if (!count) x=0; else {--count; x=1;}
Mouse.release(MOUSE_LEFT);
break;
default: x=0;break;
}
return x;
}; // }}}
private:
byte count;
}; // }}}
class ClickYes : public Base { // {{{
public:
virtual void start(){ stop_me=false; count=40;};
virtual void restart(){ count=+40;};
virtual void stop(){ stop_me=true; count=0;};
virtual unsigned long long pause(unsigned long x){ UNUSED(x); return FAST_MOUSE;};
virtual unsigned long next(unsigned long x){ // {{{
switch (x) {
case 1: ++x;Mouse.press(MOUSE_LEFT);break;
case 2: ++x;Mouse.release(MOUSE_LEFT);break;
case 3: ++x;Keyboard.press('y');break;
case 4:
if (stop_me) x=0; else if (!count) x=0; else {--count; x=1;}
Keyboard.release('y');
break;
default: x=0;break;
}
return x;
}; // }}}
private:
byte count;
}; // }}}
class Relearn : public Base { // {{{ Rest / Loiter / 3 hours / Enter } x 3 + Center / click / Training
public:
virtual unsigned long long pause(unsigned long x){ // {{{
unsigned long long p;
switch (x) {
case 15: case 115: case 215: p=6000;break; // 6sec = 3 hours countdown
case  1: case 101: case 201:
case  5: case 105: case 205:
case  9: case 109: case 209:
case 221: case 223:
case 220: case 222: case 224:
p=60;break; // time to actualise mouse
case 6: case 106: case 206: p=FAST_MOUSE+2;break; // longer click on camp
case  7: case 107: case 207:
case 18: case 118: case 218:
case 219: p=200;break; // time to actualise mouse - Trainer screen is slow
default: p=FAST_MOUSE;break;
};
return p;
}; // }}}
virtual unsigned long next(unsigned long x){ // {{{
switch (x) {
case  1: case 101: case 201:
case  2: case 102: case 202:
case  3: case 103: case 203: ++x;break;
case  4: case 104: case 204: ++x;tgt.set(DFS); while (!MouseMoveHere(tgt)){};break;
// ++x;Mouse.move(127,127,0);break;  // to right down
case  5: case 105: case 205:
++x; // Mouse.move(-120,-50);break;  // to Camp
case  6: case 106: case 206: ++x;Keyboard.press('r');break; // Mouse.click() is too fast, need press/release (Rest)
case  7: case 107: case 207: ++x;Keyboard.release('r');break;
case  8: case 108: case 208: ++x;tgt.set(-DFS2.x/2,-1.25*DFS2.y); while (!MouseMoveHere(tgt)){};break; // Mouse is  NOT accelerated over long fast moves (To Loiter)
case  9: case 109: case 209: ++x;break; // Mouse.move(0,-70,0);break;
case 10: case 110: case 210: ++x;Mouse.press(MOUSE_LEFT);break;
case 11: case 111: case 211: ++x;Mouse.release(MOUSE_LEFT);break;
case 12: case 112: case 212: ++x;Keyboard.press('3');break; // 3 hours
case 13: case 113: case 213: ++x;Keyboard.release('3');break;
case 14: case 114: case 214: ++x;Keyboard.press(KEY_RETURN);break;
case 15: case 115: case 215: ++x;Keyboard.release(KEY_RETURN);break; // wait here
// waiting for 3 hour countdown
case 16: case 116: case 216: ++x;Keyboard.press(KEY_RETURN);break;
case 17: case 117: case 217: ++x;Keyboard.release(KEY_RETURN);break;
// x3
case 18: case 118: case 218: ++x;break;
// 218->219 to Trainer; else back and again
case 19: case 119: ++x;tgt.set(60,300); while (!MouseMoveHere(tgt)){};break; // Mouse is NOT accelerated over long fast moves (Back To Loiter)
case 20: case 120: ++x;break; // Mouse.move(0,120,0);break;
case 21: case 121: x += (101-21); break; // loop: 23->101, 123->201
// To Trainer
case 219: ++x;tgt.set(DFS);while (!MouseMoveHere(tgt)){};break;
// click Trainer
case 220: ++x;tgt.set(-DFS2.x,-DFS2.y-78);while (!MouseMoveHere(tgt)){}; Mouse.press(MOUSE_LEFT);break;
case 221: ++x;Mouse.release(MOUSE_LEFT);break;
// Train?
case 222: ++x;Mouse.press(MOUSE_LEFT);break;
case 223: ++x;Mouse.release(MOUSE_LEFT);break;
// yes
case 224: ++x;Keyboard.press('y');break;
case 225: ++x;Keyboard.release('y');break;
//
default: x=0;break;
}
return x;
}; // }}}
}; // }}}
class Skills : public Base { // {{{ Open minor skills tab
public:
virtual unsigned long long pause(unsigned long x){ UNUSED(x); return FAST_MOUSE;};
virtual unsigned long next(unsigned long x){ // {{{
switch (x) {
case 1:
case 2:
case 3:
case 4:
++x;tgt.set(DFS);tgt.negX();tgt.add(tgt); while (!MouseMoveHere(tgt)){}; break;
case 5:
++x;Mouse.move(20,-20,0);break;
case 6: ++x;break;
case 7: ++x;Mouse.press(MOUSE_LEFT);break; // Mouse.click() is too fast, need press/release
case 8: ++x;Mouse.release(MOUSE_LEFT);break;
case 9: ++x;break;
case 10:
++x;Mouse.move(40,-75,0);break; // Mouse is accelerated over long fast moves
case 11: ++x;Mouse.press(MOUSE_LEFT);break;
case 12: ++x;Mouse.release(MOUSE_LEFT);break;
default: x=0;break;
};
return x;
}; // }}}
}; // }}}
class Swing : public Base { // {{{
public:
virtual void start(){ stop_me=false; count=20;};
virtual void restart(){ count+=20;};
virtual void stop(){ stop_me=true; count=0;};
virtual unsigned long long pause(unsigned long x){ if ((x ==4)) return 1.5*SLOW_MOUSE; else return FAST_MOUSE;};
virtual unsigned long next(unsigned long x){ // {{{
switch (x) {
case 1: ++x;tgt.set(DFS);tgt.negate(); while (!MouseMoveHere(tgt)){}; break;
case 2: ++x;tgt.set(DFS2.x,DFS4.y); while (!MouseMoveHere(tgt)){}; break;
case 3: ++x;Mouse.press(MOUSE_RIGHT);break;
case 4: ++x;tgt.set(0,DFS2.x/2); while (!MouseMoveHere(tgt)){}; break;
case 5: ++x;Mouse.release(MOUSE_RIGHT);break;
case 6: ++x;break;
case 7:
if (stop_me) x=0; else if (count<0) {x=0;count=0;} else {--count; x=1;};
break;
default: x=0;break;
};
return x;
}; // }}}
private:
int count;
}; // }}}
class T_run : public Base { // {{{
public:
virtual void start(){ stop_me=false; count+=T_RUNC;};
virtual void stop(){ stop_me=true; count=0;};
virtual unsigned long long pause(unsigned long x){ UNUSED(x); return T_RUN;};
virtual unsigned long next(unsigned long x){ // {{{
switch (x) {
case 1: ++x;Keyboard.press(KEY_UP_ARROW);break;
case 2: ++x;Keyboard.press('p');break;
case 3: ++x;Keyboard.release(KEY_UP_ARROW);break;
case 4: ++x;Keyboard.release('p');break;
case 5: ++x;Keyboard.press(KEY_DOWN_ARROW);break;
case 6: ++x;Keyboard.press('p');break;
case 7: ++x;Keyboard.release(KEY_DOWN_ARROW);break;
case 8:
if (stop_me) x=0; else if (!count) x=0; else {--count; x=1;}
Keyboard.release('p');
break;
default: x=0;break;
}
return x;
}; // }}}
private:
byte count;
}; // }}}
class T_climb : public Base { // {{{
public:
virtual void start(){ stop_me=false; count=+T_CLIMBC;};
virtual void stop(){ stop_me=true; count=0;};
virtual unsigned long long pause(unsigned long x){ return (x & 1)?T_CLIMB1:T_CLIMB2;};
virtual unsigned long next(unsigned long x){ // {{{
switch (x) {
case 1: ++x;Keyboard.press(KEY_UP_ARROW);break;
case 2:
if (stop_me) x=0; else if (!count) x=0; else {--count; x=1;}
Keyboard.release(KEY_UP_ARROW);
break;
default: x=0;break;
}
return x;
}; // }}}
private:
byte count;
}; // }}}
class Corners : public Base {  // {{{ TL/DR/TR/DL/Tl
public:
virtual unsigned long long pause(unsigned long x){ // {{{
unsigned long long p;
p=1000; // 1s
if (x==9) p=10;
return p;
}; // }}}
virtual unsigned long next(unsigned long x){  // {{{
switch (x) {
case 1:++x;//tgt.set(-1000,-1000); ++x;while (!MouseMoveHere(tgt)){delay(D);};break;
case 2:tgt.set(DFS2); ++x;while (!MouseMoveHere(tgt)){};break;
case 3:tgt.set(DFS2); ++x;while (!MouseMoveHere(tgt)){};break;
case 4:tgt.set(DFS2);tgt.negate(); ++x;while (!MouseMoveHere(tgt)){};break;
case 5:tgt.set(DFS2);tgt.negY(); ++x;while (!MouseMoveHere(tgt)){};break;
case 6:tgt.set(DFS2);tgt.negX(); ++x;while (!MouseMoveHere(tgt)){};break;
case 7:tgt.set(DFS2);tgt.negX(); ++x;while (!MouseMoveHere(tgt)){};break;
case 8:tgt.set(DFS2);tgt.negY(); ++x;while (!MouseMoveHere(tgt)){};break;
case 9:tgt.set(DFS2);tgt.negate(); ++x;while (!MouseMoveHere(tgt)){};break;
default: x=0;break;
}
return x;
}; // }}}
}; // }}}
class TestMove : public Base { // {{{ TL/DR/TR/DL/Tl
public:
virtual unsigned long long pause(unsigned long x){ // {{{
unsigned long long p;
p=FAST_MOUSE;
return p;
}; // }}}
virtual unsigned long next(unsigned long x){  // {{{
switch (x) {
case 1:tgt.set(DFS2); ++x;while (!MouseMoveHere(tgt)){};break;
case 2:tgt.set(DFS2); ++x;while (!MouseMoveHere(tgt)){};break;
case 3:tgt.set(-DFS2.x,-DFS2.y-78); ++x;while (!MouseMoveHere(tgt)){};break;
default: x=0;break;
}
return x;
}; // }}}
}; // }}}
class FastClick : public Base {  // {{{ 20 clicku / sec
public:
virtual unsigned long long pause(unsigned long x){ UNUSED(x); return 25;}; // 20 clicku/sec = 50ms / click = 25 ms / press/release
virtual void restart(){ stop_me = true;};
virtual unsigned long next(unsigned long x){ // {{{
// Serial.print(x);Serial.print(" -> ");
switch (x) {
case 1: ++x;Mouse.press(MOUSE_LEFT);break;
case 2:
if (stop_me) x=0; else { x=1;}
Mouse.release(MOUSE_LEFT);
break;
default: x=0;break;
};
// Serial.print(x);Serial.print(" => ");
return x;
}; // }}}
private:
byte count;
}; // }}}
#define DEFAULT_DELAY 25
#define DEFAULT_DEBOUNCE 100
unsigned long state = 0; // state of state automat - 0 = inactive; 1 = start state
Base *automat = NULL;
Base *next_automat = NULL;
unsigned long c_state = 0;
Blink *blink=new Blink;
// {{{ Automats
#define AUTOMATS 5
struct T_automat {Base *A; Base *B;};
T_automat automats[AUTOMATS] ={
{new Recast, new ClickYes}, // 1
{new T_run, new T_climb}, // 2
{new Relearn, new Skills}, // 3
{new FastClick, new Swing}, // 4
{new Recast, new Swing} // 5
// {new Corners, new TestMove},
};
// {new FastClick, new FastClickLearn},
//}}}
unsigned long long responseDelay = DEFAULT_DELAY; // repepeat delay between states
unsigned long long debounceDelay = DEFAULT_DEBOUNCE; // debounce delay of the button, in ms
bool somePressed=true; // pressed any button => digitalRead()==0
bool debouncing=false;
bool led_shines=false;
unsigned long milsDebounce;
unsigned long milsState;
unsigned long currentMillis;
void setup() { // {{{
Serial.begin(9600);
// initialize the buttons' inputs:
pinMode(button_B, INPUT_PULLUP);
pinMode(button_C, INPUT_PULLUP);
pinMode(button_A, INPUT_PULLUP);
pinMode(led, OUTPUT);
// initialize mouse control:
Mouse.begin();
Keyboard.begin();
milsDebounce=millis();
milsState=millis();
delay(1000);
Serial.println("Klikimouse5 2023.07.29 10:45:37 ");
Serial.println("{new Recast, new ClickYes}, // 1");
Serial.println("{new T_run, new T_climb}, // 2");
Serial.println("{new Relearn, new Skills}, // 3");
Serial.println("{new FastClick, new Swing}, // 4");
Serial.println("{new Recast, new Swing} // 5");
pinMode(RXled, OUTPUT);
pinMode(TXled, OUTPUT);
pinMode(C_led, OUTPUT);
digitalWrite(RXled,HIGH);
digitalWrite(TXled,HIGH);
digitalWrite(C_led,LOW);
   
} // }}}
void loop() {
digitalWrite(RXled,!((c_state+1) & _BV(0)));
digitalWrite(TXled,!((c_state+1) & _BV(1)));
digitalWrite(C_led, ((c_state+1) & _BV(2)));
currentMillis=millis(); // {{{ prolog
bool act_B= ! digitalRead(button_B);
bool act_C= ! digitalRead(button_C);
bool act_A= ! digitalRead(button_A);
if (debouncing and ((currentMillis-milsDebounce) >= debounceDelay)) {
debouncing = false;
};
// }}}
if (! debouncing) { // {{{ check for change
if ( (act_B || act_C || act_A) != somePressed){ // {{{ somePressed changed !
// {{{ start debouncing
milsDebounce=currentMillis;
somePressed=(act_B || act_C || act_A);
debouncing=true;
// }}}
if (act_C) { // act_C if possible
next_automat = NULL;
if (automat) automat->stop();
else {
if (++c_state >=AUTOMATS) c_state=0;
automat=blink;
automat->start();
responseDelay = automat->pause(state);
blink->set_count(c_state+1);
state = 1;
led_shines = false;
// Serial.println(c_state); // Serial běží "na pozadí" a bliká LEDkama
};
};
if (act_B) { // act_B if possible
if (automat && (automat == automats[c_state].B)) automat->restart();
else {
if (automat) automat->stop();
next_automat = automats[c_state].B;
};
};
if (act_A) { // act_A high priority
if (automat && (automat == automats[c_state].A)) automat->restart();
else {
if (automat) automat->stop();
next_automat = automats[c_state].A;
};
};
}; // }}}
}; // }}} ! debouncing
if ((currentMillis-milsState) >= responseDelay){ // {{{ next state
milsState = currentMillis; // next step
if (state == 0) {
if (automat) automat->stop();
automat = NULL;
responseDelay = DEFAULT_DELAY;
if (next_automat) {
state = 1;
automat = next_automat;
next_automat = NULL;
automat->start();
responseDelay = automat->pause(state);
led_shines = false;
};
};
if (state){
responseDelay = automat->pause(state);
state = automat->next(state);
// Serial.print((long)(void *)automat,HEX);Serial.print(":");
// Serial.println(state);
led_shines = !led_shines;
} else {
led_shines = false;
};
digitalWrite(led,led_shines);
}; // }}}
}