diff --git a/gradint-build/PocketPC/gradint/setup.py b/gradint-build/PocketPC/gradint/setup.py
index 4a3ded2e27bc07843131dbf30a199c6ed6c1205d..e0461ae8927a6e532be24aa447ed2960d801ea43 100644
--- a/gradint-build/PocketPC/gradint/setup.py
+++ b/gradint-build/PocketPC/gradint/setup.py
@@ -2,25 +2,6 @@
 
 import os, py_compile, sys
 
-# shortcut
-progs="\\Windows\\Start Menu\\Programs"
-if not os.path.isdir(progs): progs="\\Windows\\Start Menu" # WM-Standard has no Programs subdir
-try:
-  if "Storage Card" in os.getcwd():
-    os.rename(os.getcwd()+"\\gradint-card.lnk",progs+"\\Gradint.lnk")
-    os.remove(os.getcwd()+"\\gradint-internal.lnk")
-  else:
-    os.rename(os.getcwd()+"\\gradint-internal.lnk",progs+"\\Gradint.lnk")
-    os.remove(os.getcwd()+"\\gradint-card.lnk")
-except: pass
-if not os.path.exists(progs+"\\Gradint.lnk"):
-  # TODO will it really get HERE if Application Lock is on?
-  raw_input("Failed to write to "+progs)
-  raw_input("is Application Lock on? Remove and try again.")
-  raise SystemExit
-  # http://www.mobilejaw.com/articles/2009/09/removing-application-lock-on-windows-mobile-standard-devices/
-  # -> http://www.mobilejaw.com/content/2009/09/MobileJaw-ClearSecurity-MobiControl.cab
-
 # Pre-compile - helps when the device is short of RAM,
 # since compiling and running at the same time
 # can take more RAM than doing it separately.
@@ -37,46 +18,53 @@ if a:
   try: os.remove(f) # leave the .pyc only
   except: pass
 
+# shortcut
+progs="\\Windows\\Start Menu\\Programs"
+if not os.path.isdir(progs): progs="\\Windows\\Start Menu" # WM-Standard has no Programs subdir
+try:
+  if "Storage Card" in os.getcwd():
+    os.rename(os.getcwd()+"\\gradint-card.lnk",progs+"\\Gradint.lnk")
+    os.remove(os.getcwd()+"\\gradint-internal.lnk")
+  else:
+    os.rename(os.getcwd()+"\\gradint-internal.lnk",progs+"\\Gradint.lnk")
+    os.remove(os.getcwd()+"\\gradint-card.lnk")
+except: pass
+
+fail={}
 def moveFiles(srcDir,destDir):
     try: os.mkdir(destDir)
     except: pass
     for f in os.listdir(srcDir):
-        if not "." in f:
-            c = os.getcwd() ; isDir=0
-            try:
-                os.chdir(srcDir+"\\"+f)
-                isDir = 1
-            except: pass
-            os.chdir(c)
-            if isDir:
-                moveFiles(srcDir+"\\"+f, destDir+"\\"+f)
-                continue
-        if os.path.exists(destDir+"\\"+f): os.remove(srcDir+"\\"+f)
-        else: os.rename(srcDir+"\\"+f,destDir+"\\"+f)
-    os.rmdir(srcDir)
+        if not "." in f and os.path.isdir(srcDir+"\\"+f):
+            moveFiles(srcDir+"\\"+f, destDir+"\\"+f)
+            continue
+        try:
+          if os.path.exists(destDir+"\\"+f): os.remove(srcDir+"\\"+f)
+          os.rename(srcDir+"\\"+f,destDir+"\\"+f)
+        except:
+          if not destDir in fail:
+            fail[destDir]=1
+            raw_input("Failed to write to "+destDir)
+            raw_input("Please do it manually in Explorer")
+            raw_input("or remove Application Lock if on")
+    try: os.rmdir(srcDir)
+    except: pass # follow-through
+# http://www.mobilejaw.com/articles/2009/09/removing-application-lock-on-windows-mobile-standard-devices/
+# -> http://www.mobilejaw.com/content/2009/09/MobileJaw-ClearSecurity-MobiControl.cab
 
