shithub: puzzles

Download patch

ref: 15f70f527a0a753285e3fa871bd4018e547fbb05
parent: 3bfe0fb32eae41dcc213e1cef860ec421cc2540c
author: Simon Tatham <[email protected]>
date: Mon Feb 26 15:35:47 EST 2007

Dariusz Olszewski's changes to support compiling for PocketPC. This
is mostly done with ifdefs in windows.c; so mkfiles.pl generates a
new makefile (Makefile.wce) and Recipe enables it, but it's hardly
any different from Makefile.vc apart from a few definitions at the
top of the files.

Currently the PocketPC build is not enabled in the build script, but
with any luck I'll be able to do so reasonably soon.

[originally from svn r7337]

--- a/LICENCE
+++ b/LICENCE
@@ -1,7 +1,7 @@
 This software is copyright (c) 2004-2007 Simon Tatham.
 
-Portions copyright Richard Boulton, James Harvey, Mike Pinna and
-Jonas K�lker.
+Portions copyright Richard Boulton, James Harvey, Mike Pinna, Jonas
+K�lker and Dariusz Olszewski.
 
 Permission is hereby granted, free of charge, to any person
 obtaining a copy of this software and associated documentation files
--- a/Recipe
+++ b/Recipe
@@ -10,6 +10,7 @@
 
 !makefile gtk Makefile
 !makefile vc Makefile.vc
+!makefile wce Makefile.wce
 !makefile cygwin Makefile.cyg
 !makefile osx Makefile.osx
 
@@ -89,6 +90,11 @@
 	cl $(VER) $(CFLAGS) /c version.c
 !end
 !specialobj vc version
+!begin wce
+version.obj: *.c *.h
+	$(CC) $(VER) $(CFLAGS) /c version.c
+!end
+!specialobj wce version
 !begin cygwin
 version.o: FORCE;
 FORCE:
--- a/blackbox.c
+++ b/blackbox.c
@@ -1431,7 +1431,7 @@
     FALSE, FALSE, game_print_size, game_print,
     TRUE,			       /* wants_statusbar */
     FALSE, game_timing_state,
-    0,				       /* flags */
+    REQUIRE_RBUTTON,		       /* flags */
 };
 
 /* vim: set shiftwidth=4 tabstop=8: */
--- a/bridges.c
+++ b/bridges.c
@@ -2662,7 +2662,7 @@
     TRUE, FALSE, game_print_size, game_print,
     FALSE,			       /* wants_statusbar */
     FALSE, game_timing_state,
-    0,				       /* flags */
+    REQUIRE_RBUTTON,		       /* flags */
 };
 
 /* vim: set shiftwidth=4 tabstop=8: */
--- a/filling.c
+++ b/filling.c
@@ -47,7 +47,6 @@
 
 #include <assert.h>
 #include <ctype.h>
-#include <errno.h>
 #include <math.h>
 #include <stdio.h>
 #include <stdlib.h>
@@ -984,9 +983,8 @@
         new_state->cheated = TRUE;
     } else {
         char *endptr;
-        const int i = strtol(move, &endptr, errno = 0);
+        const int i = strtol(move, &endptr, 0);
         int value;
-        if (errno == ERANGE) return NULL;
         if (endptr == move) return NULL;
         if (*endptr != '_') return NULL;
         move = endptr + 1;
--- a/galaxies.c
+++ b/galaxies.c
@@ -3234,7 +3234,7 @@
     FALSE,			       /* wants_statusbar */
 #endif
     FALSE, game_timing_state,
-    0,				       /* flags */
+    REQUIRE_RBUTTON,		       /* flags */
 };
 
 #ifdef STANDALONE_SOLVER
--- a/icons/Makefile
+++ b/icons/Makefile
@@ -126,7 +126,8 @@
 
 # Build the .RC files which bind the icons into the applications.
 $(RC): %.rc:
-	echo '200 ICON "$*.ico"' > $@
+	echo '#include "puzzles.rc2"' > $@
+	echo '200 ICON "$*.ico"' >> $@
 
 # Build the GTK icon source files.
 $(CICONS): %-icon.c: %-16d24.png %-32d24.png %-48d24.png
--- a/inertia.c
+++ b/inertia.c
@@ -88,8 +88,11 @@
     game_params *ret = snew(game_params);
 
     ret->w = 10;
+#ifdef PORTRAIT_SCREEN
+    ret->h = 10;
+#else
     ret->h = 8;
-
+#endif
     return ret;
 }
 
@@ -106,9 +109,15 @@
 }
 
 static const struct game_params inertia_presets[] = {
+#ifdef PORTRAIT_SCREEN
+    { 10, 10 },
+    { 12, 12 },
+    { 16, 16 },
+#else
     { 10, 8 },
     { 15, 12 },
     { 20, 16 },
+#endif
 };
 
 static int game_fetch_preset(int i, char **name, game_params **params)
@@ -1511,7 +1520,11 @@
 
 #define PREFERRED_TILESIZE 32
 #define TILESIZE (ds->tilesize)
+#ifdef SMALL_SCREEN
+#define BORDER    (TILESIZE / 4)
+#else
 #define BORDER    (TILESIZE)
+#endif
 #define HIGHLIGHT_WIDTH (TILESIZE / 10)
 #define COORD(x)  ( (x) * TILESIZE + BORDER )
 #define FROMCOORD(x)  ( ((x) - BORDER + TILESIZE) / TILESIZE - 1 )
--- a/latin.c
+++ b/latin.c
@@ -12,6 +12,11 @@
 
 #include "latin.h"
 
+static void assert_f(p)
+{
+    assert(p);
+}
+
 /* --------------------------------------------------------
  * Solver.
  */
@@ -26,7 +31,7 @@
     int i, o = solver->o;
 
     assert(n <= o);
-    assert(cube(x,y,n));
+    assert_f(cube(x,y,n));
 
     /*
      * Rule out all other numbers in this square.
@@ -1188,7 +1193,7 @@
 		lcp = snew(lcparams);
 		lcp->elt = ELT(sq, c, r);
 		lcp->count = 1;
-		assert(add234(dict, lcp) == lcp);
+		assert_f(add234(dict, lcp) == lcp);
 	    } else {
 		lcp->count++;
 	    }
--- a/loopy.c
+++ b/loopy.c
@@ -512,9 +512,11 @@
     { 15, 15, DIFF_EASY, 0 },
     { 15, 15, DIFF_NORMAL, 0 },
     { 15, 15, DIFF_HARD, 0 },
+#ifndef SMALL_SCREEN
     { 30, 20, DIFF_EASY, 0 },
     { 30, 20, DIFF_NORMAL, 0 },
     { 30, 20, DIFF_HARD, 0 }
+#endif
 #endif
 };
 
--- a/map.c
+++ b/map.c
@@ -100,8 +100,13 @@
 {
     game_params *ret = snew(game_params);
 
+#ifdef PORTRAIT_SCREEN
+    ret->w = 16;
+    ret->h = 18;
+#else
     ret->w = 20;
     ret->h = 15;
+#endif
     ret->n = 30;
     ret->diff = DIFF_NORMAL;
 
@@ -109,6 +114,14 @@
 }
 
 static const struct game_params map_presets[] = {
+#ifdef PORTRAIT_SCREEN
+    {16, 18, 30, DIFF_EASY},
+    {16, 18, 30, DIFF_NORMAL},
+    {16, 18, 30, DIFF_HARD},
+    {16, 18, 30, DIFF_RECURSE},
+    {25, 30, 75, DIFF_NORMAL},
+    {25, 30, 75, DIFF_HARD},
+#else
     {20, 15, 30, DIFF_EASY},
     {20, 15, 30, DIFF_NORMAL},
     {20, 15, 30, DIFF_HARD},
@@ -115,6 +128,7 @@
     {20, 15, 30, DIFF_RECURSE},
     {30, 25, 75, DIFF_NORMAL},
     {30, 25, 75, DIFF_HARD},
+#endif
 };
 
 static int game_fetch_preset(int i, char **name, game_params **params)
@@ -2517,10 +2531,18 @@
 }
 
 const float map_colours[FOUR][3] = {
+#ifdef VIVID_COLOURS
+    // Use more vivid colours (e.g. on the Pocket PC)
+    {0.75F, 0.25F, 0.25F},
+    {0.3F,  0.7F,  0.3F},
+    {0.3F,  0.3F,  0.7F},
+    {0.85F, 0.85F, 0.1F},
+#else
     {0.7F, 0.5F, 0.4F},
     {0.8F, 0.7F, 0.4F},
     {0.5F, 0.6F, 0.4F},
     {0.55F, 0.45F, 0.35F},
+#endif
 };
 const int map_hatching[FOUR] = {
     HATCH_VERT, HATCH_SLASH, HATCH_HORIZ, HATCH_BACKSLASH
--- a/mines.c
+++ b/mines.c
@@ -28,7 +28,11 @@
 
 #define PREFERRED_TILE_SIZE 20
 #define TILE_SIZE (ds->tilesize)
+#ifdef SMALL_SCREEN
+#define BORDER 8
+#else
 #define BORDER (TILE_SIZE * 3 / 2)
+#endif
 #define HIGHLIGHT_WIDTH (TILE_SIZE / 10)
 #define OUTER_HIGHLIGHT_WIDTH (BORDER / 10)
 #define COORD(x)  ( (x) * TILE_SIZE + BORDER )
@@ -102,8 +106,10 @@
   {9, 9, 35, TRUE},
   {16, 16, 40, TRUE},
   {16, 16, 99, TRUE},
+#ifndef SMALL_SCREEN
   {30, 16, 99, TRUE},
   {30, 16, 170, TRUE},
+#endif
 };
 
 static int game_fetch_preset(int i, char **name, game_params **params)
@@ -3103,7 +3109,7 @@
     FALSE, FALSE, game_print_size, game_print,
     TRUE,			       /* wants_statusbar */
     TRUE, game_timing_state,
