ref: 0fa5d9a16217993922c88f7ec83ae99857a31267
parent: a1ed7e76583127562c73bf12766ba2958451b9dc
author: Bryan Bishop <[email protected]>
date: Sun Mar 3 22:08:00 EST 2013
vba - keyboard input optimization
--- a/extras/vba.py
+++ b/extras/vba.py
@@ -104,6 +104,11 @@
from vba_config import *
+try:
+ import vba_keyboard as keyboard
+except ImportError:
+ print "Not loading the keyboard module (which uses networkx)."
+
if not os.path.exists(rom_path):
raise Exception("rom_path is not configured properly; edit vba_config.py?")
@@ -163,6 +168,10 @@
buttons.replace("select", "")
result |= button_masks["select"]
+ if isinstance(buttons, list):
+ if len(buttons) > 9:
+ raise Exception("can't combine more than 9 buttons at a time")
+
for each in buttons:
result |= button_masks[each]
@@ -827,6 +836,25 @@
return output
@staticmethod
+ def keyboard_apply(button_sequence):
+ """
+ Applies a sequence of buttons to the on-screen keyboard.
+ """
+ for buttons in button_sequence:
+ press(buttons)
+ nstep(2)
+ press([])
+
+ @staticmethod
+ def write(something="TrAiNeR"):
+ """
+ Uses a planning algorithm to type out a word in the most efficient way
+ possible.
+ """
+ button_sequence = keyboard.plan_typing(something)
+ crystal.keyboard_apply([[x] for x in button_sequence])
+
+ @staticmethod
def set_partymon2():
"""
This causes corruption, so it's not working yet.
@@ -895,6 +923,14 @@
text = crystal.get_text()
self.assertTrue("TRAINER" in text)
+
+class TestWriter(unittest.TestCase):
+ def test_very_basic(self):
+ button_sequence = keyboard.plan_typing("an")
+ expected_result = ["select", "a", "d", "r", "r", "r", "r", "a"]
+
+ self.assertEqual(len(expected_result), len(button_sequence))
+ self.assertEqual(expected_result, button_sequence)
if __name__ == "__main__":
unittest.main()
--- /dev/null
+++ b/extras/vba_keyboard.py
@@ -1,0 +1,563 @@
+# -*- encoding: utf-8 -*-
+"""
+This file constructs a networkx.DiGraph object called graph, which can be used
+to find the shortest path of keypresses on the keyboard to type a word.
+"""
+
+import itertools
+import networkx
+
+graph = networkx.DiGraph()
+
+graph_data = """
+A a select
+A B r
+A I l
+A lower-upper-column-1 u
+A J d
+
+B b select
+B A l
+B C r
+B lower-upper-column-2 u
+B K d
+
+C c select
+C D r
+C B l
+C lower-upper-column-3 u
+C L d
+
+D d select
+D E r
+D C l
+D del-upper-column-1 u
+D M d
+
+E e select
+E del-upper-column-2 u
+E N d
+E D l
+E F r
+
+F f select
+F del-upper-column-3 u
+F O d
+F E l
+F G r
+
+G g select
+G end-upper-column-1 u
+G P d
+G F l
+G H r
+
+H h select
+H end-upper-column-2 u
+H Q d
+H G l
+H I r
+
+I i select
+I end-upper-column-3 u
+I R d
+I H l
+I A r
+
+J j select
+J A u
+J S d
+J R l
+J K r
+
+K k select
+K B u
+K T d
+K J l
+K L r
+
+L l select
+L C u
+L U d
+L K l
+L M r
+
+M m select
+M D u
+M V d
+M L l
+M N r
+
+N n select
+N E u
+N W d
+N M l
+N O r
+
+O o select
+O F u
+O X d
+O N l
+O P r
+
+P p select
+P G u
+P Y d
+P O l
+P Q r
+
+Q q select
+Q H u
+Q Z d
+Q P l
+Q R r
+
+R r select
+R I u
+R space-upper-x8-y2 d
+R Q l
+R J r
+
+S s select
+S J u
+S - d
+S space-upper-x8-y2 l
+
+T t select
+T K u
+T ? d
+T S l
+T U r
+
+U u select
+U L u
+U ! d
+U T l
+U V r
+
+V v select
+V M u
+V / d
+V U l
+V W r
+
+W w select
+W N u
+W . d
+W V l
+W X r
+
+X x select
+X O u
+X , d
+X W l
+X Y r
+
+Y y select
+Y P u
+Y space-upper-x6-y3 d
+Y X l
+Y Z r
+
+Z z select
+Z Q u
+Z space-upper-x7-y3 d
+Z Y l
+Z space-upper-x8-y2 r
+
+end-upper-column-1 lower-upper-column-1 r
+end-upper-column-2 lower-upper-column-1 r
+end-upper-column-3 lower-upper-column-1 r
+end-upper-column-1 del-upper-column-1 l
+end-upper-column-2 del-upper-column-1 l
+end-upper-column-3 del-upper-column-1 l
+lower-upper-column-1 end-upper-column-1 l
+lower-upper-column-2 end-upper-column-1 l
+lower-upper-column-3 end-upper-column-1 l
+lower-upper-column-1 del-upper-column-1 r
+lower-upper-column-2 del-upper-column-1 r
+lower-upper-column-3 del-upper-column-1 r
+del-upper-column-1 lower-upper-column-1 l
+del-upper-column-2 lower-upper-column-1 l
+del-upper-column-3 lower-upper-column-1 l
+del-upper-column-1 end-upper-column-1 r
+del-upper-column-2 end-upper-column-1 r
+del-upper-column-3 end-upper-column-1 r
+
+lower-upper-column-1 A d
+lower-upper-column-2 B d
+lower-upper-column-3 C d
+lower-upper-column-1 - u
+lower-upper-column-2 ? u
+lower-upper-column-3 ! u
+
+del-upper-column-1 D d
+del-upper-column-2 E d
+del-upper-column-3 F d
+del-upper-column-1 / u
+del-upper-column-2 . u
+del-upper-column-3 , u
+
+end-upper-column-1 G d
+end-upper-column-2 H d
+end-upper-column-3 I d
+end-upper-column-1 space-upper-x6-y3 u
+end-upper-column-2 space-upper-x7-y3 u
+end-upper-column-3 space-upper-x8-y3 u
+
+space-upper-x8-y2 space-lower-x8-y2 select
+space-upper-x8-y2 R u
+space-upper-x8-y2 space-upper-x8-y3 d
+space-upper-x8-y2 Z l
+space-upper-x8-y2 S r
+
+space-upper-x8-y3 MN select
+space-upper-x8-y3 space-upper-x8-y2 u
+space-upper-x8-y3 end-upper-column-3 d
+space-upper-x8-y3 space-upper-x7-y3 l
+space-upper-x8-y3 - r
+
+space-upper-x7-y3 PK select
+space-upper-x7-y3 Z u
+space-upper-x7-y3 end-upper-column-2 d
+space-upper-x7-y3 space-upper-x6-y3 l
+space-upper-x7-y3 space-upper-x8-y3 r
+
+space-upper-x6-y3 ] select
+space-upper-x6-y3 Y u
+space-upper-x6-y3 end-upper-column-1 d
+space-upper-x6-y3 , l
+space-upper-x6-y3 space-upper-x7-y3 r
+
+end-upper-column-1 end-lower-column-1 select
+end-upper-column-2 end-lower-column-2 select
+end-upper-column-3 end-lower-column-3 select
+lower-upper-column-1 lower-lower-column-1 select
+lower-upper-column-2 lower-lower-column-2 select
+lower-upper-column-3 lower-lower-column-3 select
+del-upper-column-1 del-lower-column-1 select
+del-upper-column-2 del-lower-column-2 select
+del-upper-column-3 del-lower-column-3 select
+
+lower-lower-column-1 × u
+lower-lower-column-2 ( u
+lower-lower-column-3 ) u
+lower-lower-column-1 a d
+lower-lower-column-2 b d
+lower-lower-column-3 c d
+
+end-lower-column-1 ] u
+end-lower-column-2 PK u
+end-lower-column-3 MN u
+end-lower-column-1 g d
+end-lower-column-2 h d
+end-lower-column-3 i d
+
+del-lower-column-1 : u
+del-lower-column-2 ; u
+del-lower-column-3 [ u
+del-lower-column-1 d d
+del-lower-column-2 e d
+del-lower-column-3 f d
+
+- × select
+- S u
+- lower-upper-column-1 d
+- space-upper-x8-y3 l
+- ? r
+
+? ( select
+? T u
+? lower-upper-column-2 d
+? - l
+? ! r
+
+! ) select
+! U u
+! lower-upper-column-3 d
+! ? l
+! / r
+
+/ : select
+/ V u
+/ del-upper-column-1 d
+/ ! l
+/ . r
+
+. ; select
+. W u
+. del-upper-column-2 d
+. / l
+. , r
+
+, [ select
+, X u
+, del-upper-column-3 d
+, . l
+, space-upper-x6-y3 r
+
+× - select
+× s u
+× upper-lower-column-1 d
+× MN l
+× ( r
+
+( ? select
+( t u
+( upper-lower-column-2 d
+( × l
+( ) r
+
+) ! select
+) u u
+) upper-lower-column-3 d
+) ( l
+) : r
+
+: / select
+: v u
+: del-lower-column-1 d
+: ) l
+: ; r
+
+; . select
+; w u
+; del-lower-column-2 d
+; : l
+; [ r
+
+[ , select
+[ x u
+[ del-lower-column-3 d
+[ ; l
+[ ] r
+
+] space-upper-x6-y3 select
+] y u
+] end-lower-column-1 d
+] [ l
+] PK r
+
+PK space-upper-x7-y3 select
+PK z u
+PK end-lower-column-2 d
+PK ] l
+PK MN r
+
+MN space-upper-x8-y3 select
+MN space-lower-x8-y2 u
+MN end-lower-column-3 d
+MN PK l
+MN × r
+
+space-lower-x8-y2 space-upper-x8-y2 select
+space-lower-x8-y2 r u
+space-lower-x8-y2 MN d
+space-lower-x8-y2 z l
+space-lower-x8-y2 s r
+
+a A select
+a upper-lower-column-1 u
+a j d
+a i l
+a b r
+
+b B select
+b upper-lower-column-2 u
+b k d
+b a l
+b c r
+
+c C select
+c upper-lower-column-3 u
+c l d
+c b l
+c d r
+
+d D select
+d del-lower-column-1 u
+d m d
+d c l
+d e r
+
+e E select
+e del-lower-column-2 u
+e n d
+e d l
+e f r
+
+f F select
+f del-lower-column-3 u
+f o d
+f e l
+f g r
+
+g G select
+g end-lower-column-1 u
+g p d
+g f l
+g h r
+
+h H select
+h end-lower-column-2 u
+h q d
+h g l
+h i r
+
+i I select
+i end-lower-column-3 u
+i r d
+i h l
+i a r
+
+j J select
+j a u
+j s d
+j r l
+j k r
+
+k K select
+k b u
+k t d
+k j l
+k l r
+
+l L select
+l c u
+l u d
+l k l
+l m r
+
+m M select
+m d u
+m v d
+m l l
+m n r
+
+n N select
+n e u
+n w d
+n m l
+n o r
+
+o O select
+o f u
+o x d
+o n l
+o p r
+
+p P select
+p g u
+p y d
+p o l
+p q r
+
+q Q select
+q h u
+q z d
+q p l
+q r r
+
+r R select
+r i u
+r space-lower-x8-y2 d
+r q l
+r j r
+
+s S select
+s j u
+s × d
+s space-lower-x8-y2 l
+s t r
+
+t T select
+t k u
+t ( d
+t s l
+t u r
+
+u U select
+u l u
+u ) d
+u t l
+u v r
+
+v V select
+v m u
+v : d
+v u l
+v w r
+
+w W select
+w n u
+w ; d
+w v l
+w x r
+
+x X select
+x o u
+x [ d
+x w l
+x y r
+
+y Y select
+y p u
+y ] d
+y x l
+y z r
+
+z Z select
+z q u
+z PK d
+z y l
+z space-lower-x8-y2 r"""
+
+for line in graph_data.split("\n"):
+ if line == "":
+ continue
+ elif line[0] == "#":
+ continue
+
+ (node1, node2, edge_name) = line.split(" ")
+ graph.add_edge(node1, node2, key=edge_name)
+
+ #print "Adding edge ("+edge_name+") "+node1+" -> "+node2
+
+def shortest_path(node1, node2):
+ """
+ Figures out the shortest list of button presses to move from one letter to
+ another.
+ """
+ buttons = []
+ last = None
+ path = networkx.shortest_path(graph, node1, node2)
+ for each in path:
+ if last != None:
+ buttons.append(convert_nodes_to_button_press(last, each))
+ last = each
+ return buttons
+ #return [convert_nodes_to_button_press(node3, node4) for (node3, node4) in zip(*(iter(networkx.shortest_path(graph, node1, node2)),) * 2)]
+
+def convert_nodes_to_button_press(node1, node2):
+ """
+ Determines the button necessary to switch from node1 to node2.
+ """
+ print "getting button press for state transition: " + node1 + " -> " + node2
+ return graph.get_edge_data(node1, node2)["key"]
+
+def plan_typing(text, current="A"):
+ """
+ Plans a sequence of button presses to spell out the given text.
+ """
+ buttons = []
+ for target in text:
+ if target == current:
+ buttons.append("a")
+ else:
+ print "Finding the shortest path between " + current + " and " + target
+ more_buttons = shortest_path(current, target)
+ buttons.extend(more_buttons)
+ buttons.append("a")
+ current = target
+ return buttons
+