-try: l=os.listdir(os.getcwd()+"\\espeak-data")
-except: l=0
-if l:
+if os.path.isdir(os.getcwd()+"\\espeak-data"):
   print "Installing eSpeak..."
   moveFiles(os.getcwd()+"\\espeak-data","\\espeak-data")
   if "Storage Card" in os.getcwd(): moveFiles(os.getcwd()+"\\bin","\\Storage Card\\bin")
   else: moveFiles(os.getcwd()+"\\bin","\\bin")
-try: l=os.listdir(os.getcwd()+"\\Program Files")
-except: l=0
-if l:
+if os.path.isdir(os.getcwd()+"\\Program Files"):
     print "Installing TkInter..."
-    try: moveFiles("\\Storage Card\\Windows","\\Windows")
-    except: pass
-    try:
-      if "Storage Card" in os.getcwd(): moveFiles(os.getcwd()+"\\Program Files","\\Storage Card\\Program Files")
-      else: moveFiles(os.getcwd()+"\\Program Files","\\Program Files")
-      # need to restart Python
-      raw_input("Setup successful - now run Gradint")
-    except:
-      raw_input("Failed to move Program Files")
-      raw_input("Please do it manually in Explorer")
-      raw_input("or remove Application Lock if on")
+    if "Storage Card" in os.getcwd():
+      if os.path.isdir("\\Storage Card\\Windows"):
+        moveFiles("\\Storage Card\\Windows","\\Windows")
+      moveFiles(os.getcwd()+"\\Program Files","\\Storage Card\\Program Files")
+    else: moveFiles(os.getcwd()+"\\Program Files","\\Program Files")
+    raw_input("Setup successful - now run Gradint")
     raise SystemExit
 
 # can now run
diff --git a/gradint-build/src/frontend.py b/gradint-build/src/frontend.py
index f939019046a275fa48b9331f869dba55c9289d19..5872be36328c85e9b27c8fb35410ee6428f0bcc5 100644
--- a/gradint-build/src/frontend.py
+++ b/gradint-build/src/frontend.py
@@ -97,6 +97,7 @@ def primitive_synthloop():
         if not lang: lang=oldLang
 
 def startBrowser(url): # true if success
+  if winCEsound: return None # user might be paying per byte! + difficult to switch back if no Alt-Tab program
   try: import webbrowser
   except: webbrowser=0
   if webbrowser:
@@ -188,7 +189,22 @@ def addTextBox(row,wide=0):
     entry = Tkinter.Entry(row,textvariable=text)
     if winsound or mingw32 or cygwin or macsound: entry.bind('<Button-3>',CXVMenu)
     if macsound: entry.bind('<Control-Button-1>',CXVMenu)
-    if winCEsound: # Try to detect long clicks. This is awkward. time.time is probably 1sec resolution so will get false +ves if go by that only.
+    if winCEsound:
+      if WMstandard: # non-numeric inputs no good on WMstandard Tkinter
+        def doRawInput(text,entry):
+            app.input_to_set = text
+            app.menu_response="input"
+        entry.bind('<Return>',lambda e:doRawInput(text,entry))
+        if wide: # put help in 1st wide textbox
+          global had_doRawInput
+          try: had_doRawInput
+          except:
+            had_doRawInput=1
+            text.set("(Push OK to type A-Z)")
+            class E: pass
+            e=E() ; e.widget = entry
+            entry.after(10,lambda *args:selectAll(e))
+      else: # PocketPC: try to detect long clicks. This is awkward. time.time is probably 1sec resolution so will get false +ves if go by that only.
         def timeStamp(entry): entry.buttonPressTime=time.time()
         entry.bind('<ButtonPress-1>',lambda e:timeStamp(entry))
         global lastDblclkAdvisory,lastDblclk