-    BUTTON_BEATS(LEFT_BUTTON, RIGHT_BUTTON),
+    BUTTON_BEATS(LEFT_BUTTON, RIGHT_BUTTON) | REQUIRE_RBUTTON,
 };
 
 #ifdef STANDALONE_OBFUSCATOR
--- a/mkfiles.pl
+++ b/mkfiles.pl
@@ -284,7 +284,7 @@
     # Returns true if the argument is a known makefile type. Otherwise,
     # prints a warning and returns false;
     if (grep { $type eq $_ }
-	("vc","vcproj","cygwin","borland","lcc","gtk","mpw","osx")) {
+	("vc","vcproj","cygwin","borland","lcc","gtk","mpw","osx","wce")) {
 	    return 1;
 	}
     warn "$.:unknown makefile type '$type'\n";
@@ -698,6 +698,114 @@
     }
     print "\n";
     print $makefile_extra{'vc'};
+    print "\nclean: tidy\n".
+      "\t-del *.exe\n\n".
+      "tidy:\n".
+      "\t-del *.obj\n".
+      "\t-del *.res\n".
+      "\t-del *.pch\n".
+      "\t-del *.aps\n".
+      "\t-del *.ilk\n".
+      "\t-del *.pdb\n".
+      "\t-del *.rsp\n".
+      "\t-del *.dsp\n".
+      "\t-del *.dsw\n".
+      "\t-del *.ncb\n".
+      "\t-del *.opt\n".
+      "\t-del *.plg\n".
+      "\t-del *.map\n".
+      "\t-del *.idb\n".
+      "\t-del debug.log\n";
+    select STDOUT; close OUT;
+}
+
+if (defined $makefiles{'wce'}) {
+    $mftyp = 'wce';
+    $dirpfx = &dirpfx($makefiles{'wce'}, "\\");
+
+    ##-- eMbedded Visual C PocketPC makefile
+    open OUT, ">$makefiles{'wce'}"; select OUT;
+    print
+      "# Makefile for $project_name on PocketPC using eMbedded Visual C.\n".
+      "#\n# This file was created by `mkfiles.pl' from the `Recipe' file.\n".
+      "# DO NOT EDIT THIS FILE DIRECTLY; edit Recipe or mkfiles.pl instead.\n";
+    print $help;
+    print
+      "\n".
+      "# If you rename this file to `Makefile', you should change this line,\n".
+      "# so that the .rsp files still depend on the correct makefile.\n".
+      "MAKEFILE = Makefile.wce\n".
+      "\n".
+      "# This makefile expects the environment to have been set up by one\n".
+      "# of the PocketPC batch files wcearmv4.bat and wceemulator.bat. No\n".
+      "# other build targets are currently supported, because they would\n".
+      "# need a section in this if statement.\n".
+      "!if \"\$(TARGETCPU)\" == \"emulator\"\n".
+      "PLATFORM_DEFS=/D \"_i386_\" /D \"i_386_\" /D \"_X86_\" /D \"x86\"\n".
+      "CC=cl\n".
+      "BASELIBS=commctrl.lib coredll.lib corelibc.lib aygshell.lib\n".
+      "MACHINE=IX86\n".
+      "!else\n".
+      "PLATFORM_DEFS=/D \"ARM\" /D \"_ARM_\" /D \"ARMV4\"\n".
+      "CC=clarm\n".
+      "BASELIBS=commctrl.lib coredll.lib aygshell.lib\n".
+      "MACHINE=ARM\n".
+      "!endif\n".
+      "\n".
+      "# C compilation flags\n".
+      "CFLAGS = /nologo /W3 /O1 /MC /D _WIN32_WCE=420 /D \"WIN32_PLATFORM_PSPC=400\" /D UNDER_CE=420 \\\n".
+      "         \$(PLATFORM_DEFS) \\\n".
+      "         /D \"UNICODE\" /D \"_UNICODE\" /D \"NDEBUG\" /D \"NO_HTMLHELP\"\n".
+      "\n".
+      "LFLAGS = /nologo /incremental:no \\\n".
+      "         /base:0x00010000 /stack:0x10000,0x1000 /entry:WinMainCRTStartup \\\n".
+      "         /nodefaultlib:libc.lib /nodefaultlib:libcmt.lib /nodefaultlib:msvcrt.lib /nodefaultlib:OLDNAMES.lib \\\n".
+      "         /subsystem:windowsce,4.20 /align:4096 /MACHINE:\$(MACHINE)\n".
+      "\n".
+      "RCFL = /d UNDER_CE=420 /d _WIN32_WCE=420 /d \"WIN32_PLATFORM_PSPC=400\" \\\n".
+      "       \$(PLATFORM_DEFS) \\\n".
+      "       /d \"NDEBUG\" /d \"UNICODE\" /d \"_UNICODE\"\n".
+      "\n";
+    print &splitline("all:" . join "", map { " $_.exe" } &progrealnames("G"));
+    print "\n\n";
+    foreach $p (&prognames("G")) {
+	($prog, $type) = split ",", $p;
+	$objstr = &objects($p, "X.obj", "X.res", undef);
+	print &splitline("$prog.exe: " . $objstr . " $prog.rsp"), "\n";
+	print "\tlink \$(LFLAGS) -out:$prog.exe -map:$prog.map \@$prog.rsp\n\n";
+    }
+    foreach $p (&prognames("G")) {
+	($prog, $type) = split ",", $p;
+	print $prog, ".rsp: \$(MAKEFILE)\n";
+	$objstr = &objects($p, "X.obj", "X.res", undef);
+	@objlist = split " ", $objstr;
+	@objlines = ("");
+	foreach $i (@objlist) {
+	    if (length($objlines[$#objlines] . " $i") > 50) {
+		push @objlines, "";
+	    }
+	    $objlines[$#objlines] .= " $i";
+	}
+	print "\techo \$(BASELIBS) > $prog.rsp\n";
+	for ($i=0; $i<=$#objlines; $i++) {
+	    print "\techo$objlines[$i] >> $prog.rsp\n";
+	}
+	print "\n";
+    }
+    foreach $d (&deps("X.obj", "X.res", $dirpfx, "\\")) {
+	print &splitline(sprintf("%s: %s", $d->{obj}, join " ", @{$d->{deps}})),
+	  "\n";
+	if ($d->{obj} =~ /\.res$/) {
+	    print "\trc \$(FWHACK) \$(RCFL) -r -fo".
+	      $d->{obj}." ".$d->{deps}->[0]."\n";
+	} else {
+	    $deflist = join "", map { " /D$_" } @{$d->{defs}};
+	    print "\t\$(CC) \$(COMPAT) \$(FWHACK) \$(CFLAGS) \$(XFLAGS)$deflist".
+	      " /c ".$d->{deps}->[0]." /Fo$d->{obj}\n";
+	}
+    }
+    print "\n";
+    print $makefile_extra{'wce'};
     print "\nclean: tidy\n".
       "\t-del *.exe\n\n".
       "tidy:\n".
--- a/net.c
+++ b/net.c
@@ -46,7 +46,11 @@
 #define PREFERRED_TILE_SIZE 32
 #define TILE_SIZE (ds->tilesize)
 #define TILE_BORDER 1
+#ifdef SMALL_SCREEN
+#define WINDOW_OFFSET 4
+#else
 #define WINDOW_OFFSET 16
+#endif
 
 #define ROTATE_TIME 0.13F
 #define FLASH_FRAME 0.07F
@@ -150,12 +154,16 @@
     {7, 7, FALSE, TRUE, 0.0},
     {9, 9, FALSE, TRUE, 0.0},
     {11, 11, FALSE, TRUE, 0.0},
+#ifndef SMALL_SCREEN
     {13, 11, FALSE, TRUE, 0.0},
+#endif
     {5, 5, TRUE, TRUE, 0.0},
     {7, 7, TRUE, TRUE, 0.0},
     {9, 9, TRUE, TRUE, 0.0},
     {11, 11, TRUE, TRUE, 0.0},
+#ifndef SMALL_SCREEN
     {13, 11, TRUE, TRUE, 0.0},
+#endif
 };
 
 static int game_fetch_preset(int i, char **name, game_params **params)
binary files /dev/null b/padtoolbar.bmp differ
--- a/pattern.c
+++ b/pattern.c
@@ -1276,7 +1276,7 @@
     TRUE, FALSE, game_print_size, game_print,
     FALSE,			       /* wants_statusbar */
     FALSE, game_timing_state,
-    0,				       /* flags */
+    REQUIRE_RBUTTON,		       /* flags */
 };
 
 #ifdef STANDALONE_SOLVER
--- a/puzzles.h
+++ b/puzzles.h
@@ -67,7 +67,18 @@
 #define BUTTON_BEATS(x,y) ( 1 << (((x)-LEFT_BUTTON)*3+(y)-LEFT_BUTTON) )
 /* Flag indicating that Solve operations should be animated */
 #define SOLVE_ANIMATES ( 1 << 9 )
+/* Pocket PC: Game requires right mouse button emulation */
+#define REQUIRE_RBUTTON ( 1 << 10 )
+/* Pocket PC: Game requires numeric input */
+#define REQUIRE_NUMPAD ( 1 << 11 )
 /* end of `flags' word definitions */
+
+#ifdef _WIN32_WCE
+  /* Pocket PC devices have small, portrait screen that requires more vivid colours */
+  #define SMALL_SCREEN
+  #define PORTRAIT_SCREEN
+  #define VIVID_COLOURS
+#endif
 
 #define IGNOREARG(x) ( (x) = (x) )
 
--- /dev/null
+++ b/puzzles.rc2
@@ -1,0 +1,65 @@
+/* Standard stuff that goes into the Windows resources for all puzzles. */
+
+#ifdef _WIN32_WCE
+
+#include <winuser.h>
+#include <commctrl.h>
+
+#define SHMENUBAR       RCDATA
+#define I_IMAGENONE     (-2)
+#define IDC_STATIC      (-1)
+
+#include "resource.h"
+
+IDR_MENUBAR1 MENU DISCARDABLE 
+BEGIN
+    POPUP "Game"
+    BEGIN
+        MENUITEM "Dummy", 0
+    END
+    POPUP "Type"
+    BEGIN
+        MENUITEM "Dummy", 0
+    END
+END
+
+IDR_MENUBAR1 SHMENUBAR DISCARDABLE 
+BEGIN
+    IDR_MENUBAR1, 2,
+    I_IMAGENONE, ID_GAME, TBSTATE_ENABLED, 
+    TBSTYLE_DROPDOWN | TBSTYLE_AUTOSIZE, IDS_CAP_GAME, 0, 0,
+    I_IMAGENONE, ID_TYPE, TBSTATE_ENABLED, 
+    TBSTYLE_DROPDOWN | TBSTYLE_AUTOSIZE, IDS_CAP_TYPE, 0, 1,
+END
+
+STRINGTABLE DISCARDABLE 
+BEGIN
+    IDS_CAP_GAME            "Game"
+    IDS_CAP_TYPE            "Type"
+END
+
+IDD_ABOUT DIALOG DISCARDABLE  0, 0, 0, 0
+STYLE WS_POPUP
+FONT 8, "Tahoma"
+BEGIN
+    LTEXT "", IDC_ABOUT_CAPTION,        4,  4, 150,  8
+    LTEXT "", IDC_ABOUT_LINE,           4, 16, 150,  1, WS_BORDER
+    LTEXT "", IDC_ABOUT_GAME,           4, 22, 150,  8
+    LTEXT "from Simon Tatham's Portable Puzzle Collection",
+	      IDC_STATIC,               4, 36, 150,  8, SS_LEFTNOWORDWRAP
+    LTEXT "Pocket PC port by Darek Olszewski",
+	      IDC_STATIC,               4, 46, 150,  8
+    LTEXT "", IDC_ABOUT_VERSION,        4, 60, 150,  8
+END
+
+IDD_CONFIG DIALOG DISCARDABLE  0, 0, 0, 0
+STYLE WS_POPUP
+FONT 8, "Tahoma"
+BEGIN
+    LTEXT "", IDC_CONFIG_CAPTION,       4,  4, 150,  8
+    LTEXT "", IDC_CONFIG_LINE,          4, 16, 150,  1, WS_BORDER
+END
+
+IDR_PADTOOLBAR BITMAP DISCARDABLE "padtoolbar.bmp"
+
+#endif /* _WIN32_WCE */
--- a/rect.c
+++ b/rect.c
@@ -60,7 +60,11 @@
 
 #define PREFERRED_TILE_SIZE 24
 #define TILE_SIZE (ds->tilesize)
+#ifdef SMALL_SCREEN
+#define BORDER (2)
+#else
 #define BORDER (TILE_SIZE * 3 / 4)
+#endif
 
 #define CORNER_TOLERANCE 0.15F
 #define CENTRE_TOLERANCE 0.15F
@@ -102,8 +106,10 @@
       case 2: w = 11, h = 11; break;
       case 3: w = 13, h = 13; break;
       case 4: w = 15, h = 15; break;
+#ifndef SMALL_SCREEN
       case 5: w = 17, h = 17; break;
       case 6: w = 19, h = 19; break;
+#endif
       default: return FALSE;
     }
 
--- /dev/null
+++ b/resource.h
@@ -1,0 +1,20 @@
+
+#define IDR_MENUBAR1                    101
+
+#define ID_GAME                         40005
+#define ID_TYPE                         40006
+
+#define IDS_CAP_GAME                    40105
+#define IDS_CAP_TYPE                    40106
+
+#define IDD_ABOUT			2000
+#define IDC_ABOUT_CAPTION		2001
+#define IDC_ABOUT_LINE			2002
+#define IDC_ABOUT_GAME			2003
+#define IDC_ABOUT_VERSION		2004
+
+#define IDD_CONFIG			2100
+#define IDC_CONFIG_CAPTION		2101
+#define IDC_CONFIG_LINE			2102
+
+#define IDR_PADTOOLBAR                  4000
--- a/solo.c
+++ b/solo.c
@@ -3085,7 +3085,7 @@
     TRUE, FALSE, game_print_size, game_print,
     FALSE,			       /* wants_statusbar */
     FALSE, game_timing_state,
-    0,				       /* flags */
+    REQUIRE_RBUTTON | REQUIRE_NUMPAD,  /* flags */
 };
 
 #ifdef STANDALONE_SOLVER
