/*\r
* JAWS.c -- Code for Windows front end to XBoard to use it with JAWS\r
- * $Id: winboard.c,v 2.3 2003/11/25 05:25:20 mann Exp $\r
*\r
* Copyright 1991 by Digital Equipment Corporation, Maynard,\r
- * Massachusetts. Enhancements Copyright\r
- * 1992-2001,2002,2003,2004,2005,2006,2007,2008,2009 Free Software\r
- * Foundation, Inc.\r
+ * Massachusetts.\r
+ *\r
+ * Enhancements Copyright 1992-2001, 2002, 2003, 2004, 2005, 2006,\r
+ * 2007, 2008, 2009 Free Software Foundation, Inc.\r
*\r
* XBoard borrows its colors and the bitmaps.xchess bitmap set from XChess,\r
* which was written and is copyrighted by Wayne Christopher.\r
// BOARD_LEFT as 0, BOARD_RGHT and BOARD_HEIGHT as 8, and set holdingssizes to 0.\r
// You will need to build with jaws.rc in stead of winboard.rc.\r
\r
-// from common.h, but 'extern' added to it, so the actual declaraton can remain in backend.c\r
-\r
-extern long whiteTimeRemaining, blackTimeRemaining, timeControl, timeIncrement;\r
+// from resource.h\r
+\r
+#define IDM_PossibleAttackMove 1800\r
+#define IDM_PossibleAttacked 1801\r
+#define IDM_SayMachineMove 1802\r
+#define IDM_ReadRow 1803\r
+#define IDM_ReadColumn 1804\r
+#define IDM_SayCurrentPos 1805\r
+#define IDM_SayAllBoard 1806\r
+#define IDM_SayUpperDiagnols 1807\r
+#define IDM_SayLowerDiagnols 1808\r
+#define IDM_SayClockTime 1810\r
+#define IDM_SayWhosTurn 1811\r
+#define IDM_SayKnightMoves 1812\r
+#define ID_SHITTY_HI 1813\r
+#define IDM_SayWhitePieces 1816\r
+#define IDM_SayBlackPieces 1817\r
\r
-#if 0\r
-// from moves.h, but no longer needed, as the new routines are all moved to winboard.c\r
\r
-extern char* PieceToName P((ChessSquare p, int i));\r
-extern char* SquareToChar P((int Xpos)); \r
-extern char* SquareToNum P((int Ypos));\r
-extern int CoordToNum P((char c));\r
+// from common.h, but 'extern' added to it, so the actual declaraton can remain in backend.c\r
\r
-#endif\r
+extern long whiteTimeRemaining, blackTimeRemaining, timeControl, timeIncrement;\r
\r
// from moves.c, added WinBoard_F piece types and ranks / files\r
\r
"Empty"\r
};\r
\r
+char *pieceTypeName[] = {\r
+ "Pawn", "Knight", "Bishop", "Rook", "Queen", \r
+ "Guard", "Elephant", "Arch Bishop", "Chancellor",\r
+ "General", "Man", "Cannon", "Night Rider",\r
+ "Crowned Bishop", "Crowned Rook", "Grass Hopper", "Veteran",\r
+ "Falcon", "Amazon", "Snake", "Unicorn",\r
+ "King",\r
+ "Pawn", "Knight", "Bishop", "Rook", "Queen", \r
+ "Guard", "Elephant", "Arch Bishop", "Chancellor",\r
+ "General", "Man", "Cannon", "Night Rider",\r
+ "Crowned Bishop", "Crowned Rook", "Grass Hopper", "Veteran",\r
+ "Falcon", "Amazon", "Snake", "Unicorn",\r
+ "King",\r
+ "Empty"\r
+ };\r
+\r
int CoordToNum(c)\r
char c;\r
{\r
int i;\r
{\r
if(i) return pieceToName[(int) p];\r
- return pieceToName[(int) p]+6;\r
+ return pieceTypeName[(int) p];\r
}\r
\r
char* SquareToChar(x)\r
\r
\r
// from winboard.c: all new routines\r
-\r
-#include "jfwapi.h"\r
-#include "jaws.h"\r
+#define JFWAPI __declspec(dllimport)\r
+JFWAPI BOOL WINAPI JFWSayString (LPCTSTR lpszStrinToSpeak, BOOL bInterrupt);\r
\r
typedef JFWAPI BOOL (WINAPI *PSAYSTRING)(LPCTSTR lpszStrinToSpeak, BOOL bInterrupt);\r
\r
static int oldFromX, oldFromY;\r
static int timeflag;\r
static int suppressClocks = 0;\r
+static int suppressOneKey = 0;\r
+static HANDLE hAccelJAWS;\r
+\r
+typedef struct { char *name; int code; } MenuItemDesc;\r
+\r
+MenuItemDesc menuItemJAWS[] = {\r
+{"Say Clock &Time\tAlt+T", IDM_SayClockTime },\r
+{"-", 0 },\r
+{"Say Last &Move\tAlt+M", IDM_SayMachineMove },\r
+{"Say W&ho's Turn\tAlt+X", IDM_SayWhosTurn },\r
+{"-", 0 },\r
+{"Say Complete &Position\tAlt+P",IDM_SayAllBoard },\r
+{"Say &White Pieces\tAlt+W", IDM_SayWhitePieces },\r
+{"Say &Black Pieces\tAlt+B", IDM_SayBlackPieces },\r
+{"Say Board &Rank\tAlt+R", IDM_ReadRow },\r
+{"Say Board &File\tAlt+F", IDM_ReadColumn },\r
+{"-", 0 },\r
+{"Say &Upper Diagonals\tAlt+U", IDM_SayUpperDiagnols },\r
+{"Say &Lower Diagonals\tAlt+L", IDM_SayLowerDiagnols },\r
+{"Say K&night Moves\tAlt+N", IDM_SayKnightMoves },\r
+{"Say Current &Square\tAlt+S", IDM_SayCurrentPos },\r
+{"Say &Attacks\tAlt+A", IDM_PossibleAttackMove },\r
+{"Say Attacke&d\tAlt+D", IDM_PossibleAttacked },\r
+{NULL, 0}\r
+};\r
+\r
+ACCEL acceleratorsJAWS[] = {\r
+{FVIRTKEY|FALT, 'T', IDM_SayClockTime },\r
+{FVIRTKEY|FALT, 'M', IDM_SayMachineMove },\r
+{FVIRTKEY|FALT, 'X', IDM_SayWhosTurn },\r
+{FVIRTKEY|FALT, 'P', IDM_SayAllBoard },\r
+{FVIRTKEY|FALT, 'W', IDM_SayWhitePieces },\r
+{FVIRTKEY|FALT, 'B', IDM_SayBlackPieces },\r
+{FVIRTKEY|FALT, 'R', IDM_ReadRow },\r
+{FVIRTKEY|FALT, 'F', IDM_ReadColumn },\r
+{FVIRTKEY|FALT, 'U', IDM_SayUpperDiagnols },\r
+{FVIRTKEY|FALT, 'L', IDM_SayLowerDiagnols },\r
+{FVIRTKEY|FALT, 'N', IDM_SayKnightMoves },\r
+{FVIRTKEY|FALT, 'S', IDM_SayCurrentPos },\r
+{FVIRTKEY|FALT, 'A', IDM_PossibleAttackMove },\r
+{FVIRTKEY|FALT, 'D', IDM_PossibleAttacked }\r
+};\r
+\r
+void\r
+AdaptMenu()\r
+{\r
+ HMENU menuMain, menuJAWS;\r
+ MENUBARINFO helpMenuInfo;\r
+ int i;\r
+\r
+ helpMenuInfo.cbSize = sizeof(helpMenuInfo);\r
+ menuMain = GetMenu(hwndMain);\r
+ if(appData.debugMode) fprintf(debugFP, "hwndMain: %8x %8x\n", hwndMain, menuMain);\r
+ menuJAWS = CreatePopupMenu();\r
+ \r
+ for(i=0; menuItemJAWS[i].name; i++) {\r
+ if(menuItemJAWS[i].name[0] == '-') \r
+ AppendMenu(menuJAWS, MF_SEPARATOR, (UINT_PTR) 0, NULL);\r
+ else AppendMenu(menuJAWS, MF_ENABLED|MF_STRING, \r
+ (UINT_PTR) menuItemJAWS[i].code, (LPCTSTR) menuItemJAWS[i].name);\r
+ }\r
+ InsertMenu(menuMain, 5, MF_BYPOSITION|MF_POPUP|MF_ENABLED|MF_STRING, \r
+ (UINT_PTR) menuJAWS, "&JAWS");\r
+ oldMenuItemState[6] = oldMenuItemState[5];\r
+ DrawMenuBar(hwndMain);\r
+}\r
\r
BOOL\r
InitJAWS()\r
}\r
\r
{\r
- // [HGM] kludge to reduce need for modification of winboard.c: mak tinyLayout menu identical\r
+ // [HGM] kludge to reduce need for modification of winboard.c: make tinyLayout menu identical\r
// to standard layout, so that code for switching between them does not have to be deleted\r
- HMENU hmenu = GetMenu(hwndMain);\r
int i;\r
\r
+ AdaptMenu();\r
menuBarText[0][5] = "&JAWS";\r
for(i=0; i<7; i++) menuBarText[1][i] = menuBarText[0][i];\r
- for (i=0; menuBarText[tinyLayout][i]; i++) {\r
- ModifyMenu(hmenu, i, MF_STRING|MF_BYPOSITION|MF_POPUP, \r
- (UINT)GetSubMenu(hmenu, i), menuBarText[tinyLayout][i]);\r
- }\r
- DrawMenuBar(hwndMain);\r
}\r
\r
+ hAccelJAWS = CreateAcceleratorTable(acceleratorsJAWS, 14);\r
+\r
/* initialize cursor position */\r
fromX = fromY = 0;\r
SetHighlights(fromX, fromY, -1, -1);\r
return TRUE;\r
}\r
\r
+int beeps[] = { 1, 0, 0, 0, 0 };\r
+int beepCodes[] = { 0, MB_OK, MB_ICONERROR, MB_ICONQUESTION, MB_ICONEXCLAMATION, MB_ICONASTERISK };\r
+\r
VOID\r
KeyboardEvent(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)\r
{\r
ChessSquare currentPiece;\r
char *piece, *xchar, *ynum ;\r
- int n;\r
+ int n, beepType = 1; // empty beep\r
\r
if(fromX == -1 || fromY == -1) {\r
fromX = BOARD_LEFT; fromY = 0;\r
switch(wParam) {\r
case VK_LEFT:\r
if(fromX == BOARD_RGHT+1) fromX -= 2; else\r
- if(fromX == BOARD_LEFT) { if(fromY >= BOARD_HEIGHT - gameInfo.holdingsSize) fromX -= 2; } else\r
- if(fromX > BOARD_LEFT) fromX--;\r
+ if(fromX == BOARD_LEFT) { if(fromY >= BOARD_HEIGHT - gameInfo.holdingsSize) fromX -= 2; else beepType = 0; } else\r
+ if(fromX > BOARD_LEFT) fromX--; else beepType = 0; // off-board beep\r
break;\r
case VK_RIGHT:\r
if(fromX == BOARD_LEFT-2) fromX += 2; else\r
- if(fromX == BOARD_RGHT-1) { if(fromY < gameInfo.holdingsSize) fromX += 2; } else\r
- if(fromX < BOARD_RGHT-1) fromX++;\r
+ if(fromX == BOARD_RGHT-1) { if(fromY < gameInfo.holdingsSize) fromX += 2; else beepType = 0; } else\r
+ if(fromX < BOARD_RGHT-1) fromX++; else beepType = 0;\r
break;\r
case VK_UP:\r
- if(fromX == BOARD_RGHT+1) { if(fromY < gameInfo.holdingsSize - 1) fromY++; } else\r
- if(fromY < BOARD_HEIGHT-1) fromY++;\r
+ if(fromX == BOARD_RGHT+1) { if(fromY < gameInfo.holdingsSize - 1) fromY++; else beepType = 0; } else\r
+ if(fromY < BOARD_HEIGHT-1) fromY++; else beepType = 0;\r
break;\r
case VK_DOWN:\r
- if(fromX == BOARD_LEFT-2) { if(fromY > BOARD_HEIGHT - gameInfo.holdingsSize) fromY--; } else\r
- if(fromY > 0) fromY--;\r
+ if(fromX == BOARD_LEFT-2) { if(fromY > BOARD_HEIGHT - gameInfo.holdingsSize) fromY--; else beepType = 0; } else\r
+ if(fromY > 0) fromY--; else beepType = 0;\r
break;\r
}\r
SetHighlights(fromX, fromY, -1, -1);\r
DrawPosition(FALSE, NULL);\r
currentPiece = boards[currentMove][fromY][fromX];\r
piece = PieceToName(currentPiece,1);\r
- if(currentPiece != EmptySquare) MessageBeep(currentPiece < (int)BlackPawn ? MB_OK : MB_ICONEXCLAMATION);\r
+ if(beepType == 1 && currentPiece != EmptySquare) beepType = currentPiece < (int) BlackPawn ? 2 : 3; // white or black beep\r
+ if(beeps[beepType] == beeps[1] && (fromX == BOARD_RGHT+1 || fromX == BOARD_LEFT-2)) beepType = 4; // holdings beep\r
+ beepType = beeps[beepType]%6;\r
+ if(beepType) MessageBeep(beepCodes[beepType]);\r
if(fromX == BOARD_LEFT - 2) {\r
SayString("black holdings", FALSE);\r
if(currentPiece != EmptySquare) {\r
char buf[MSG_SIZ];\r
n = boards[currentMove][fromY][1];\r
- sprintf(buf, "%d %s%s", n, piece+6, n == 1 ? "" : "s");\r
+ sprintf(buf, "%d %s%s", n, PieceToName(currentPiece,0), n == 1 ? "" : "s");\r
SayString(buf, TRUE);\r
}\r
} else\r
if(currentPiece != EmptySquare) {\r
char buf[MSG_SIZ];\r
n = boards[currentMove][fromY][BOARD_WIDTH-2];\r
- sprintf(buf, "%d %s%s", n, piece+6, n == 1 ? "" : "s");\r
+ sprintf(buf, "%d %s%s", n, PieceToName(currentPiece,0), n == 1 ? "" : "s");\r
SayString(buf, TRUE);\r
}\r
} else\r
SayString(xchar, FALSE);\r
SayString(ynum, FALSE);\r
SayString(piece, FALSE);\r
- if((fromX-BOARD_LEFT) ^ fromY)\r
- SayString("on a dark square",FALSE);\r
- else \r
+ if(((fromX-BOARD_LEFT) ^ fromY)&1)\r
SayString("on a light square",FALSE);\r
+ else \r
+ SayString("on a dark square",FALSE);\r
\r
PossibleAttacked();\r
return;\r
{\r
int Xpos, Ypos;\r
ChessSquare currentpiece;\r
- char *piece, *xchar, *ynum ;\r
+ char *piece, *ynum ;\r
\r
if(gameInfo.holdingsWidth) {\r
int first = 0;\r
for(Xpos=BOARD_LEFT; Xpos<BOARD_RGHT; Xpos++) {\r
currentpiece = boards[currentMove][Ypos][Xpos]; \r
if(currentpiece != EmptySquare) {\r
- int count = 0, oldX = Xpos;\r
+ int count = 0;\r
char buf[50];\r
piece = PieceToName(currentpiece,1);\r
while(Xpos < BOARD_RGHT && boards[currentMove][Ypos][Xpos] == currentpiece)\r
}\r
}\r
\r
+extern char *commentList[];\r
\r
VOID\r
SayMachineMove(int evenIfDuplicate)\r
{\r
int len, xPos, yPos, moveNr, secondSpace = 0, castle = 0, n;\r
ChessSquare currentpiece;\r
- char *piece, *xchar, *ynum, *p;\r
+ char *piece, *xchar, *ynum, *p, checkMark = 0;\r
char c, buf[MSG_SIZ], comment[MSG_SIZ];\r
static char disambiguation[2];\r
static int previousMove = 0;\r
if(secondSpace) len = secondSpace; // position behind move\r
if(messageText[len-1] == '+' || messageText[len-1] == '#') { /* you are in checkmate */\r
len--; // strip off check or mate indicator\r
+ checkMark = messageText[len]; // make sure still seen after we stip off promo piece\r
}\r
if(messageText[len-2] == '=') { /* promotion */\r
len-=2; // strip off promotion piece\r
SayString(piece, FALSE);\r
} else SayString("Capturing onn passann",FALSE);\r
}\r
- if(messageText[len] == '+') SayString("check", FALSE); else\r
- if(messageText[len] == '#') {\r
+ }\r
+ if(checkMark == '+') SayString("check", FALSE); else\r
+ if(checkMark == '#') {\r
SayString("finishing off", FALSE);\r
SayString(WhiteOnMove(n) ? "White" : "Black", FALSE);\r
- }\r
}\r
}\r
\r
SayString(comment, FALSE); // alphabetic comment (usually game end)\r
} else if(p) SayString(p, FALSE);\r
\r
+ if(commentDialog && commentList[currentMove]) SetFocus(commentDialog);\r
+\r
} else {\r
/* starts not with digit */\r
if(StrCaseStr(messageText, "illegal")) PlayIcsUnfinishedSound();\r
return (x%3000 == 0);\r
}\r
\r
+#define JAWS_ARGS \\r
+ { "beepOffBoard", ArgInt, (LPVOID) beeps, TRUE },\\r
+ { "beepEmpty", ArgInt, (LPVOID) (beeps+1), TRUE },\\r
+ { "beepWhite", ArgInt, (LPVOID) (beeps+2), TRUE },\\r
+ { "beepBlack", ArgInt, (LPVOID) (beeps+3), TRUE },\\r
+ { "beepHoldings", ArgInt, (LPVOID) (beeps+4), TRUE },\\r
+\r
#define JAWS_ALT_INTERCEPT \\r
- if(isalpha((char)wParam)) {\\r
- /* capitals of any ind are intercepted and distinguished by left and right shift */\\r
- int mine = GetKeyState(VK_RSHIFT) < 0;\\r
- if(mine || GetKeyState(VK_LSHIFT) < 0) {\\r
-\\r
- if(gameMode == IcsPlayingWhite || gameMode == MachinePlaysBlack) mine = !mine;\\r
-\\r
- if(ToLower((char)wParam) == 'x') {\\r
- SayPieces(mine ? WhitePlay : BlackPlay);\\r
- break;\\r
- } else\\r
- if(CharToPiece((char)wParam) != EmptySquare) {\\r
- SayPieces(CharToPiece(mine ? ToUpper((char)wParam) : ToLower((char)wParam)));\\r
- break;\\r
- }\\r
- }\\r
+ if(suppressOneKey) {\\r
+ suppressOneKey = 0;\\r
+ if(GetKeyState(VK_MENU) < 0 && GetKeyState(VK_CONTROL) < 0) break;\\r
}\\r
if ((char)wParam == 022 && gameMode == EditPosition) { /* <Ctl R>. Pop up piece menu */\\r
POINT pt; int x, y;\\r
#define JAWS_KB_NAVIGATION \\r
\\r
case WM_KEYDOWN:\\r
+\\r
+ if(GetKeyState(VK_MENU) < 0 && GetKeyState(VK_CONTROL) < 0) {\\r
+ /* Control + Alt + letter used for speaking piece positions */\\r
+ static int lastTime; static char lastChar;\\r
+ int mine = 0, time = GetTickCount(); char c;\\r
+\\r
+ if((char)wParam == lastChar && time-lastTime < 250) mine = 1;\\r
+ lastChar = wParam; lastTime = time;\\r
+ c = wParam;\\r
+\\r
+ if(gameMode == IcsPlayingWhite || gameMode == MachinePlaysBlack) mine = !mine;\\r
+\\r
+ if(ToLower(c) == 'x') {\\r
+ SayPieces(mine ? WhitePlay : BlackPlay);\\r
+ suppressOneKey = 1;\\r
+ break;\\r
+ } else\\r
+ if(CharToPiece(c) != EmptySquare) {\\r
+ SayPieces(CharToPiece(mine ? ToUpper(c) : ToLower(c)));\\r
+ suppressOneKey = 1;\\r
+ break;\\r
+ }\\r
+ }\\r
+\\r
switch (wParam) {\\r
case VK_LEFT:\\r
case VK_RIGHT:\\r
\\r
\r
\r
+#define JAWS_ACCEL \\r
+ !(!frozen && TranslateAccelerator(hwndMain, hAccelJAWS, &msg)) &&\r
+\r
#define JAWS_INIT if (!InitJAWS()) return (FALSE);\r
\r
#define JAWS_DELETE(X)\r
\r
#define JAWS_SILENCE if(suppressClocks) return;\r
\r
+#define JAWS_COPYRIGHT \\r
+ SetDlgItemText(hDlg, OPT_MESS, "Auditory/Keyboard Enhancements By: Ed Rodriguez (sort of)");\r
+\r
#define SAY(S) SayString((S), FALSE)\r
\r
#define SAYMACHINEMOVE() SayMachineMove(0)\r
\r
// After inclusion of this file somewhere early in winboard.c, the remaining part of the patch\r
// is scattered over winboard.c for actually calling the routines.\r
-//\r
-// * move fromX, fromY declaration to front, before incusion of this file. (Can be permanent change in winboard.c.)\r
-// * call InitJAWS(), after calling InitIntance(). (Using JAWS_INIT macro)\r
-// * add keyboard cases in main switch of WndProc, though JAWS_KB_NAVIGATION above, e.g. before WM_CHAR case.\r
-// * change the WM_CHAR case of same switch from "if(appData.icsActive)" to "if(appData.icsActive JAWS_IF_TAB)"\r
-// * add new menu cases in WM_COMMAND case of WndProc, e.g. before IDM_Forward. (throug macro defined above)\r
-// * add SAYMACHINEMOVE(); at the end of DisplayMessage();\r
-// * add SAY("board"); in WM_CHAR case of ConsoleTextSubclass, just before "SetFocus(buttondesc..."\r