@@ -204,9 +220,8 @@ def addTextBox(row,wide=0):
             global lastDblclk ; lastDblclk=time.time()
         entry.bind('<ButtonRelease-1>',lambda e:pasteInstructions(time.time()-getattr(entry,"buttonPressTime",time.time())))
         entry.bind('<Double-Button-1>',lambda e:doPaste(text,entry))
-    else:
-        # Tkinter bug workaround (some versions): event_generate from within a key event handler can be unreliable, so the Ctrl-A handler delays selectAll by 10ms:
-        entry.bind(cond(macsound,'<Command-a>','<Control-a>'),(lambda e:e.widget.after(10,lambda e=e:selectAll(e))))
+    # Tkinter bug workaround (some versions): event_generate from within a key event handler can be unreliable, so the Ctrl-A handler delays selectAll by 10ms:
+    entry.bind(cond(macsound,'<Command-a>','<Control-a>'),(lambda e:e.widget.after(10,lambda e=e:selectAll(e))))
     bindUpDown(entry,False)
     if wide=="nopack": pass
     elif wide:
@@ -398,6 +413,8 @@ def focusButton(button):
           app.after(t+150,lambda *args:flashButton(button,"normal"))
         # (Don't like flashing, but can't make it permanently active as it won't change when the focus does)
 
+if WMstandard: GUI_omit_statusline = 1 # unlikely to be room (and can disrupt nav)
+
 def startTk():
     class Application(Tkinter.Frame):
         def __init__(self, master=None):
@@ -408,6 +425,7 @@ def startTk():
             make_extra_buttons_waiting_list()
             if olpc: self.master.option_add('*font',cond(extra_buttons_waiting_list,'Helvetica 9','Helvetica 14'))
             elif macsound and Tkinter.TkVersion>=8.6: self.master.option_add('*font','System 13') # ok with magnification.  Note >13 causes square buttons.  (Including this line causes "Big print" to work)
+            elif WMstandard: self.master.option_add('*font','Helvetica 7') # TODO on ALL WMstandard devices?
             if winsound or cygwin or macsound: self.master.resizable(1,0) # resizable in X direction but not Y (latter doesn't make sense, see below).  (Don't do this on X11 because on some distros it results in loss of automatic expansion as we pack more widgets.)
             self.extra_button_callables = []
             self.pack(fill=Tkinter.BOTH,expand=1)
@@ -569,6 +587,9 @@ def startTk():
             if hasattr(self.todo,"undoRecordFrom"):
                 theRecorderControls.undoRecordFrom()
                 del self.todo.undoRecordFrom
+            if hasattr(self.todo,"input_response"): # WMstandard
+                self.input_to_set.set(self.todo.input_response)
+                del self.todo.input_response,self.input_to_set
             if hasattr(self.todo,"exit_ASAP"):
                 self.master.destroy()
                 self.pollInterval = 0
@@ -747,10 +768,11 @@ def startTk():
             self.TestEtcCol = addRow(self.row1) # effectively adding a column to the end of the row, for "Speak" and any other buttons to do with 2nd-language text (although be careful not to add too many due to tabbing)
             self.TestTextButton = addButton(self.TestEtcCol,"",self.testText,status="Use this button to check how the\ncomputer will pronounce words before you add them") # will set text in updateLanguageLabels
             self.Label2,self.Text2,self.Entry2 = addLabelledBox(self.row2,True)
-            self.Entry1.bind('<Return>',self.testText)
-            self.Entry1.bind('<F5>',self.debugText)
-            self.Entry2.bind('<Return>',self.addText)
-            for e in [self.Entry1,self.Entry2]: addStatus(e,"Enter a word or phrase to add or to test\nor to search your existing collection",mouseOnly=1)
+            if not WMstandard:
+              self.Entry1.bind('<Return>',self.testText)
+              self.Entry1.bind('<F5>',self.debugText)
+              self.Entry2.bind('<Return>',self.addText)
+              for e in [self.Entry1,self.Entry2]: addStatus(e,"Enter a word or phrase to add or to test\nor to search your existing collection",mouseOnly=1)
             self.AddButton = addButton(self.row2,"",self.addText,status="Adds the pair to your vocabulary collection\nor adds extra revision if it's already there") # will set text in updateLanguageLabels
             self.L1Label,self.L1Text,self.L1Entry = addLabelledBox(self.row3,status="The abbreviation of your\nfirst (i.e. native) language")
             self.L2Label,self.L2Text,self.L2Entry = addLabelledBox(self.row3,status="The abbreviation of the other\nlanguage that you learn most")