--- a/tents.c
+++ b/tents.c
@@ -2086,7 +2086,7 @@
     TRUE, FALSE, game_print_size, game_print,
     FALSE,			       /* wants_statusbar */
     FALSE, game_timing_state,
-    0,				       /* flags */
+    REQUIRE_RBUTTON,		       /* flags */
 };
 
 #ifdef STANDALONE_SOLVER
--- a/unequal.c
+++ b/unequal.c
@@ -26,6 +26,11 @@
 #include "puzzles.h"
 #include "latin.h" /* contains typedef for digit */
 
+static void assert_f(p)
+{
+    assert(p);
+}
+
 /* ----------------------------------------------------------
  * Constant and structure definitions
  */
@@ -971,7 +976,7 @@
         gg_solved++;
         if (solver_state(copy, difficulty) != 1) {
             /* put clue back, we can't solve without it. */
-            assert(gg_place_clue(new, scratch[i], latin, 0) == 1);
+            assert_f(gg_place_clue(new, scratch[i], latin, 0) == 1);
         } else {
 #ifdef STANDALONE_SOLVER
             if (solver_show_working)
@@ -1355,7 +1360,7 @@
             p++;
         }
         if (*p) goto badmove;
-        assert(check_complete(ret->nums, ret, 1) > 0);
+	assert_f(check_complete(ret->nums, ret, 1) > 0);
         return ret;
     } else if (move[0] == 'H') {
         return solver_hint(state, NULL, DIFF_EASY, DIFF_EASY);
@@ -1748,7 +1753,7 @@
     TRUE, FALSE, game_print_size, game_print,
     FALSE,			       /* wants_statusbar */
     FALSE, game_timing_state,
-    0,				       /* flags */
+    REQUIRE_RBUTTON | REQUIRE_NUMPAD,  /* flags */
 };
 
 /* ----------------------------------------------------------------------
--- a/windows.c
+++ b/windows.c
@@ -8,6 +8,11 @@
 #include <htmlhelp.h>
 #endif /* NO_HTMLHELP */
 
+#ifdef _WIN32_WCE
+#include <commdlg.h>
+#include <aygshell.h>
+#endif
+
 #include <stdio.h>
 #include <assert.h>
 #include <ctype.h>
@@ -18,6 +23,10 @@
 
 #include "puzzles.h"
 
+#ifdef _WIN32_WCE
+#include "resource.h"
+#endif
+
 #define IDM_NEW       0x0010
 #define IDM_RESTART   0x0020
 #define IDM_UNDO      0x0030
@@ -36,6 +45,8 @@
 #define IDM_PRINT     0x0100
 #define IDM_PRESETS   0x0110
 
+#define IDM_KEYEMUL   0x0400
+
 #define HELP_FILE_NAME  "puzzles.hlp"
 #define HELP_CNT_NAME   "puzzles.cnt"
 #ifndef NO_HTMLHELP
@@ -52,6 +63,58 @@
 const char *help_topic;
 int help_has_contents;
 
+#ifndef FILENAME_MAX
+#define	FILENAME_MAX	(260)
+#endif
+
+#ifndef HGDI_ERROR
+#define HGDI_ERROR ((HANDLE)GDI_ERROR)
+#endif
+
+#ifdef _WIN32_WCE
+
+/*
+ * Wrapper implementations of functions not supplied by the
+ * PocketPC API.
+ */
+
+#define SHGetSubMenu(hWndMB,ID_MENU) (HMENU)SendMessage((hWndMB), SHCMBM_GETSUBMENU, (WPARAM)0, (LPARAM)ID_MENU)
+
+#undef MessageBox
+
+int MessageBox(HWND hWnd, LPCSTR lpText, LPCSTR lpCaption, UINT uType)
+{
+    TCHAR wText[2048];
+    TCHAR wCaption[2048];
+
+    MultiByteToWideChar (CP_ACP, 0, lpText,    -1, wText,    2048);
+    MultiByteToWideChar (CP_ACP, 0, lpCaption, -1, wCaption, 2048);
+
+    return MessageBoxW (hWnd, wText, wCaption, uType);
+}
+
+BOOL SetDlgItemTextA(HWND hDlg, int nIDDlgItem, LPCSTR lpString)
+{
+    TCHAR wText[256];
+
+    MultiByteToWideChar (CP_ACP, 0, lpString, -1, wText, 256);
+    return SetDlgItemTextW(hDlg, nIDDlgItem, wText);
+}
+
+LPCSTR getenv(LPCSTR buf)
+{
+    return NULL;
+}
+
+BOOL GetKeyboardState(PBYTE pb)
+{
+  return FALSE;
+}
+
+static TCHAR wGameName[256];
+
+#endif
+
 #ifdef DEBUGGING
 static FILE *debug_fp = NULL;
 static HANDLE debug_hdl = INVALID_HANDLE_VALUE;
@@ -90,8 +153,12 @@
 }
 #endif
 
+#ifndef _WIN32_WCE
 #define WINFLAGS (WS_OVERLAPPEDWINDOW &~ \
 		      (WS_THICKFRAME | WS_MAXIMIZEBOX | WS_OVERLAPPED))
