In [264]:
import time

import Quartz
from Quartz.CoreGraphics import CGEventCreateMouseEvent
from Quartz.CoreGraphics import CGEventPost
from Quartz.CoreGraphics import kCGEventMouseMoved
from Quartz.CoreGraphics import kCGEventLeftMouseDown
from Quartz.CoreGraphics import kCGEventLeftMouseDown
from Quartz.CoreGraphics import kCGEventLeftMouseUp
from Quartz.CoreGraphics import kCGMouseButtonLeft
from Quartz.CoreGraphics import kCGHIDEventTap

class State(object):
  x: int = 0
  y: int = 0

_STATE = State()

def mouse_event(type, x, y):
  _STATE.x = x
  _STATE.y = y
  e = CGEventCreateMouseEvent(
      None, 
      type, 
      (x, y), 
      kCGMouseButtonLeft)
  CGEventPost(kCGHIDEventTap, e)

def mouse_position():
  return Quartz.CGEventGetLocation(Quartz.CGEventCreate(None))
  
def mouse_move(x, y):
  global _LAST
  mouse_event(kCGEventMouseMoved, x, y);

def mouse_click(x=None, y=None, hold_ms=(50/1000)):
  if x is None and y is None and mouse_position() != (_STATE.x, _STATE.y):
    raise Exception('Mouse moved.')
  if x is None:
    x = _STATE.x
  if y is None:
    y = _STATE.y
  # uncomment this line if you want to force the mouse 
  # to MOVE to the click location first (I found it was not necessary).
  # mouse_event(kCGEventMouseMoved, x, y);
  time.sleep(5 / 1000)
  mouse_event(kCGEventLeftMouseDown, x, y);
  time.sleep(hold_ms)
  mouse_event(kCGEventLeftMouseUp, x, y);

In [265]:
mouse_position()


Out[265]:
<NSPoint x=376.45703125 y=519.0546875>

In [293]:
from pynput import keyboard

In [23]:
# LEVEL 1.
mouse_move(1300, 600)
for x in range(66):
  mouse_click()
  time.sleep(50 / 1000)

In [33]:
# LEVEL 2.
mouse_move(1300, 600)
for x in range(30):
  mouse_click()
  time.sleep(50 / 1000)

In [62]:
# LEVEL 3.
mouse_move(1300, 600)
for x in range(4, 18):
  mouse_click(hold_ms=(x * 500)/1000)
  time.sleep(500 / 1000)
  mouse_click(hold_ms=(x * 500 + 250)/1000)
  time.sleep(500 / 1000)


---------------------------------------------------------------------------
KeyboardInterrupt                         Traceback (most recent call last)
<ipython-input-62-ceeab2a99e78> in <module>()
      4   mouse_click(hold_ms=(x * 500)/1000)
      5   time.sleep(500 / 1000)
----> 6   mouse_click(hold_ms=(x * 500 + 250)/1000)
      7   time.sleep(500 / 1000)

<ipython-input-35-0d390b98591a> in mouse_click(x, y, hold_ms)
     40   time.sleep(5 / 1000)
     41   mouse_event(kCGEventLeftMouseDown, x, y);
---> 42   time.sleep(hold_ms)
     43   mouse_event(kCGEventLeftMouseUp, x, y);

KeyboardInterrupt: 

In [63]:
# LEVEL 4.
mouse_move(1300, 600)
for x in range(8):
  mouse_click(hold_ms=1000/1000)
  time.sleep(1000 / 1000)

In [255]:
CODE = {
  '.': '.',
  '-': '-',
  ' ': ' ',

  'A': '.-',     'B': '-...',   'C': '-.-.', 
  'D': '-..',    'E': '.',      'F': '..-.',
  'G': '--.',    'H': '....',   'I': '..',
  'J': '.---',   'K': '-.-',    'L': '.-..',
  'M': '--',     'N': '-.',     'O': '---',
  'P': '.--.',   'Q': '--.-',   'R': '.-.',
  'S': '...',    'T': '-',      'U': '..-',
  'V': '...-',   'W': '.--',    'X': '-..-',
  'Y': '-.--',   'Z': '--..',

  '0': '-----',  '1': '.----',  '2': '..---',
  '3': '...--',  '4': '....-',  '5': '.....',
  '6': '-....',  '7': '--...',  '8': '---..',
  '9': '----.',
}
def word_stats(s):
  symbols = [CODE[c] for c in s.upper()]
  return s, ' '.join(symbols), len(''.join(symbols))