@@ -865,7 +887,7 @@ def startTk():
             self.AddButton["text"] = localise("Add to %s") % gui_vocabFile_name
             self.ChangeLanguageButton["text"] = localise("Change languages")
             self.ChangeButton["text"] = localise("Change or delete item")
-            if hasattr(self,"EditVocabButton"): self.EditVocabButton["text"] = localise(textEditorName)+" "+gui_vocabFile_name
+            if hasattr(self,"EditVocabButton"): self.EditVocabButton["text"] = cond(WMstandard,gui_vocabFile_name,localise(textEditorName)+" "+gui_vocabFile_name) # (save as much space as possible on WMstandard by omitting the "Edit " verb)
             if hasattr(self,"RecordedWordsButton"): self.RecordedWordsButton["text"] = localise("Recorded words")
         def wrongMouseButton(self,*args): self.todo.alert="Please use the OTHER mouse button when clicking on list and button controls." # Simulating it is awkward.  And we might as well teach them something.
         def getListItem(self,*args):
@@ -1245,7 +1267,9 @@ def gui_event_loop():
             if emulated_interruptMain: check_for_interrupts()
             time.sleep(0.3)
         menu_response = app.menu_response
-        if menu_response=="go":
+        if menu_response=="input": # WMstandard
+            app.todo.input_response=raw_input()
+        elif menu_response=="go":
             gui_outputTo_start()
             if not soundCollector: app.todo.add_briefinterrupt_button = 1
             try: lesson_loop()
diff --git a/gradint-build/src/system.py b/gradint-build/src/system.py
index 7c2a96cd75ce5a8d9fdda0dc94741182d3291921..4c8be33c68ce66eb310a7d27d58e98b87c2a277c 100644
--- a/gradint-build/src/system.py
+++ b/gradint-build/src/system.py
@@ -51,7 +51,7 @@ if appuifw:
     appuifw.app.menu=[(u"Brief interrupt",s60_briefInt),(u"Cancel lesson",s60_interrupt)]
     appuifw.app.exit_key_handler = s60_interrupt
 
-winCEsound = msvcrt = None
+winCEsound = msvcrt = WMstandard = None
 if winsound:
     try: import msvcrt
     except: msvcrt = None # missing
@@ -60,6 +60,8 @@ if winsound:
         import ctypes # if that fails (pre-2.5, pre-Windows Mobile 2003) then we can't do much
         import ctypes.wintypes as wintypes
         class ShellExecuteInfo(ctypes.Structure): _fields_ = [("cbSize",wintypes.DWORD),("fMask",wintypes.ULONG),("hwnd",wintypes.HWND),("Verb",ctypes.c_wchar_p),("File",ctypes.c_wchar_p),("Parameters",ctypes.c_wchar_p),("Directory",ctypes.c_wchar_p),("nShow",ctypes.c_int),("hInstApp",wintypes.HINSTANCE),("IDList",ctypes.c_void_p),("Class",ctypes.c_wchar_p),("hkeyClass",wintypes.HKEY),("dwHotKey",wintypes.DWORD),("hIconOrMonitor",wintypes.HANDLE),("hProcess",wintypes.HANDLE)]
+        try: ctypes.cdll.commdlg
+        except: WMstandard = True
 
 if macsound and __name__=="__main__": os.system("clear 1>&2") # so warnings etc start with a clear terminal (1>&2 just in case using stdout for something else)
 if riscos_sound: sys.stderr.write("Loading Gradint...\n") # in case it takes a while