+#else
+#define WINFLAGS (WS_CAPTION | WS_SYSMENU)
+#endif
 
 static void new_game_size(frontend *fe);
 
@@ -116,8 +183,12 @@
 struct frontend {
     midend *me;
     HWND hwnd, statusbar, cfgbox;
+#ifdef _WIN32_WCE
+    HWND numpad;  /* window handle for the numeric pad */
+#endif
     HINSTANCE inst;
     HBITMAP bitmap, prevbm;
+    RECT bitmapPosition;  /* game bitmap position within game window */
     HDC hdc;
     COLORREF *colours;
     HBRUSH *brushes;
@@ -185,17 +256,29 @@
 
 void get_random_seed(void **randseed, int *randseedsize)
 {
-    time_t *tp = snew(time_t);
-    time(tp);
-    *randseed = (void *)tp;
-    *randseedsize = sizeof(time_t);
+    SYSTEMTIME *st = snew(SYSTEMTIME);
+
+    GetLocalTime(st);
+
+    *randseed = (void *)st;
+    *randseedsize = sizeof(SYSTEMTIME);
 }
 
 static void win_status_bar(void *handle, char *text)
 {
+#ifdef _WIN32_WCE
+    TCHAR wText[255];
+#endif
     frontend *fe = (frontend *)handle;
 
+#ifdef _WIN32_WCE
+    MultiByteToWideChar (CP_ACP, 0, text, -1, wText, 255);
+    SendMessage(fe->statusbar, SB_SETTEXT,
+                (WPARAM) 255 | SBT_NOBORDERS,
+                (LPARAM) wText);
+#else
     SetWindowText(fe->statusbar, text);
+#endif
 }
 
 static blitter *win_blitter_new(void *handle, int w, int h)
@@ -334,13 +417,20 @@
 	float r, g, b;
 	print_get_colour(fe->dr, colour, &hatch, &r, &g, &b);
 
-	if (fe->printcolour)
+	if (fe->printcolour) {
 	    br = CreateSolidBrush(RGB(r * 255, g * 255, b * 255));
-	else if (hatch == HATCH_SOLID)
+	} else if (hatch == HATCH_SOLID) {
 	    br = CreateSolidBrush(RGB(0,0,0));
-	else if (hatch == HATCH_CLEAR)
+	} else if (hatch == HATCH_CLEAR) {
 	    br = CreateSolidBrush(RGB(255,255,255));
-	else
+	} else {
+#ifdef _WIN32_WCE
+	    /*
+	     * This is only ever required during printing, and the
+	     * PocketPC port doesn't support printing.
+	     */
+	    fatal("CreateHatchBrush not supported");
+#else
 	    br = CreateHatchBrush(hatch == HATCH_BACKSLASH ? HS_FDIAGONAL :
 				  hatch == HATCH_SLASH ? HS_BDIAGONAL :
 				  hatch == HATCH_HORIZ ? HS_HORIZONTAL :
@@ -348,6 +438,8 @@
 				  hatch == HATCH_PLUS ? HS_CROSS :
 				  /* hatch == HATCH_X ? */ HS_DIAGCROSS,
 				  RGB(0,0,0));
+#endif
+	}
     } else {
 	br = fe->brushes[colour];
     }
@@ -433,6 +525,7 @@
     frontend *fe = (frontend *)handle;
     POINT xy;
     int i;
+    LOGFONT lf;
 
     if (fe->drawstatus == NOTHING)
 	return;
@@ -460,15 +553,21 @@
         fe->fonts[i].type = fonttype;
         fe->fonts[i].size = fontsize;
 
-        fe->fonts[i].font = CreateFont(-fontsize, 0, 0, 0,
-				       fe->drawstatus == PRINTING ? 0 : FW_BOLD,
-				       FALSE, FALSE, FALSE, DEFAULT_CHARSET,
-				       OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS,
-				       DEFAULT_QUALITY,
-				       (fonttype == FONT_FIXED ?
-					FIXED_PITCH | FF_DONTCARE :
-					VARIABLE_PITCH | FF_SWISS),
-				       NULL);
+        memset (&lf, 0, sizeof(LOGFONT));
+        lf.lfHeight = -fontsize;
+        lf.lfWeight = (fe->drawstatus == PRINTING ? 0 : FW_BOLD);
+        lf.lfCharSet = DEFAULT_CHARSET;
+        lf.lfOutPrecision = OUT_DEFAULT_PRECIS;
+        lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
+        lf.lfQuality = DEFAULT_QUALITY;
+        lf.lfPitchAndFamily = (fonttype == FONT_FIXED ?
+                               FIXED_PITCH | FF_DONTCARE :
+                               VARIABLE_PITCH | FF_SWISS);
+#ifdef _WIN32_WCE
+        wcscpy(lf.lfFaceName, TEXT("Tahoma"));
+#endif
+
+        fe->fonts[i].font = CreateFontIndirect(&lf);
     }
 
     /*
@@ -478,6 +577,10 @@
 	HFONT oldfont;
 	TEXTMETRIC tm;
 	SIZE size;
+#ifdef _WIN32_WCE
+	TCHAR wText[256];
+	MultiByteToWideChar (CP_ACP, 0, text, -1, wText, 256);
+#endif
 
 	oldfont = SelectObject(fe->hdc, fe->fonts[i].font);
 	if (GetTextMetrics(fe->hdc, &tm)) {
@@ -486,7 +589,11 @@
 	    else
 		xy.y -= tm.tmAscent;
 	}
+#ifndef _WIN32_WCE
 	if (GetTextExtentPoint32(fe->hdc, text, strlen(text), &size)) {
+#else
+	if (GetTextExtentPoint32(fe->hdc, wText, wcslen(wText), &size)) {
+#endif
 	    if (align & ALIGN_HCENTRE)
 		xy.x -= size.cx / 2;
 	    else if (align & ALIGN_HRIGHT)
@@ -494,7 +601,11 @@
 	}
 	SetBkMode(fe->hdc, TRANSPARENT);
 	win_text_colour(fe, colour);
+#ifndef _WIN32_WCE
 	TextOut(fe->hdc, xy.x, xy.y, text, strlen(text));
+#else
+	ExtTextOut(fe->hdc, xy.x, xy.y, 0, NULL, wText, wcslen(wText), NULL);
+#endif
 	SelectObject(fe->hdc, oldfont);
     }
 }
@@ -529,18 +640,17 @@
 static void win_draw_line(void *handle, int x1, int y1, int x2, int y2, int colour)
 {
     frontend *fe = (frontend *)handle;
-    POINT p, q;
+    POINT pp[2];
 
     if (fe->drawstatus == NOTHING)
 	return;
 
     win_set_pen(fe, colour, FALSE);
-    p = win_transform_point(fe, x1, y1);
-    q = win_transform_point(fe, x2, y2);
-    MoveToEx(fe->hdc, p.x, p.y, NULL);
-    LineTo(fe->hdc, q.x, q.y);
+    pp[0] = win_transform_point(fe, x1, y1);
+    pp[1] = win_transform_point(fe, x2, y2);
+    Polyline(fe->hdc, pp, 2);
     if (fe->drawstatus == DRAWING)
-	SetPixel(fe->hdc, q.x, q.y, fe->colours[colour]);
+	SetPixel(fe->hdc, pp[1].x, pp[1].y, fe->colours[colour]);
     win_reset_pen(fe);
 }
 
@@ -548,7 +658,7 @@
 			    int fillcolour, int outlinecolour)
 {
     frontend *fe = (frontend *)handle;
-    POINT p, q, r;
+    POINT p, q;
 
     assert(outlinecolour >= 0);
 
@@ -555,22 +665,17 @@
     if (fe->drawstatus == NOTHING)
 	return;
 
-    if (fillcolour >= 0) {
+    if (fillcolour >= 0)
 	win_set_brush(fe, fillcolour);
-	win_set_pen(fe, outlinecolour, FALSE);
-	p = win_transform_point(fe, cx - radius, cy - radius);
-	q = win_transform_point(fe, cx + radius, cy + radius);
-	Ellipse(fe->hdc, p.x, p.y, q.x+1, q.y+1);
-	win_reset_brush(fe);
-	win_reset_pen(fe);
-    } else {
-	win_set_pen(fe, outlinecolour, FALSE);
-	p = win_transform_point(fe, cx - radius, cy - radius);
-	q = win_transform_point(fe, cx + radius, cy + radius);
-	r = win_transform_point(fe, cx - radius, cy);
-	Arc(fe->hdc, p.x, p.y, q.x+1, q.y+1, r.x, r.y, r.x, r.y);
-	win_reset_pen(fe);
-    }
+    else
+	fe->oldbr = SelectObject(fe->hdc, GetStockObject(NULL_BRUSH));
+
+    win_set_pen(fe, outlinecolour, FALSE);
+    p = win_transform_point(fe, cx - radius, cy - radius);
+    q = win_transform_point(fe, cx + radius, cy + radius);
+    Ellipse(fe->hdc, p.x, p.y, q.x+1, q.y+1);
+    win_reset_brush(fe);
+    win_reset_pen(fe);
 }
 
 static void win_draw_polygon(void *handle, int *coords, int npoints,
@@ -619,7 +724,9 @@
     fe->prevbm = SelectObject(fe->hdc, fe->bitmap);
     ReleaseDC(fe->hwnd, hdc_win);
     fe->clip = NULL;
+#ifndef _WIN32_WCE
     SetMapMode(fe->hdc, MM_TEXT);
+#endif
     fe->drawstatus = DRAWING;
 }
 
@@ -636,6 +743,7 @@
     r.right = x + w;
     r.bottom = y + h;
 
+    OffsetRect(&r, fe->bitmapPosition.left, fe->bitmapPosition.top);
     InvalidateRect(fe->hwnd, &r, FALSE);
 }
 
@@ -838,6 +946,7 @@
 
 void print(frontend *fe)
 {
+#ifndef _WIN32_WCE
     PRINTDLG pd;
     char doctitle[256];
     document *doc;
@@ -928,6 +1037,7 @@
 
     DeleteDC(pd.hDC);
     document_free(doc);
+#endif
 }
 
 void deactivate_timer(frontend *fe)
@@ -943,7 +1053,7 @@
     if (!fe)
 	return;			       /* for non-interactive midend */
     if (!fe->timer) {
-	fe->timer = SetTimer(fe->hwnd, fe->timer, 20, NULL);
+	fe->timer = SetTimer(fe->hwnd, 1, 20, NULL);
 	fe->timer_last_tickcount = GetTickCount();
     }
 }