In [237]:
for s in ['MARATHON', 'HORSE', 'RACE', 'PONY', 'EXAMPLE', 'ASCII']:
  print(word_stats(s))


('MARATHON', '-- .- .-. .- - .... --- -.', 19)
('HORSE', '.... --- .-. ... .', 14)
('RACE', '.-. .- -.-. .', 10)
('PONY', '.--. --- -. -.--', 13)
('EXAMPLE', '. -..- .- -- .--. .-.. .', 18)
('ASCII', '.- ... -.-. .. ..', 13)

In [219]:
# HORSE.
mouse_move(1300, 600)
mouse_click()  # Give focus.

DOT = 200  # ms
for c in 'HORSE':
  print('%s = %s' % (c, CODE[c]))
  for tone in CODE[c]:
    if tone == '.':
      mouse_click(hold_ms=DOT/1000)
    elif tone == '-':
      mouse_click(hold_ms=3*DOT/1000)
    time.sleep(DOT / 1000)
  time.sleep(3*DOT / 1000)


H = ....
O = ---
R = .-.
S = ...
E = .

In [239]:
# MARATHON.
mouse_move(1300, 600)
mouse_click()  # Give focus.

DOT = 75  # ms
for word in ['PONY', 'PONY']:
  for c in word:
    print(c, end=' ')
    for tone in CODE[c]:
      if tone == '.':
        print('.', end='')
        mouse_click(hold_ms=DOT/1000)
      elif tone == '-':
        print('-', end='')
        mouse_click(hold_ms=3*DOT/1000)
      time.sleep(DOT / 1000)
    print(end=' ')
    time.sleep(3*DOT / 1000)
  time.sleep(4*DOT / 1000)
  print()


P .--. O --- N -. Y -.-- 
P .--. O --- N -. Y -.-- 

In [317]:
# PASSKEY.
mouse_move(1300, 600)
mouse_click()  # Give focus.

DOT = 375  # ms
# CV S1 E1
for word in ['-.-. ...-- ... .---- . .---- .']:
  for c in word:
    if c in '.- ':
      print(c, end='')
    else:
      print(c, CODE[c], end=' ')
    for tone in CODE[c]:
      if tone == '.':
        mouse_click(hold_ms=DOT/1000)
      elif tone == '-':
        mouse_click(hold_ms=3*DOT/1000)
      if c not in '.-':
        time.sleep(DOT / 1000)
    time.sleep(2*DOT / 1000)
  print()
  time.sleep(4*DOT / 1000)  # 3 (above) + 4 (remaining) = 7


-.-. ...-- ... .---- . .---- .

In [275]:
# FAUCET.
mouse_move(1300, 600)
mouse_click()  # Give focus.

DOT = 750  # ms
for c in 'ASCII':
  print(c, CODE[c], end=' ')
  for tone in CODE[c]:
    if tone == '-':  # INVERTED
      mouse_click(hold_ms=DOT/1000)
    elif tone == '.':
      mouse_click(hold_ms=3*DOT/1000)
    time.sleep(DOT / 1000)
  time.sleep(3*DOT / 1000)
print()
time.sleep(7*DOT / 1000)


A .- S ... 
---------------------------------------------------------------------------
Exception                                 Traceback (most recent call last)
<ipython-input-275-723c02ab83a0> in <module>()
     10       mouse_click(hold_ms=DOT/1000)
     11     elif tone == '.':
---> 12       mouse_click(hold_ms=3*DOT/1000)
     13     time.sleep(DOT / 1000)
     14   time.sleep(3*DOT / 1000)

<ipython-input-264-9e8aedb7a65d> in mouse_click(x, y, hold_ms)
     36 def mouse_click(x=None, y=None, hold_ms=(50/1000)):
     37   if x is None and y is None and mouse_position() != (_STATE.x, _STATE.y):
---> 38     raise Exception('Mouse moved.')
     39   if x is None:
     40     x = _STATE.x

Exception: Mouse moved.

In [ ]: