KlikiMouse3.ino (Source)

/*
Klikimouse3 aneb objects forever!
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;
#define UNUSED(x) (void)(x)
#define FAST_MOUSE 25
class Base{ // {{{
public:
virtual void start(){ stop_me=false;};                          // initialise class for next round of cycles
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;
}; // }}}
class Recast : public Base { // {{{
public:
virtual void start(){ stop_me=false; count=10;};
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('c');break;
case 2: ++x;Keyboard.release('c');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 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:
p=60;break; // time to actualise mouse
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:
case  4: case 104: case 204:
++x;Mouse.move(127,127,0);break;
case  5: case 105: case 205:
++x;Mouse.move(-60,-20,0);break;
case  6: case 106: case 206: ++x;Mouse.press(MOUSE_LEFT);break; //  Mouse.click() is too fast, need press/release (Rest)
case  7: case 107: case 207: ++x;Mouse.release(MOUSE_LEFT);break;
case  8: case 108: case 208: ++x;Mouse.move(-20,-120,0);break; // Mouse is accelerated over long fast moves (To Loiter)
case  9: case 109: case 209: ++x;Mouse.move(0,-60,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;Mouse.move(20,120,0);break; // Mouse is accelerated over long fast moves (Back To Loiter)
case 20: case 120: ++x;Mouse.move(0,120,0);break;
case 21: case 121: x += (101-21); break; // loop: 23->101, 123->201
// To Trainer
case 219: ++x;Mouse.move(-80,-30,0);break;
// click Trainer
case 220: ++x;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;Mouse.move(-127,127,0);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 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;Mouse.move(-127,127,0);break;
case 5:
++x;Mouse.move(127,-120,0);break;
case 6: ++x;break;
case 7: ++x;Mouse.press(MOUSE_RIGHT);break; //  Mouse.click() is too fast, need press/release
case 8: ++x;Mouse.move(0,-120,0);break;
case 9: ++x;break;
case 10: ++x;Mouse.release(MOUSE_RIGHT);break;
case 11: ++x;break;
case 12: if (stop_me) x=0; else x=3;break; // infinite loop
default: x=0;break;
};
return x;
}; // }}}
}; // }}}
#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 3
struct T_automat {Base *A; Base *B;};
T_automat automats[AUTOMATS] ={
{new Recast, new ClickYes},
{new Relearn, new Skills},
{new Recast, new Swing}
};
//}}}
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() { // {{{
// 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();
} // }}}
void loop() {
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;
};
};
if (act_B) { // act_B if possible
if (automat) automat->stop();
next_automat = automats[c_state].B;
};
if (act_A) { // act_A high priority
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);
led_shines = !led_shines;
} else {
led_shines = false;
};
digitalWrite(led,led_shines);
}; // }}}
}