@@ -1000,6 +1110,7 @@
  */
 static void init_help(void)
 {
+#ifndef _WIN32_WCE
     char b[2048], *p, *q, *r;
     FILE *fp;
 
@@ -1066,8 +1177,11 @@
     }
 
     help_type = NONE;	       /* didn't find any */
+#endif
 }
 
+#ifndef _WIN32_WCE
+
 /*
  * Start Help.
  */
@@ -1137,6 +1251,8 @@
     }
 }
 
+#endif
+
 /*
  * Terminate Help on process exit.
  */
@@ -1177,14 +1293,18 @@
 	r.right = x;
 	r.bottom = y + sy;
 	AdjustWindowRectEx(&r, WINFLAGS, TRUE, 0);
+#ifndef _WIN32_WCE
 	SetWindowPos(fe->hwnd, NULL, 0, 0, r.right - r.left, r.bottom - r.top,
 		     SWP_NOMOVE | SWP_NOZORDER);
+#endif
     }
 
     if (fe->statusbar) {
 	GetClientRect(fe->hwnd, &r);
+#ifndef _WIN32_WCE
 	SetWindowPos(fe->statusbar, NULL, 0, r.bottom-r.top-sy, r.right-r.left,
 		     sy, SWP_NOZORDER);
+#endif
     }
 
     *px = x;
@@ -1215,6 +1335,23 @@
     }
 }
 
+#ifdef _WIN32_WCE
+/* Toolbar buttons on the numeric pad */
+static TBBUTTON tbNumpadButtons[] =
+{
+    {0, IDM_KEYEMUL + '1', TBSTATE_ENABLED, TBSTYLE_BUTTON,  0, -1},
+    {1, IDM_KEYEMUL + '2', TBSTATE_ENABLED, TBSTYLE_BUTTON,  0, -1},
+    {2, IDM_KEYEMUL + '3', TBSTATE_ENABLED, TBSTYLE_BUTTON,  0, -1},
+    {3, IDM_KEYEMUL + '4', TBSTATE_ENABLED, TBSTYLE_BUTTON,  0, -1},
+    {4, IDM_KEYEMUL + '5', TBSTATE_ENABLED, TBSTYLE_BUTTON,  0, -1},
+    {5, IDM_KEYEMUL + '6', TBSTATE_ENABLED, TBSTYLE_BUTTON,  0, -1},
+    {6, IDM_KEYEMUL + '7', TBSTATE_ENABLED, TBSTYLE_BUTTON,  0, -1},
+    {7, IDM_KEYEMUL + '8', TBSTATE_ENABLED, TBSTYLE_BUTTON,  0, -1},
+    {8, IDM_KEYEMUL + '9', TBSTATE_ENABLED, TBSTYLE_BUTTON,  0, -1},
+    {9, IDM_KEYEMUL + ' ', TBSTATE_ENABLED, TBSTYLE_BUTTON,  0, -1}
+};
+#endif
+
 static frontend *new_window(HINSTANCE inst, char *game_id, char **error)
 {
     frontend *fe;
@@ -1271,7 +1408,7 @@
     }
 
     if (midend_wants_statusbar(fe->me)) {
-	fe->statusbar = CreateWindowEx(0, STATUSCLASSNAME, "ooh",
+	fe->statusbar = CreateWindowEx(0, STATUSCLASSNAME, TEXT("ooh"),
 				       WS_CHILD | WS_VISIBLE,
 				       0, 0, 0, 0, /* status bar does these */
 				       NULL, NULL, inst, NULL);
@@ -1286,6 +1423,51 @@
     r.bottom = y;
     AdjustWindowRectEx(&r, WINFLAGS, TRUE, 0);
 
+#ifdef _WIN32_WCE
+    fe->hwnd = CreateWindowEx(0, wGameName, wGameName,
+			      WS_VISIBLE,
+			      CW_USEDEFAULT, CW_USEDEFAULT,
+			      CW_USEDEFAULT, CW_USEDEFAULT,
+			      NULL, NULL, inst, NULL);
+
+    {
+	SHMENUBARINFO mbi;
+	RECT rc, rcBar, rcTB, rcClient;
+
+	memset (&mbi, 0, sizeof(SHMENUBARINFO));
+	mbi.cbSize     = sizeof(SHMENUBARINFO);
+	mbi.hwndParent = fe->hwnd;
+	mbi.nToolBarId = IDR_MENUBAR1;
+	mbi.hInstRes   = inst;
+
+	SHCreateMenuBar(&mbi);
+
+	GetWindowRect(fe->hwnd, &rc);
+	GetWindowRect(mbi.hwndMB, &rcBar);
+	rc.bottom -= rcBar.bottom - rcBar.top;
+	MoveWindow(fe->hwnd, rc.left, rc.top, rc.right - rc.left, rc.bottom - rc.top, FALSE);
+
+	if (thegame.flags & REQUIRE_NUMPAD)
+	{
+	    fe->numpad = CreateToolbarEx (fe->hwnd,
+				          WS_VISIBLE | WS_CHILD | CCS_NOPARENTALIGN | TBSTYLE_FLAT,
+				          0, 10, inst, IDR_PADTOOLBAR,
+				          tbNumpadButtons, sizeof (tbNumpadButtons) / sizeof (TBBUTTON),
+				          0, 0, 14, 15, sizeof (TBBUTTON));
+	    GetWindowRect(fe->numpad, &rcTB);
+	    GetClientRect(fe->hwnd, &rcClient);
+	    MoveWindow(fe->numpad, 
+		       0, 
+		       rcClient.bottom - (rcTB.bottom - rcTB.top) - 1,
+		       rcClient.right,
+		       rcTB.bottom - rcTB.top,
+		       FALSE);
+	    SendMessage(fe->numpad, TB_SETINDENT, (rcClient.right - (10 * 21)) / 2, 0);
+	}
+	else
+	    fe->numpad = NULL;
+    }
+#else
     fe->hwnd = CreateWindowEx(0, thegame.name, thegame.name,
 			      WS_OVERLAPPEDWINDOW &~
 			      (WS_THICKFRAME | WS_MAXIMIZEBOX),
@@ -1292,47 +1474,72 @@
 			      CW_USEDEFAULT, CW_USEDEFAULT,
 			      r.right - r.left, r.bottom - r.top,
 			      NULL, NULL, inst, NULL);
+#endif
 
     if (midend_wants_statusbar(fe->me)) {
 	RECT sr;
 	DestroyWindow(fe->statusbar);
-	fe->statusbar = CreateWindowEx(0, STATUSCLASSNAME, "ooh",
+	fe->statusbar = CreateWindowEx(0, STATUSCLASSNAME, TEXT("ooh"),
 				       WS_CHILD | WS_VISIBLE,
 				       0, 0, 0, 0, /* status bar does these */
 				       fe->hwnd, NULL, inst, NULL);
+#ifdef _WIN32_WCE
+	/* Flat status bar looks better on the Pocket PC */
+	SendMessage(fe->statusbar, SB_SIMPLE, (WPARAM) TRUE, 0);
+	SendMessage(fe->statusbar, SB_SETTEXT,
+				(WPARAM) 255 | SBT_NOBORDERS,
+				(LPARAM) L"");
+#endif
+
 	/*
 	 * Now resize the window to take account of the status bar.
 	 */
 	GetWindowRect(fe->statusbar, &sr);
 	GetWindowRect(fe->hwnd, &r);
+#ifndef _WIN32_WCE
 	SetWindowPos(fe->hwnd, NULL, 0, 0, r.right - r.left,
 		     r.bottom - r.top + sr.bottom - sr.top,
 		     SWP_NOMOVE | SWP_NOZORDER);
+#endif
     } else {
 	fe->statusbar = NULL;
     }
 
     {
+#ifndef _WIN32_WCE
 	HMENU bar = CreateMenu();
 	HMENU menu = CreateMenu();
 
 	AppendMenu(bar, MF_ENABLED|MF_POPUP, (UINT)menu, "Game");
-	AppendMenu(menu, MF_ENABLED, IDM_NEW, "New");
-	AppendMenu(menu, MF_ENABLED, IDM_RESTART, "Restart");
-	AppendMenu(menu, MF_ENABLED, IDM_DESC, "Specific...");
-	AppendMenu(menu, MF_ENABLED, IDM_SEED, "Random Seed...");
+#else
+	HMENU menu = SHGetSubMenu(SHFindMenuBar(fe->hwnd), ID_GAME);
+	DeleteMenu(menu, 0, MF_BYPOSITION);
+#endif
+	AppendMenu(menu, MF_ENABLED, IDM_NEW, TEXT("New"));
+	AppendMenu(menu, MF_ENABLED, IDM_RESTART, TEXT("Restart"));
+#ifndef _WIN32_WCE
+	AppendMenu(menu, MF_ENABLED, IDM_DESC, TEXT("Specific..."));
+	AppendMenu(menu, MF_ENABLED, IDM_SEED, TEXT("Random Seed..."));
+#endif
 
 	if ((fe->npresets = midend_num_presets(fe->me)) > 0 ||
 	    thegame.can_configure) {
-	    HMENU sub = CreateMenu();
 	    int i;
+#ifndef _WIN32_WCE
+	    HMENU sub = CreateMenu();
 
 	    AppendMenu(bar, MF_ENABLED|MF_POPUP, (UINT)sub, "Type");
-
+#else
+	    HMENU sub = SHGetSubMenu(SHFindMenuBar(fe->hwnd), ID_TYPE);
+	    DeleteMenu(sub, 0, MF_BYPOSITION);
+#endif
 	    fe->presets = snewn(fe->npresets, game_params *);
 
 	    for (i = 0; i < fe->npresets; i++) {
 		char *name;
+#ifdef _WIN32_WCE
+		TCHAR wName[255];
+#endif
 
 		midend_fetch_preset(fe->me, i, &name, &fe->presets[i]);
 
@@ -1341,40 +1548,51 @@
 		 * with ampersands here.
 		 */
 
+#ifndef _WIN32_WCE
 		AppendMenu(sub, MF_ENABLED, IDM_PRESETS + 0x10 * i, name);
+#else
+		MultiByteToWideChar (CP_ACP, 0, name, -1, wName, 255);
+		AppendMenu(sub, MF_ENABLED, IDM_PRESETS + 0x10 * i, wName);
+#endif
 	    }
-
 	    if (thegame.can_configure) {
-		AppendMenu(sub, MF_ENABLED, IDM_CONFIG, "Custom...");
+		AppendMenu(sub, MF_ENABLED, IDM_CONFIG, TEXT("Custom..."));
 	    }
 	}
 
 	AppendMenu(menu, MF_SEPARATOR, 0, 0);
-	AppendMenu(menu, MF_ENABLED, IDM_LOAD, "Load...");
-	AppendMenu(menu, MF_ENABLED, IDM_SAVE, "Save...");
+#ifndef _WIN32_WCE
+	AppendMenu(menu, MF_ENABLED, IDM_LOAD, TEXT("Load..."));
+	AppendMenu(menu, MF_ENABLED, IDM_SAVE, TEXT("Save..."));
 	AppendMenu(menu, MF_SEPARATOR, 0, 0);
 	if (thegame.can_print) {
-	    AppendMenu(menu, MF_ENABLED, IDM_PRINT, "Print...");
+	    AppendMenu(menu, MF_ENABLED, IDM_PRINT, TEXT("Print..."));
 	    AppendMenu(menu, MF_SEPARATOR, 0, 0);
 	}
-	AppendMenu(menu, MF_ENABLED, IDM_UNDO, "Undo");
-	AppendMenu(menu, MF_ENABLED, IDM_REDO, "Redo");
+#endif
+	AppendMenu(menu, MF_ENABLED, IDM_UNDO, TEXT("Undo"));
+	AppendMenu(menu, MF_ENABLED, IDM_REDO, TEXT("Redo"));
+#ifndef _WIN32_WCE
 	if (thegame.can_format_as_text) {
 	    AppendMenu(menu, MF_SEPARATOR, 0, 0);
-	    AppendMenu(menu, MF_ENABLED, IDM_COPY, "Copy");
+	    AppendMenu(menu, MF_ENABLED, IDM_COPY, TEXT("Copy"));
 	}
+#endif
 	if (thegame.can_solve) {
 	    AppendMenu(menu, MF_SEPARATOR, 0, 0);
-	    AppendMenu(menu, MF_ENABLED, IDM_SOLVE, "Solve");
+	    AppendMenu(menu, MF_ENABLED, IDM_SOLVE, TEXT("Solve"));
 	}
 	AppendMenu(menu, MF_SEPARATOR, 0, 0);
-	AppendMenu(menu, MF_ENABLED, IDM_QUIT, "Exit");
+#ifndef _WIN32_WCE
+	AppendMenu(menu, MF_ENABLED, IDM_QUIT, TEXT("Exit"));
 	menu = CreateMenu();
-	AppendMenu(bar, MF_ENABLED|MF_POPUP, (UINT)menu, "Help");
-	AppendMenu(menu, MF_ENABLED, IDM_ABOUT, "About");
+	AppendMenu(bar, MF_ENABLED|MF_POPUP, (UINT)menu, TEXT("Help"));
+#endif
+	AppendMenu(menu, MF_ENABLED, IDM_ABOUT, TEXT("About"));
+#ifndef _WIN32_WCE
         if (help_type != NONE) {
 	    AppendMenu(menu, MF_SEPARATOR, 0, 0);
-            AppendMenu(menu, MF_ENABLED, IDM_HELPC, "Contents");
+            AppendMenu(menu, MF_ENABLED, IDM_HELPC, TEXT("Contents"));
             if (help_topic) {
                 char *item;
                 assert(thegame.name);
@@ -1385,6 +1603,7 @@
             }
         }
 	SetMenu(fe->hwnd, bar);
+#endif
     }
 
     fe->bitmap = NULL;
@@ -1393,7 +1612,7 @@
 
     SetWindowLong(fe->hwnd, GWL_USERDATA, (LONG)fe);
 
-    ShowWindow(fe->hwnd, SW_NORMAL);
+    ShowWindow(fe->hwnd, SW_SHOWNORMAL);
     SetForegroundWindow(fe->hwnd);
 
     midend_redraw(fe->me);
@@ -1401,6 +1620,36 @@
     return fe;
 }
 
+#ifdef _WIN32_WCE
+static HFONT dialog_title_font()
+{
+    static HFONT hf = NULL;
+    LOGFONT lf;
+
+    if (hf)
+	return hf;
+
+    memset (&lf, 0, sizeof(LOGFONT));
+    lf.lfHeight = -11; /* - ((8 * GetDeviceCaps(hdc, LOGPIXELSY)) / 72) */
+    lf.lfWeight = FW_BOLD;
+    wcscpy(lf.lfFaceName, TEXT("Tahoma"));
+
+    return hf = CreateFontIndirect(&lf);
+}
+
+static void make_dialog_full_screen(HWND hwnd)
+{
+    SHINITDLGINFO shidi;
+
+    /* Make dialog full screen */
+    shidi.dwMask = SHIDIM_FLAGS;
+    shidi.dwFlags = SHIDIF_DONEBUTTON | SHIDIF_SIZEDLGFULLSCREEN |
+                    SHIDIF_EMPTYMENU;
+    shidi.hDlg = hwnd;
+    SHInitDialog(&shidi);
+}
+#endif
+
 static int CALLBACK AboutDlgProc(HWND hwnd, UINT msg,
 				 WPARAM wParam, LPARAM lParam)
 {
@@ -1408,17 +1657,39 @@
 
     switch (msg) {
       case WM_INITDIALOG:
-	return 0;
+#ifdef _WIN32_WCE
+	{
+	    char title[256];
 
+	    make_dialog_full_screen(hwnd);
+
+	    sprintf(title, "About %.250s", thegame.name);
+	    SetDlgItemTextA(hwnd, IDC_ABOUT_CAPTION, title);
+
+	    SendDlgItemMessage(hwnd, IDC_ABOUT_CAPTION, WM_SETFONT,
+			       (WPARAM) dialog_title_font(), 0);
+
+	    SetDlgItemTextA(hwnd, IDC_ABOUT_GAME, thegame.name);
+	    SetDlgItemTextA(hwnd, IDC_ABOUT_VERSION, ver);
+	}
+#endif
+	return TRUE;
+
       case WM_COMMAND:
-	if ((HIWORD(wParam) == BN_CLICKED ||
-	     HIWORD(wParam) == BN_DOUBLECLICKED) &&
-	    LOWORD(wParam) == IDOK)
+	if (LOWORD(wParam) == IDOK)
+#ifdef _WIN32_WCE
+	    EndDialog(hwnd, 1);
+#else
 	    fe->dlg_done = 1;
+#endif
 	return 0;
 
       case WM_CLOSE:
+#ifdef _WIN32_WCE
+	EndDialog(hwnd, 1);
+#else
 	fe->dlg_done = 1;
+#endif
 	return 0;
     }
 
@@ -1525,6 +1796,117 @@
     }
 }
 
+#ifdef _WIN32_WCE
+/* Separate version of mkctrl function for the Pocket PC. */
+/* Control coordinates should be specified in dialog units. */
+HWND mkctrl(frontend *fe, int x1, int x2, int y1, int y2,
+	    LPCTSTR wclass, int wstyle,
+	    int exstyle, const char *wtext, int wid)
+{
+    RECT rc;
+    TCHAR wwtext[256];
+
+    /* Convert dialog units into pixels */
+    rc.left = x1;  rc.right  = x2;
+    rc.top  = y1;  rc.bottom = y2;
+    MapDialogRect(fe->cfgbox, &rc);
+
+    MultiByteToWideChar (CP_ACP, 0, wtext, -1, wwtext, 256);
+
+    return CreateWindowEx(exstyle, wclass, wwtext,
+			  wstyle | WS_CHILD | WS_VISIBLE,
+			  rc.left, rc.top,
+			  rc.right - rc.left, rc.bottom - rc.top,
+			  fe->cfgbox, (HMENU) wid, fe->inst, NULL);
+}
+
+static void create_config_controls(frontend * fe)
+{
+    int id, nctrls;
+    int col1l, col1r, col2l, col2r, y;
+    config_item *i;
+    struct cfg_aux *j;
+    HWND ctl;
+
+    /* Control placement done in dialog units */
+    col1l = 4;   col1r = 96;   /* Label column */
+    col2l = 100; col2r = 154;  /* Input column (edit boxes and combo boxes) */
+
+    /*
+     * Count the controls so we can allocate cfgaux.
+     */
+    for (nctrls = 0, i = fe->cfg; i->type != C_END; i++)
+	nctrls++;
+    fe->cfgaux = snewn(nctrls, struct cfg_aux);
+
+    id = 1000;
+    y = 22; /* Leave some room for the dialog title */
+    for (i = fe->cfg, j = fe->cfgaux; i->type != C_END; i++, j++) {
+	switch (i->type) {
+	  case C_STRING:
+	    /*
+	     * Edit box with a label beside it.
+	     */
+	    mkctrl(fe, col1l, col1r, y + 1, y + 11,
+		   TEXT("Static"), SS_LEFTNOWORDWRAP, 0, i->name, id++);
+	    mkctrl(fe, col2l, col2r, y, y + 12,
+		   TEXT("EDIT"), WS_BORDER | WS_TABSTOP | ES_AUTOHSCROLL,
+		   0, "", (j->ctlid = id++));
+	    SetDlgItemTextA(fe->cfgbox, j->ctlid, i->sval);
+	    break;
+
+	  case C_BOOLEAN:
+	    /*
+	     * Simple checkbox.
+	     */
+	    mkctrl(fe, col1l, col2r, y + 1, y + 11, TEXT("BUTTON"),
+		   BS_NOTIFY | BS_AUTOCHECKBOX | WS_TABSTOP,
+		   0, i->name, (j->ctlid = id++));
+	    CheckDlgButton(fe->cfgbox, j->ctlid, (i->ival != 0));
+	    break;
+
+	  case C_CHOICES:
+	    /*
+	     * Drop-down list with a label beside it.
+	     */
+	    mkctrl(fe, col1l, col1r, y + 1, y + 11,
+		   TEXT("STATIC"), SS_LEFTNOWORDWRAP, 0, i->name, id++);
+	    ctl = mkctrl(fe, col2l, col2r, y, y + 48,
+			 TEXT("COMBOBOX"), WS_BORDER | WS_TABSTOP |
+			 CBS_DROPDOWNLIST | CBS_HASSTRINGS,
+			 0, "", (j->ctlid = id++));
+	    {
+		char c, *p, *q, *str;
+
+		p = i->sval;
+		c = *p++;
+		while (*p) {
+		    q = p;
+		    while (*q && *q != c) q++;
+		    str = snewn(q-p+1, char);
+		    strncpy(str, p, q-p);
+		    str[q-p] = '\0';
+		    {
+			TCHAR ws[50];
+			MultiByteToWideChar (CP_ACP, 0, str, -1, ws, 50);
+			SendMessage(ctl, CB_ADDSTRING, 0, (LPARAM)ws);
+		    }
+		    
+		    sfree(str);
+		    if (*q) q++;
+		    p = q;
+		}
+	    }
+	    SendMessage(ctl, CB_SETCURSEL, i->ival, 0);
+	    break;
+	}
+
+	y += 15;
+    }
+
+}
+#endif
+
 static int CALLBACK ConfigDlgProc(HWND hwnd, UINT msg,
 				  WPARAM wParam, LPARAM lParam)
 {
@@ -1534,15 +1916,32 @@
 
     switch (msg) {
       case WM_INITDIALOG:
-	return 0;
+#ifdef _WIN32_WCE
+	{
+            char *title;
 
+	    fe = (frontend *) lParam;
+	    SetWindowLong(hwnd, GWL_USERDATA, lParam);
+	    fe->cfgbox = hwnd;
+
+            fe->cfg = frontend_get_config(fe, fe->cfg_which, &title);
+
+    	    make_dialog_full_screen(hwnd);
+
+	    SetDlgItemTextA(hwnd, IDC_CONFIG_CAPTION, title);
+	    SendDlgItemMessage(hwnd, IDC_CONFIG_CAPTION, WM_SETFONT,
+			       (WPARAM) dialog_title_font(), 0);
+
+	    create_config_controls(fe);
+	}
+#endif
+	return TRUE;
+
       case WM_COMMAND:
 	/*
 	 * OK and Cancel are special cases.
 	 */
-	if ((HIWORD(wParam) == BN_CLICKED ||
-	     HIWORD(wParam) == BN_DOUBLECLICKED) &&
-	    (LOWORD(wParam) == IDOK || LOWORD(wParam) == IDCANCEL)) {
+	if ((LOWORD(wParam) == IDOK || LOWORD(wParam) == IDCANCEL)) {
 	    if (LOWORD(wParam) == IDOK) {
 		char *err = frontend_set_config(fe, fe->cfg_which, fe->cfg);
 
@@ -1550,10 +1949,18 @@
 		    MessageBox(hwnd, err, "Validation error",
 			       MB_ICONERROR | MB_OK);
 		} else {
+#ifdef _WIN32_WCE
+		    EndDialog(hwnd, 2);
+#else
 		    fe->dlg_done = 2;
+#endif
 		}
 	    } else {
+#ifdef _WIN32_WCE
+		EndDialog(hwnd, 1);
+#else
 		fe->dlg_done = 1;
+#endif
 	    }
 	    return 0;
 	}
@@ -1570,13 +1977,19 @@
 
 	if (i->type == C_STRING && HIWORD(wParam) == EN_CHANGE) {
 	    char buffer[4096];
+#ifdef _WIN32_WCE
+	    TCHAR wBuffer[4096];
+	    GetDlgItemText(fe->cfgbox, j->ctlid, wBuffer, 4096);
+	    WideCharToMultiByte(CP_ACP, 0, wBuffer, -1, buffer, 4096, NULL, NULL);
+#else
 	    GetDlgItemText(fe->cfgbox, j->ctlid, buffer, lenof(buffer));
+#endif
 	    buffer[lenof(buffer)-1] = '\0';
 	    sfree(i->sval);
 	    i->sval = dupstr(buffer);
 	} else if (i->type == C_BOOLEAN && 
 		   (HIWORD(wParam) == BN_CLICKED ||
-		    HIWORD(wParam) == BN_DOUBLECLICKED)) {
+		    HIWORD(wParam) == BN_DBLCLK)) {
 	    i->ival = IsDlgButtonChecked(fe->cfgbox, j->ctlid);
 	} else if (i->type == C_CHOICES &&
 		   HIWORD(wParam) == CBN_SELCHANGE) {
@@ -1594,6 +2007,7 @@
     return 0;
 }
 
+#ifndef _WIN32_WCE
 HWND mkctrl(frontend *fe, int x1, int x2, int y1, int y2,
 	    char *wclass, int wstyle,
 	    int exstyle, const char *wtext, int wid)
@@ -1605,9 +2019,13 @@
     SendMessage(ret, WM_SETFONT, (WPARAM)fe->cfgfont, MAKELPARAM(TRUE, 0));
     return ret;
 }
+#endif
 
 static void about(frontend *fe)
 {
+#ifdef _WIN32_WCE
+    DialogBox(fe->inst, MAKEINTRESOURCE(IDD_ABOUT), fe->hwnd, AboutDlgProc);
+#else
     int i;
     WNDCLASS wc;
     MSG msg;
@@ -1629,7 +2047,7 @@
     strings[nstrings++] = "from Simon Tatham's Portable Puzzle Collection";
     strings[nstrings++] = ver;
 
-    wc.style = CS_DBLCLKS | CS_SAVEBITS | CS_BYTEALIGNWINDOW;
+    wc.style = CS_DBLCLKS | CS_SAVEBITS;
     wc.lpfnWndProc = DefDlgProc;
     wc.cbClsExtra = 0;
     wc.cbWndExtra = DLGWINDOWEXTRA + 8;
@@ -1745,7 +2163,7 @@
     SendMessage(fe->cfgbox, WM_INITDIALOG, 0, 0);
 
     EnableWindow(fe->hwnd, FALSE);
-    ShowWindow(fe->cfgbox, SW_NORMAL);
+    ShowWindow(fe->cfgbox, SW_SHOWNORMAL);
     while ((gm=GetMessage(&msg, NULL, 0, 0)) > 0) {
 	if (!IsDialogMessage(fe->cfgbox, &msg))
 	    DispatchMessage(&msg);
@@ -1756,10 +2174,19 @@
     SetForegroundWindow(fe->hwnd);
     DestroyWindow(fe->cfgbox);
     DeleteObject(fe->cfgfont);
+#endif
 }
 
 static int get_config(frontend *fe, int which)
 {
+#ifdef _WIN32_WCE
+    fe->cfg_which = which;
+
+    return DialogBoxParam(fe->inst,
+			  MAKEINTRESOURCE(IDD_CONFIG),
+			  fe->hwnd, ConfigDlgProc,
+			  (LPARAM) fe) == 2;
+#else
     config_item *i;
     struct cfg_aux *j;
     char *title;
@@ -1774,7 +2201,7 @@
     int winwidth, winheight, col1l, col1r, col2l, col2r, y;
     int height, width, maxlabel, maxcheckbox;
 
-    wc.style = CS_DBLCLKS | CS_SAVEBITS | CS_BYTEALIGNWINDOW;
+    wc.style = CS_DBLCLKS | CS_SAVEBITS;
     wc.lpfnWndProc = DefDlgProc;
     wc.cbClsExtra = 0;
     wc.cbWndExtra = DLGWINDOWEXTRA + 8;
@@ -1981,7 +2408,7 @@
     SendMessage(fe->cfgbox, WM_INITDIALOG, 0, 0);
 
     EnableWindow(fe->hwnd, FALSE);
-    ShowWindow(fe->cfgbox, SW_NORMAL);
+    ShowWindow(fe->cfgbox, SW_SHOWNORMAL);
     while ((gm=GetMessage(&msg, NULL, 0, 0)) > 0) {
 	if (!IsDialogMessage(fe->cfgbox, &msg))
 	    DispatchMessage(&msg);
@@ -1997,8 +2424,48 @@
     sfree(fe->cfgaux);
 
     return (fe->dlg_done == 2);
+#endif
 }
 
+#ifdef _WIN32_WCE
+static void calculate_bitmap_position(frontend *fe, int x, int y)
+{
+    /* Pocket PC - center the game in the full screen window */
+    int yMargin;
+    RECT rcClient;
+
+    GetClientRect(fe->hwnd, &rcClient);
+    fe->bitmapPosition.left = (rcClient.right  - x) / 2;
+    yMargin = rcClient.bottom - y;
+
+    if (fe->numpad != NULL) {
+	RECT rcPad;
+	GetWindowRect(fe->numpad, &rcPad);
+	yMargin -= rcPad.bottom - rcPad.top;
+    }
+
+    if (fe->statusbar != NULL) {
+	RECT rcStatus;
+	GetWindowRect(fe->statusbar, &rcStatus);
+	yMargin -= rcStatus.bottom - rcStatus.top;
+    }
+
+    fe->bitmapPosition.top = yMargin / 2;
+
+    fe->bitmapPosition.right  = fe->bitmapPosition.left + x;
+    fe->bitmapPosition.bottom = fe->bitmapPosition.top  + y;
+}
+#else
+static void calculate_bitmap_position(frontend *fe, int x, int y)
+{
+    /* Plain Windows - position the game in the upper-left corner */
+    fe->bitmapPosition.left = 0;
+    fe->bitmapPosition.top = 0;
+    fe->bitmapPosition.right  = fe->bitmapPosition.left + x;
+    fe->bitmapPosition.bottom = fe->bitmapPosition.top  + y;
+}
+#endif
+
 static void new_game_size(frontend *fe)
 {
     RECT r, sr;
@@ -2018,23 +2485,31 @@
     } else {
 	sr.left = sr.right = sr.top = sr.bottom = 0;
     }
+#ifndef _WIN32_WCE
     SetWindowPos(fe->hwnd, NULL, 0, 0,
 		 r.right - r.left,
 		 r.bottom - r.top + sr.bottom - sr.top,
 		 SWP_NOMOVE | SWP_NOZORDER);
+#endif
 
     check_window_size(fe, &x, &y);
 
+#ifndef _WIN32_WCE
     if (fe->statusbar != NULL)
 	SetWindowPos(fe->statusbar, NULL, 0, y, x,
 		     sr.bottom - sr.top, SWP_NOZORDER);
+#endif
 
     if (fe->bitmap) DeleteObject(fe->bitmap);
 
     hdc = GetDC(fe->hwnd);
     fe->bitmap = CreateCompatibleBitmap(hdc, x, y);
+    calculate_bitmap_position(fe, x, y);
     ReleaseDC(fe->hwnd, hdc);
 
+#ifdef _WIN32_WCE
+    InvalidateRect(fe->hwnd, NULL, TRUE);
+#endif
     midend_redraw(fe->me);
 }
 
@@ -2083,6 +2558,13 @@
 	DestroyWindow(hwnd);
 	return 0;
       case WM_COMMAND:
+#ifdef _WIN32_WCE
+	/* Numeric pad sends WM_COMMAND messages */
+	if ((wParam >= IDM_KEYEMUL) && (wParam < IDM_KEYEMUL + 256))
+	{
+	    midend_process_key(fe->me, 0, 0, wParam - IDM_KEYEMUL);
+	}
+#endif
 	cmd = wParam & ~0xF;	       /* low 4 bits reserved to Windows */
 	switch (cmd) {
 	  case IDM_NEW:
@@ -2227,6 +2709,7 @@
 	    }
 
 	    break;
+#ifndef _WIN32_WCE
           case IDM_HELPC:
 	    start_help(fe, NULL);
 	    break;
@@ -2233,6 +2716,7 @@
           case IDM_GAMEHELP:
 	    start_help(fe, help_topic);
             break;
+#endif
 	  default:
 	    {
 		int p = ((wParam &~ 0xF) - IDM_PRESETS) / 0x10;
@@ -2246,7 +2730,9 @@
 	}
 	break;
       case WM_DESTROY:
+#ifndef _WIN32_WCE
 	stop_help(fe);
+#endif
 	PostQuitMessage(0);
 	return 0;
       case WM_PAINT:
@@ -2254,16 +2740,22 @@
 	    PAINTSTRUCT p;
 	    HDC hdc, hdc2;
 	    HBITMAP prevbm;
+	    RECT rcDest;
 
 	    hdc = BeginPaint(hwnd, &p);
 	    hdc2 = CreateCompatibleDC(hdc);
 	    prevbm = SelectObject(hdc2, fe->bitmap);
+#ifdef _WIN32_WCE
+	    FillRect(hdc, &(p.rcPaint), (HBRUSH) GetStockObject(WHITE_BRUSH));
+#endif
+	    IntersectRect(&rcDest, &(fe->bitmapPosition), &(p.rcPaint));
 	    BitBlt(hdc,
-		   p.rcPaint.left, p.rcPaint.top,
-		   p.rcPaint.right - p.rcPaint.left,
-		   p.rcPaint.bottom - p.rcPaint.top,
+		   rcDest.left, rcDest.top,
+		   rcDest.right - rcDest.left,
+		   rcDest.bottom - rcDest.top,
 		   hdc2,
-		   p.rcPaint.left, p.rcPaint.top,
+		   rcDest.left - fe->bitmapPosition.left,
+		   rcDest.top - fe->bitmapPosition.top,
 		   SRCCOPY);
 	    SelectObject(hdc2, prevbm);
 	    DeleteDC(hdc2);
@@ -2368,10 +2860,32 @@
 	    else if (message == WM_RBUTTONDOWN || is_alt_pressed())
 		button = RIGHT_BUTTON;
 	    else
+#ifndef _WIN32_WCE
 		button = LEFT_BUTTON;
+#else
+		if ((thegame.flags & REQUIRE_RBUTTON) == 0)
+		    button = LEFT_BUTTON;
+		else
+		{
+		    SHRGINFO shrgi;
 
-	    if (!midend_process_key(fe->me, (signed short)LOWORD(lParam),
-				    (signed short)HIWORD(lParam), button))
+		    shrgi.cbSize     = sizeof(SHRGINFO);
+		    shrgi.hwndClient = hwnd;
+		    shrgi.ptDown.x   = (signed short)LOWORD(lParam);
+		    shrgi.ptDown.y   = (signed short)HIWORD(lParam);
+		    shrgi.dwFlags    = SHRG_RETURNCMD;
+
+		    if (GN_CONTEXTMENU == SHRecognizeGesture(&shrgi))
+			button = RIGHT_BUTTON;
+		    else
+			button = LEFT_BUTTON;
+		}
+#endif
+
+	    if (!midend_process_key(fe->me,
+				    (signed short)LOWORD(lParam) - fe->bitmapPosition.left,
+				    (signed short)HIWORD(lParam) - fe->bitmapPosition.top,
+				    button))
 		PostQuitMessage(0);
 
 	    SetCapture(hwnd);
@@ -2395,8 +2909,10 @@
 	    else
 		button = LEFT_RELEASE;
 
-	    if (!midend_process_key(fe->me, (signed short)LOWORD(lParam),
-				    (signed short)HIWORD(lParam), button))
+	    if (!midend_process_key(fe->me,
+				    (signed short)LOWORD(lParam) - fe->bitmapPosition.left,
+				    (signed short)HIWORD(lParam) - fe->bitmapPosition.top,
+				    button))
 		PostQuitMessage(0);
 
 	    ReleaseCapture();
@@ -2413,8 +2929,10 @@
 	    else
 		button = LEFT_DRAG;
 	    
-	    if (!midend_process_key(fe->me, (signed short)LOWORD(lParam),
-				    (signed short)HIWORD(lParam), button))
+	    if (!midend_process_key(fe->me,
+				    (signed short)LOWORD(lParam) - fe->bitmapPosition.left,
+				    (signed short)HIWORD(lParam) - fe->bitmapPosition.top,
+				    button))
 		PostQuitMessage(0);
 	}
 	break;
@@ -2435,11 +2953,34 @@
     return DefWindowProc(hwnd, message, wParam, lParam);
 }
 
+#ifdef _WIN32_WCE
+static int FindPreviousInstance()
+{
+    /* Check if application is running. If it's running then focus on the window */
+    HWND hOtherWnd = NULL;
+
+    hOtherWnd = FindWindow (wGameName, wGameName);
+    if (hOtherWnd)
+    {
+        SetForegroundWindow (hOtherWnd);
+        return TRUE;
+    }
+
+    return FALSE;
+}
+#endif
+
 int WINAPI WinMain(HINSTANCE inst, HINSTANCE prev, LPSTR cmdline, int show)
 {
     MSG msg;
     char *error;
 
+#ifdef _WIN32_WCE
+    MultiByteToWideChar (CP_ACP, 0, thegame.name, -1, wGameName, 256);
+    if (FindPreviousInstance ())
+        return 0;
+#endif
+
     InitCommonControls();
 
     if (!prev) {
@@ -2451,12 +2992,18 @@
 	wndclass.cbWndExtra = 0;
 	wndclass.hInstance = inst;
 	wndclass.hIcon = LoadIcon(inst, MAKEINTRESOURCE(200));
+#ifndef _WIN32_WCE
 	if (!wndclass.hIcon)	       /* in case resource file is absent */
 	    wndclass.hIcon = LoadIcon(inst, IDI_APPLICATION);
+#endif
 	wndclass.hCursor = LoadCursor(NULL, IDC_ARROW);
 	wndclass.hbrBackground = NULL;
 	wndclass.lpszMenuName = NULL;
+#ifdef _WIN32_WCE
+	wndclass.lpszClassName = wGameName;
+#else
 	wndclass.lpszClassName = thegame.name;
+#endif
 
 	RegisterClass(&wndclass);
     }