2 * JAWS.c -- Code for Windows front end to XBoard to use it with JAWS
\r
4 * Copyright 1991 by Digital Equipment Corporation, Maynard,
\r
7 * Enhancements Copyright 1992-2001, 2002, 2003, 2004, 2005, 2006,
\r
8 * 2007, 2008, 2009 Free Software Foundation, Inc.
\r
10 * XBoard borrows its colors and the bitmaps.xchess bitmap set from XChess,
\r
11 * which was written and is copyrighted by Wayne Christopher.
\r
13 * The following terms apply to Digital Equipment Corporation's copyright
\r
14 * interest in XBoard:
\r
15 * ------------------------------------------------------------------------
\r
16 * All Rights Reserved
\r
18 * Permission to use, copy, modify, and distribute this software and its
\r
19 * documentation for any purpose and without fee is hereby granted,
\r
20 * provided that the above copyright notice appear in all copies and that
\r
21 * both that copyright notice and this permission notice appear in
\r
22 * supporting documentation, and that the name of Digital not be
\r
23 * used in advertising or publicity pertaining to distribution of the
\r
24 * software without specific, written prior permission.
\r
26 * DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
\r
27 * ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
\r
28 * DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
\r
29 * ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
\r
30 * WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
\r
31 * ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
\r
33 * ------------------------------------------------------------------------
\r
35 * The following terms apply to the enhanced version of XBoard
\r
36 * distributed by the Free Software Foundation:
\r
37 * ------------------------------------------------------------------------
\r
39 * GNU XBoard is free software: you can redistribute it and/or modify
\r
40 * it under the terms of the GNU General Public License as published by
\r
41 * the Free Software Foundation, either version 3 of the License, or (at
\r
42 * your option) any later version.
\r
44 * GNU XBoard is distributed in the hope that it will be useful, but
\r
45 * WITHOUT ANY WARRANTY; without even the implied warranty of
\r
46 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
\r
47 * General Public License for more details.
\r
49 * You should have received a copy of the GNU General Public License
\r
50 * along with this program. If not, see http://www.gnu.org/licenses/. *
\r
52 *------------------------------------------------------------------------
\r
53 ** See the file ChangeLog for a revision history. */
\r
55 // This file collects all patches for the JAWS version, so they can all be included in winboard.c
\r
56 // in one big swoop. At the bottom of this file you can read instructions for how to patch
\r
57 // WinBoard to work with JAWS with the aid of this file. Note that the code in this file
\r
58 // is for WinBoard 4.3 and later; for older WB versions you would have to throw out the
\r
59 // piece names for all pieces from Guard to Unicorn, #define ONE as '1', AAA as 'a',
\r
60 // BOARD_LEFT as 0, BOARD_RGHT and BOARD_HEIGHT as 8, and set holdingssizes to 0.
\r
61 // You will need to build with jaws.rc in stead of winboard.rc.
\r
65 #define IDM_PossibleAttackMove 1800
\r
66 #define IDM_PossibleAttacked 1801
\r
67 #define IDM_SayMachineMove 1802
\r
68 #define IDM_ReadRow 1803
\r
69 #define IDM_ReadColumn 1804
\r
70 #define IDM_SayCurrentPos 1805
\r
71 #define IDM_SayAllBoard 1806
\r
72 #define IDM_SayUpperDiagnols 1807
\r
73 #define IDM_SayLowerDiagnols 1808
\r
74 #define IDM_SayClockTime 1810
\r
75 #define IDM_SayWhosTurn 1811
\r
76 #define IDM_SayKnightMoves 1812
\r
77 #define ID_SHITTY_HI 1813
\r
78 #define IDM_SayWhitePieces 1816
\r
79 #define IDM_SayBlackPieces 1817
\r
82 // from common.h, but 'extern' added to it, so the actual declaraton can remain in backend.c
\r
84 extern long whiteTimeRemaining, blackTimeRemaining, timeControl, timeIncrement;
\r
87 // from moves.h, but no longer needed, as the new routines are all moved to winboard.c
\r
89 extern char* PieceToName P((ChessSquare p, int i));
\r
90 extern char* SquareToChar P((int Xpos));
\r
91 extern char* SquareToNum P((int Ypos));
\r
92 extern int CoordToNum P((char c));
\r
96 // from moves.c, added WinBoard_F piece types and ranks / files
\r
98 char *squareToChar[] = { "ay", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l" };
\r
100 char *squareToNum[] = {"naught", "1", "2", "3", "4", "5", "6", "7", "8", "9" };
\r
102 char *ordinals[] = {"zeroth", "first", "second", "third", "fourth", "fifth", "sixth", "seventh", "eighth", "nineth"};
\r
104 char *pieceToName[] = {
\r
105 "White Pawn", "White Knight", "White Bishop", "White Rook", "White Queen",
\r
106 "White Guard", "White Elephant", "White Arch Bishop", "White Chancellor",
\r
107 "White General", "White Man", "White Cannon", "White Night Rider",
\r
108 "White Crowned Bishop", "White Crowned Rook", "White Grass Hopper", "White Veteran",
\r
109 "White Falcon", "White Amazon", "White Snake", "White Unicorn",
\r
111 "Black Pawn", "Black Knight", "Black Bishop", "Black Rook", "Black Queen",
\r
112 "Black Guard", "Black Elephant", "Black Arch Bishop", "Black Chancellor",
\r
113 "Black General", "Black Man", "Black Cannon", "Black Night Rider",
\r
114 "Black Crowned Bishop", "Black Crowned Rook", "Black Grass Hopper", "Black Veteran",
\r
115 "Black Falcon", "Black Amazon", "Black Snake", "Black Unicorn",
\r
120 char *pieceTypeName[] = {
\r
121 "Pawn", "Knight", "Bishop", "Rook", "Queen",
\r
122 "Guard", "Elephant", "Arch Bishop", "Chancellor",
\r
123 "General", "Man", "Cannon", "Night Rider",
\r
124 "Crowned Bishop", "Crowned Rook", "Grass Hopper", "Veteran",
\r
125 "Falcon", "Amazon", "Snake", "Unicorn",
\r
127 "Pawn", "Knight", "Bishop", "Rook", "Queen",
\r
128 "Guard", "Elephant", "Arch Bishop", "Chancellor",
\r
129 "General", "Man", "Cannon", "Night Rider",
\r
130 "Crowned Bishop", "Crowned Rook", "Grass Hopper", "Veteran",
\r
131 "Falcon", "Amazon", "Snake", "Unicorn",
\r
139 if(isdigit(c)) return c - ONE;
\r
140 if(c >= 'a') return c - AAA;
\r
144 char* PieceToName(p, i)
\r
148 if(i) return pieceToName[(int) p];
\r
149 return pieceTypeName[(int) p];
\r
152 char* SquareToChar(x)
\r
155 return squareToChar[x - BOARD_LEFT];
\r
158 char* SquareToNum(y)
\r
161 return squareToNum[y + (gameInfo.boardHeight < 10)];
\r
165 // from winboard.c: all new routines
\r
166 #define JFWAPI __declspec(dllimport)
\r
167 JFWAPI BOOL WINAPI JFWSayString (LPCTSTR lpszStrinToSpeak, BOOL bInterrupt);
\r
169 typedef JFWAPI BOOL (WINAPI *PSAYSTRING)(LPCTSTR lpszStrinToSpeak, BOOL bInterrupt);
\r
171 PSAYSTRING RealSayString;
\r
173 VOID SayString(char *mess, BOOL flag)
\r
174 { // for debug file
\r
175 char buf[MSG_SIZ], *p;
\r
176 if(appData.debugMode) fprintf(debugFP, "SAY '%s'\n", mess);
\r
178 if(p = StrCaseStr(buf, "Xboard adjudication:")) {
\r
180 for(i=19; i>1; i--) p[i] = p[i-1];
\r
183 RealSayString(buf, flag);
\r
186 //static int fromX = 0, fromY = 0;
\r
187 static int oldFromX, oldFromY;
\r
188 static int timeflag;
\r
189 static int suppressClocks = 0;
\r
190 static int suppressOneKey = 0;
\r
191 static HANDLE hAccelJAWS;
\r
193 typedef struct { char *name; int code; } MenuItemDesc;
\r
195 MenuItemDesc menuItemJAWS[] = {
\r
196 {"Say Clock &Time\tAlt+T", IDM_SayClockTime },
\r
198 {"Say Last &Move\tAlt+M", IDM_SayMachineMove },
\r
199 {"Say W&ho's Turn\tAlt+X", IDM_SayWhosTurn },
\r
201 {"Say Complete &Position\tAlt+P",IDM_SayAllBoard },
\r
202 {"Say &White Pieces\tAlt+W", IDM_SayWhitePieces },
\r
203 {"Say &Black Pieces\tAlt+B", IDM_SayBlackPieces },
\r
204 {"Say Board &Rank\tAlt+R", IDM_ReadRow },
\r
205 {"Say Board &File\tAlt+F", IDM_ReadColumn },
\r
207 {"Say &Upper Diagonals\tAlt+U", IDM_SayUpperDiagnols },
\r
208 {"Say &Lower Diagonals\tAlt+L", IDM_SayLowerDiagnols },
\r
209 {"Say K&night Moves\tAlt+N", IDM_SayKnightMoves },
\r
210 {"Say Current &Square\tAlt+S", IDM_SayCurrentPos },
\r
211 {"Say &Attacks\tAlt+A", IDM_PossibleAttackMove },
\r
212 {"Say Attacke&d\tAlt+D", IDM_PossibleAttacked },
\r
216 ACCEL acceleratorsJAWS[] = {
\r
217 {FVIRTKEY|FALT, 'T', IDM_SayClockTime },
\r
218 {FVIRTKEY|FALT, 'M', IDM_SayMachineMove },
\r
219 {FVIRTKEY|FALT, 'X', IDM_SayWhosTurn },
\r
220 {FVIRTKEY|FALT, 'P', IDM_SayAllBoard },
\r
221 {FVIRTKEY|FALT, 'W', IDM_SayWhitePieces },
\r
222 {FVIRTKEY|FALT, 'B', IDM_SayBlackPieces },
\r
223 {FVIRTKEY|FALT, 'R', IDM_ReadRow },
\r
224 {FVIRTKEY|FALT, 'F', IDM_ReadColumn },
\r
225 {FVIRTKEY|FALT, 'U', IDM_SayUpperDiagnols },
\r
226 {FVIRTKEY|FALT, 'L', IDM_SayLowerDiagnols },
\r
227 {FVIRTKEY|FALT, 'N', IDM_SayKnightMoves },
\r
228 {FVIRTKEY|FALT, 'S', IDM_SayCurrentPos },
\r
229 {FVIRTKEY|FALT, 'A', IDM_PossibleAttackMove },
\r
230 {FVIRTKEY|FALT, 'D', IDM_PossibleAttacked }
\r
236 HMENU menuMain, menuJAWS;
\r
237 MENUBARINFO helpMenuInfo;
\r
240 helpMenuInfo.cbSize = sizeof(helpMenuInfo);
\r
241 menuMain = GetMenu(hwndMain);
\r
242 if(appData.debugMode) fprintf(debugFP, "hwndMain: %8x %8x\n", hwndMain, menuMain);
\r
243 menuJAWS = CreatePopupMenu();
\r
245 for(i=0; menuItemJAWS[i].name; i++) {
\r
246 if(menuItemJAWS[i].name[0] == '-')
\r
247 AppendMenu(menuJAWS, MF_SEPARATOR, (UINT_PTR) 0, NULL);
\r
248 else AppendMenu(menuJAWS, MF_ENABLED|MF_STRING,
\r
249 (UINT_PTR) menuItemJAWS[i].code, (LPCTSTR) menuItemJAWS[i].name);
\r
251 InsertMenu(menuMain, 5, MF_BYPOSITION|MF_POPUP|MF_ENABLED|MF_STRING,
\r
252 (UINT_PTR) menuJAWS, "&JAWS");
\r
253 oldMenuItemState[6] = oldMenuItemState[5];
\r
254 DrawMenuBar(hwndMain);
\r
259 { // to be called at beginning of WinMain, after InitApplication and InitInstance
\r
260 HINSTANCE hApi = LoadLibrary("jfwapi32.dll");
\r
262 DisplayInformation("Missing jfwapi32.dll");
\r
266 RealSayString = (PSAYSTRING)GetProcAddress(hApi, "JFWSayString");
\r
267 if(!RealSayString) {
\r
268 DisplayInformation("SayString returned a null pointer");
\r
273 // [HGM] kludge to reduce need for modification of winboard.c: make tinyLayout menu identical
\r
274 // to standard layout, so that code for switching between them does not have to be deleted
\r
278 menuBarText[0][5] = "&JAWS";
\r
279 for(i=0; i<7; i++) menuBarText[1][i] = menuBarText[0][i];
\r
282 hAccelJAWS = CreateAcceleratorTable(acceleratorsJAWS, 14);
\r
284 /* initialize cursor position */
\r
286 SetHighlights(fromX, fromY, -1, -1);
\r
287 DrawPosition(FALSE, NULL);
\r
288 oldFromX = oldFromY = -1;
\r
290 if(hwndConsole) SetFocus(hwndConsole);
\r
294 int beeps[] = { 1, 0, 0, 0, 0 };
\r
295 int beepCodes[] = { 0, MB_OK, MB_ICONERROR, MB_ICONQUESTION, MB_ICONEXCLAMATION, MB_ICONASTERISK };
\r
298 KeyboardEvent(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
300 ChessSquare currentPiece;
\r
301 char *piece, *xchar, *ynum ;
\r
302 int n, beepType = 1; // empty beep
\r
304 if(fromX == -1 || fromY == -1) {
\r
305 fromX = BOARD_LEFT; fromY = 0;
\r
309 if(fromX == BOARD_RGHT+1) fromX -= 2; else
\r
310 if(fromX == BOARD_LEFT) { if(fromY >= BOARD_HEIGHT - gameInfo.holdingsSize) fromX -= 2; else beepType = 0; } else
\r
311 if(fromX > BOARD_LEFT) fromX--; else beepType = 0; // off-board beep
\r
314 if(fromX == BOARD_LEFT-2) fromX += 2; else
\r
315 if(fromX == BOARD_RGHT-1) { if(fromY < gameInfo.holdingsSize) fromX += 2; else beepType = 0; } else
\r
316 if(fromX < BOARD_RGHT-1) fromX++; else beepType = 0;
\r
319 if(fromX == BOARD_RGHT+1) { if(fromY < gameInfo.holdingsSize - 1) fromY++; else beepType = 0; } else
\r
320 if(fromY < BOARD_HEIGHT-1) fromY++; else beepType = 0;
\r
323 if(fromX == BOARD_LEFT-2) { if(fromY > BOARD_HEIGHT - gameInfo.holdingsSize) fromY--; else beepType = 0; } else
\r
324 if(fromY > 0) fromY--; else beepType = 0;
\r
327 SetHighlights(fromX, fromY, -1, -1);
\r
328 DrawPosition(FALSE, NULL);
\r
329 currentPiece = boards[currentMove][fromY][fromX];
\r
330 piece = PieceToName(currentPiece,1);
\r
331 if(beepType == 1 && currentPiece != EmptySquare) beepType = currentPiece < (int) BlackPawn ? 2 : 3; // white or black beep
\r
332 if(beeps[beepType] == beeps[1] && (fromX == BOARD_RGHT+1 || fromX == BOARD_LEFT-2)) beepType = 4; // holdings beep
\r
333 beepType = beeps[beepType]%6;
\r
334 if(beepType) MessageBeep(beepCodes[beepType]);
\r
335 if(fromX == BOARD_LEFT - 2) {
\r
336 SayString("black holdings", FALSE);
\r
337 if(currentPiece != EmptySquare) {
\r
339 n = boards[currentMove][fromY][1];
\r
340 sprintf(buf, "%d %s%s", n, PieceToName(currentPiece,0), n == 1 ? "" : "s");
\r
341 SayString(buf, TRUE);
\r
344 if(fromX == BOARD_RGHT + 1) {
\r
345 SayString("white holdings", FALSE);
\r
346 if(currentPiece != EmptySquare) {
\r
348 n = boards[currentMove][fromY][BOARD_WIDTH-2];
\r
349 sprintf(buf, "%d %s%s", n, PieceToName(currentPiece,0), n == 1 ? "" : "s");
\r
350 SayString(buf, TRUE);
\r
353 if(fromX >= BOARD_LEFT && fromX < BOARD_RGHT) {
\r
355 xchar = SquareToChar(fromX);
\r
356 ynum = SquareToNum(fromY);
\r
357 if(currentPiece != EmptySquare) {
\r
358 // SayString(piece[0] == 'W' ? "white" : "black", TRUE);
\r
359 sprintf(buf, "%s %s %s", piece, xchar, ynum);
\r
360 } else sprintf(buf, "%s %s", xchar, ynum);
\r
361 SayString(buf, TRUE);
\r
366 extern char castlingRights[MAX_MOVES][BOARD_SIZE];
\r
367 int PosFlags(int nr);
\r
370 int rf, ff, rt, ft;
\r
375 extern void ReadCallback P((Board board, int flags, ChessMove kind,
\r
376 int rf, int ff, int rt, int ft,
\r
377 VOIDSTAR closure));
\r
379 void ReadCallback(board, flags, kind, rf, ff, rt, ft, closure)
\r
383 int rf, ff, rt, ft;
\r
386 register ReadClosure *cl = (ReadClosure *) closure;
\r
387 ChessSquare possiblepiece;
\r
388 char *piece, *xchar, *ynum ;
\r
390 //if(appData.debugMode) fprintf(debugFP, "%c%c%c%c\n", ff+AAA, rf+ONE, ft+AAA, rt+ONE);
\r
391 if(cl->ff == ff && cl->rf == rf) {
\r
392 possiblepiece = board[rt][ft];
\r
393 if(possiblepiece != EmptySquare) {
\r
394 piece = PieceToName(possiblepiece,1);
\r
395 xchar = SquareToChar(ft);
\r
396 ynum = SquareToNum(rt);
\r
397 SayString(xchar , FALSE);
\r
398 SayString(ynum, FALSE);
\r
399 SayString(piece, FALSE);
\r
403 if(cl->ft == ft && cl->rt == rt) {
\r
404 possiblepiece = board[rf][ff];
\r
405 piece = PieceToName(possiblepiece,1);
\r
406 xchar = SquareToChar(ff);
\r
407 ynum = SquareToNum(rf);
\r
408 SayString(xchar , FALSE);
\r
409 SayString(ynum, FALSE);
\r
410 SayString(piece, FALSE);
\r
416 PossibleAttackMove()
\r
419 ChessSquare piece, victim;
\r
420 int removedSelectedPiece = 0, swapColor;
\r
422 //if(appData.debugMode) fprintf(debugFP, "PossibleAttackMove %d %d %d %d\n", fromX, fromY, oldFromX, oldFromY);
\r
423 if(fromY < 0 || fromY >= BOARD_HEIGHT) return;
\r
424 if(fromX < BOARD_LEFT || fromX >= BOARD_RGHT) { SayString("holdings",FALSE); return; }
\r
426 piece = boards[currentMove][fromY][fromX];
\r
427 if(piece == EmptySquare) { // if square is empty, try to substitute selected piece
\r
428 if(oldFromX >= 0 && oldFromY >= 0) {
\r
429 piece = boards[currentMove][oldFromY][oldFromX];
\r
430 boards[currentMove][oldFromY][oldFromX] = EmptySquare;
\r
431 removedSelectedPiece = 1;
\r
432 SayString("Your", FALSE);
\r
433 SayString(PieceToName(piece, 0), FALSE);
\r
434 SayString("would have", FALSE);
\r
435 } else { SayString("You must select a piece first", FALSE); return; }
\r
438 victim = boards[currentMove][fromY][fromX];
\r
439 boards[currentMove][fromY][fromX] = piece; // make sure piece is actally there
\r
440 SayString("possible captures from here are", FALSE);
\r
442 swapColor = piece < (int)BlackPawn && !WhiteOnMove(currentMove) ||
\r
443 piece >= (int)BlackPawn && WhiteOnMove(currentMove);
\r
444 cl.count = 0; cl.rf = fromY; cl.ff = fromX; cl.rt = cl.ft = -1;
\r
445 GenLegal(boards[currentMove], PosFlags(currentMove + swapColor), EP_NONE,
\r
446 castlingRights[currentMove], ReadCallback, (VOIDSTAR) &cl);
\r
447 if(cl.count == 0) SayString("None", FALSE);
\r
448 boards[currentMove][fromY][fromX] = victim; // repair
\r
450 if( removedSelectedPiece ) boards[currentMove][oldFromY][oldFromX] = piece;
\r
458 ChessSquare piece = EmptySquare, victim;
\r
460 if(fromY < 0 || fromY >= BOARD_HEIGHT) return;
\r
461 if(fromX < BOARD_LEFT || fromX >= BOARD_RGHT) { SayString("holdings",FALSE); return; }
\r
463 if(oldFromX >= 0 && oldFromY >= 0) { // if piece is selected, remove it
\r
464 piece = boards[currentMove][oldFromY][oldFromX];
\r
465 boards[currentMove][oldFromY][oldFromX] = EmptySquare;
\r
468 SayString("Pieces that can capture you are", FALSE);
\r
470 victim = boards[currentMove][fromY][fromX]; // put dummy piece on target square, to activate Pawn captures
\r
471 boards[currentMove][fromY][fromX] = WhiteOnMove(currentMove) ? WhiteQueen : BlackQueen;
\r
472 cl.count = 0; cl.rt = fromY; cl.ft = fromX; cl.rf = cl.ff = -1;
\r
473 GenLegal(boards[currentMove], PosFlags(currentMove+1), EP_NONE,
\r
474 castlingRights[currentMove], ReadCallback, (VOIDSTAR) &cl);
\r
475 if(cl.count == 0) SayString("None", FALSE);
\r
477 SayString("You are defended by", FALSE);
\r
479 boards[currentMove][fromY][fromX] = WhiteOnMove(currentMove) ? BlackQueen : WhiteQueen;
\r
480 cl.count = 0; cl.rt = fromY; cl.ft = fromX; cl.rf = cl.ff = -1;
\r
481 GenLegal(boards[currentMove], PosFlags(currentMove), EP_NONE,
\r
482 castlingRights[currentMove], ReadCallback, (VOIDSTAR) &cl);
\r
483 if(cl.count == 0) SayString("None", FALSE);
\r
484 boards[currentMove][fromY][fromX] = victim; // put back original occupant
\r
486 if(oldFromX >= 0 && oldFromY >= 0) { // put back possibl selected piece
\r
487 boards[currentMove][oldFromY][oldFromX] = piece;
\r
494 ChessSquare currentpiece;
\r
495 char *piece, *xchar, *ynum ;
\r
497 ynum = SquareToNum(fromY);
\r
499 if(fromY < 0) return;
\r
501 for (xPos=BOARD_LEFT; xPos<BOARD_RGHT; xPos++) {
\r
502 currentpiece = boards[currentMove][fromY][xPos];
\r
503 if(currentpiece != EmptySquare) {
\r
504 piece = PieceToName(currentpiece,1);
\r
505 xchar = SquareToChar(xPos);
\r
506 SayString(xchar , FALSE);
\r
507 SayString(ynum, FALSE);
\r
508 SayString(piece, FALSE);
\r
513 SayString("rank", FALSE);
\r
514 SayString(ynum, FALSE);
\r
515 SayString("empty", FALSE);
\r
522 ChessSquare currentpiece;
\r
523 char *piece, *xchar, *ynum ;
\r
525 xchar = SquareToChar(fromX);
\r
527 if(fromX < 0) return;
\r
529 for (yPos=0; yPos<BOARD_HEIGHT; yPos++) {
\r
530 currentpiece = boards[currentMove][yPos][fromX];
\r
531 if(currentpiece != EmptySquare) {
\r
532 piece = PieceToName(currentpiece,1);
\r
533 ynum = SquareToNum(yPos);
\r
534 SayString(xchar , FALSE);
\r
535 SayString(ynum, FALSE);
\r
536 SayString(piece, FALSE);
\r
541 SayString(xchar, FALSE);
\r
542 SayString("file empty", FALSE);
\r
549 ChessSquare currentpiece;
\r
550 char *piece, *xchar, *ynum ;
\r
553 if(fromX < 0 || fromY < 0) return;
\r
555 if(fromX < BOARD_RGHT-1 && fromY < BOARD_HEIGHT-1) {
\r
556 SayString("The diagnol squares to your upper right contain", FALSE);
\r
559 while(yPos<BOARD_HEIGHT && xPos<BOARD_RGHT) {
\r
560 currentpiece = boards[currentMove][yPos][xPos];
\r
561 piece = PieceToName(currentpiece,1);
\r
562 xchar = SquareToChar(xPos);
\r
563 ynum = SquareToNum(yPos);
\r
564 SayString(xchar , FALSE);
\r
565 SayString(ynum, FALSE);
\r
566 SayString(piece, FALSE);
\r
571 else SayString("There is no squares to your upper right", FALSE);
\r
573 if(fromX > BOARD_LEFT && fromY < BOARD_HEIGHT-1) {
\r
574 SayString("The diagnol squares to your upper left contain", FALSE);
\r
577 while(yPos<BOARD_HEIGHT && xPos>=BOARD_LEFT) {
\r
578 currentpiece = boards[currentMove][yPos][xPos];
\r
579 piece = PieceToName(currentpiece,1);
\r
580 xchar = SquareToChar(xPos);
\r
581 ynum = SquareToNum(yPos);
\r
582 SayString(xchar , FALSE);
\r
583 SayString(ynum, FALSE);
\r
584 SayString(piece, FALSE);
\r
589 else SayString("There is no squares to your upper left", FALSE);
\r
595 ChessSquare currentpiece;
\r
596 char *piece, *xchar, *ynum ;
\r
599 if(fromX < 0 || fromY < 0) return;
\r
601 if(fromX < BOARD_RGHT-1 && fromY > 0) {
\r
602 SayString("The diagnol squares to your lower right contain", FALSE);
\r
605 while(yPos>=0 && xPos<BOARD_RGHT) {
\r
606 currentpiece = boards[currentMove][yPos][xPos];
\r
607 piece = PieceToName(currentpiece,1);
\r
608 xchar = SquareToChar(xPos);
\r
609 ynum = SquareToNum(yPos);
\r
610 SayString(xchar , FALSE);
\r
611 SayString(ynum, FALSE);
\r
612 SayString(piece, FALSE);
\r
617 else SayString("There is no squares to your lower right", FALSE);
\r
619 if(fromX > BOARD_LEFT && fromY > 0) {
\r
620 SayString("The diagnol squares to your lower left contain", FALSE);
\r
623 while(yPos>=0 && xPos>=BOARD_LEFT) {
\r
624 currentpiece = boards[currentMove][yPos][xPos];
\r
625 piece = PieceToName(currentpiece,1);
\r
626 xchar = SquareToChar(xPos);
\r
627 ynum = SquareToNum(yPos);
\r
628 SayString(xchar , FALSE);
\r
629 SayString(ynum, FALSE);
\r
630 SayString(piece, FALSE);
\r
635 else SayString("There is no squares to your lower left", FALSE);
\r
641 ChessSquare currentpiece, oldpiece;
\r
642 char *piece, *xchar, *ynum ;
\r
644 oldpiece = boards[currentMove][fromY][fromX];
\r
645 if(oldpiece == WhiteKnight || oldpiece == BlackKnight)
\r
646 SayString("The possible squares a Knight could move to are", FALSE);
\r
648 SayString("The squares a Knight could possibly attack from are", FALSE);
\r
650 if (fromY+2 < BOARD_HEIGHT && fromX-1 >= BOARD_LEFT) {
\r
651 currentpiece = boards[currentMove][fromY+2][fromX-1];
\r
652 if(((oldpiece == WhiteKnight) && (currentpiece > WhiteKing))
\r
653 || ((oldpiece == BlackKnight) && (currentpiece < BlackPawn || currentpiece == EmptySquare))
\r
654 || (oldpiece == EmptySquare) && (currentpiece == WhiteKnight || currentpiece == BlackKnight))
\r
656 piece = PieceToName(currentpiece,1);
\r
657 xchar = SquareToChar(fromX-1);
\r
658 ynum = SquareToNum(fromY+2);
\r
659 SayString(xchar , FALSE);
\r
660 SayString(ynum, FALSE);
\r
661 SayString(piece, FALSE);
\r
665 if (fromY+2 < BOARD_HEIGHT && fromX+1 < BOARD_RGHT) {
\r
666 currentpiece = boards[currentMove][fromY+2][fromX+1];
\r
667 if(((oldpiece == WhiteKnight) && (currentpiece > WhiteKing))
\r
668 || ((oldpiece == BlackKnight) && (currentpiece < BlackPawn || currentpiece == EmptySquare))
\r
669 || (oldpiece == EmptySquare) && (currentpiece == WhiteKnight || currentpiece == BlackKnight))
\r
671 piece = PieceToName(currentpiece,1);
\r
672 xchar = SquareToChar(fromX+1);
\r
673 ynum = SquareToNum(fromY+2);
\r
674 SayString(xchar , FALSE);
\r
675 SayString(ynum, FALSE);
\r
676 SayString(piece, FALSE);
\r
680 if (fromY+1 < BOARD_HEIGHT && fromX+2 < BOARD_RGHT) {
\r
681 currentpiece = boards[currentMove][fromY+1][fromX+2];
\r
682 if(((oldpiece == WhiteKnight) && (currentpiece > WhiteKing))
\r
683 || ((oldpiece == BlackKnight) && (currentpiece < BlackPawn || currentpiece == EmptySquare))
\r
684 || (oldpiece == EmptySquare) && (currentpiece == WhiteKnight || currentpiece == BlackKnight))
\r
686 piece = PieceToName(currentpiece,1);
\r
687 xchar = SquareToChar(fromX+2);
\r
688 ynum = SquareToNum(fromY+1);
\r
689 SayString(xchar , FALSE);
\r
690 SayString(ynum, FALSE);
\r
691 SayString(piece, FALSE);
\r
695 if (fromY-1 >= 0 && fromX+2 < BOARD_RGHT) {
\r
696 currentpiece = boards[currentMove][fromY-1][fromX+2];
\r
697 if(((oldpiece == WhiteKnight) && (currentpiece > WhiteKing))
\r
698 || ((oldpiece == BlackKnight) && (currentpiece < BlackPawn || currentpiece == EmptySquare))
\r
699 || (oldpiece == EmptySquare) && (currentpiece == WhiteKnight || currentpiece == BlackKnight))
\r
701 piece = PieceToName(currentpiece,1);
\r
702 xchar = SquareToChar(fromX+2);
\r
703 ynum = SquareToNum(fromY-1);
\r
704 SayString(xchar , FALSE);
\r
705 SayString(ynum, FALSE);
\r
706 SayString(piece, FALSE);
\r
710 if (fromY-2 >= 0 && fromX+1 < BOARD_RGHT) {
\r
711 currentpiece = boards[currentMove][fromY-2][fromX+1];
\r
712 if(((oldpiece == WhiteKnight) && (currentpiece > WhiteKing))
\r
713 || ((oldpiece == BlackKnight) && (currentpiece < BlackPawn || currentpiece == EmptySquare))
\r
714 || (oldpiece == EmptySquare) && (currentpiece == WhiteKnight || currentpiece == BlackKnight))
\r
716 piece = PieceToName(currentpiece,1);
\r
717 xchar = SquareToChar(fromX+1);
\r
718 ynum = SquareToNum(fromY-2);
\r
719 SayString(xchar , FALSE);
\r
720 SayString(ynum, FALSE);
\r
721 SayString(piece, FALSE);
\r
725 if (fromY-2 >= 0 && fromX-1 >= BOARD_LEFT) {
\r
726 currentpiece = boards[currentMove][fromY-2][fromX-1];
\r
727 if(((oldpiece == WhiteKnight) && (currentpiece > WhiteKing))
\r
728 || ((oldpiece == BlackKnight) && (currentpiece < BlackPawn || currentpiece == EmptySquare))
\r
729 || (oldpiece == EmptySquare) && (currentpiece == WhiteKnight || currentpiece == BlackKnight))
\r
731 piece = PieceToName(currentpiece,1);
\r
732 xchar = SquareToChar(fromX-1);
\r
733 ynum = SquareToNum(fromY-2);
\r
734 SayString(xchar , FALSE);
\r
735 SayString(ynum, FALSE);
\r
736 SayString(piece, FALSE);
\r
740 if (fromY-1 >= 0 && fromX-2 >= BOARD_LEFT) {
\r
741 currentpiece = boards[currentMove][fromY-1][fromX-2];
\r
742 if(((oldpiece == WhiteKnight) && (currentpiece > WhiteKing))
\r
743 || ((oldpiece == BlackKnight) && (currentpiece < BlackPawn || currentpiece == EmptySquare))
\r
744 || (oldpiece == EmptySquare) && (currentpiece == WhiteKnight || currentpiece == BlackKnight))
\r
746 piece = PieceToName(currentpiece,1);
\r
747 xchar = SquareToChar(fromX-2);
\r
748 ynum = SquareToNum(fromY-1);
\r
749 SayString(xchar , FALSE);
\r
750 SayString(ynum, FALSE);
\r
751 SayString(piece, FALSE);
\r
755 if (fromY+1 < BOARD_HEIGHT && fromX-2 >= BOARD_LEFT) {
\r
756 currentpiece = boards[currentMove][fromY+1][fromX-2];
\r
757 if(((oldpiece == WhiteKnight) && (currentpiece > WhiteKing))
\r
758 || ((oldpiece == BlackKnight) && (currentpiece < BlackPawn || currentpiece == EmptySquare))
\r
759 || (oldpiece == EmptySquare) && (currentpiece == WhiteKnight || currentpiece == BlackKnight))
\r
761 piece = PieceToName(currentpiece,1);
\r
762 xchar = SquareToChar(fromX-2);
\r
763 ynum = SquareToNum(fromY+1);
\r
764 SayString(xchar , FALSE);
\r
765 SayString(ynum, FALSE);
\r
766 SayString(piece, FALSE);
\r
772 SayPieces(ChessSquare p)
\r
774 ChessSquare currentpiece;
\r
775 char *piece, *xchar, *ynum ;
\r
776 int yPos, xPos, count = 0;
\r
779 if(p == WhitePlay) SayString("White pieces", FALSE); else
\r
780 if(p == BlackPlay) SayString("Black pieces", FALSE); else
\r
781 if(p == EmptySquare) SayString("Pieces", FALSE); else {
\r
782 sprintf(buf, "%ss", PieceToName(p,1));
\r
783 SayString(buf, FALSE);
\r
785 SayString("are located", FALSE);
\r
786 for(yPos=0; yPos<BOARD_HEIGHT; yPos++) {
\r
787 for(xPos=BOARD_LEFT; xPos<BOARD_RGHT; xPos++) {
\r
788 currentpiece = boards[currentMove][yPos][xPos];
\r
789 if(p == BlackPlay && currentpiece >= BlackPawn && currentpiece <= BlackKing ||
\r
790 p == WhitePlay && currentpiece >= WhitePawn && currentpiece <= WhiteKing )
\r
791 piece = PieceToName(currentpiece,0);
\r
792 else if(p == EmptySquare && currentpiece != EmptySquare)
\r
793 piece = PieceToName(currentpiece,1);
\r
794 else if(p == currentpiece)
\r
798 if(count == 0) SayString("at", FALSE);
\r
799 xchar = SquareToChar(xPos);
\r
800 ynum = SquareToNum(yPos);
\r
801 SayString(xchar , FALSE);
\r
802 SayString(ynum, FALSE);
\r
803 if(piece) SayString(piece, FALSE);
\r
807 if(count == 0) SayString("nowhere", FALSE);
\r
813 ChessSquare currentpiece;
\r
814 char *piece, *xchar, *ynum ;
\r
815 if(fromX < BOARD_LEFT) { SayString("You strayed into the white holdings", FALSE); return; }
\r
816 if(fromX >= BOARD_RGHT) { SayString("You strayed into the black holdings", FALSE); return; }
\r
817 currentpiece = boards[currentMove][fromY][fromX];
\r
818 piece = PieceToName(currentpiece,1);
\r
819 ynum = SquareToNum(fromY);
\r
820 xchar = SquareToChar(fromX);
\r
821 SayString("Your current position is", FALSE);
\r
822 SayString(xchar, FALSE);
\r
823 SayString(ynum, FALSE);
\r
824 SayString(piece, FALSE);
\r
825 if(((fromX-BOARD_LEFT) ^ fromY)&1)
\r
826 SayString("on a light square",FALSE);
\r
828 SayString("on a dark square",FALSE);
\r
830 PossibleAttacked();
\r
838 ChessSquare currentpiece;
\r
839 char *piece, *ynum ;
\r
841 if(gameInfo.holdingsWidth) {
\r
843 for(Ypos=0; Ypos<gameInfo.holdingsSize; Ypos++) {
\r
844 int n = boards[currentMove][Ypos][BOARD_WIDTH-2];
\r
845 if(n) { char buf[MSG_SIZ];
\r
846 if(!first++) SayString("white holds", FALSE);
\r
847 currentpiece = boards[currentMove][Ypos][BOARD_WIDTH-1];
\r
848 piece = PieceToName(currentpiece,0);
\r
849 sprintf(buf, "%d %s%s", n, piece, (n==1 ? "" : "s") );
\r
850 SayString(buf, FALSE);
\r
854 for(Ypos=BOARD_HEIGHT-1; Ypos>=BOARD_HEIGHT - gameInfo.holdingsSize; Ypos--) {
\r
855 int n = boards[currentMove][Ypos][1];
\r
856 if(n) { char buf[MSG_SIZ];
\r
857 if(!first++) SayString("black holds", FALSE);
\r
858 currentpiece = boards[currentMove][Ypos][0];
\r
859 piece = PieceToName(currentpiece,0);
\r
860 sprintf(buf, "%d %s%s", n, piece, (n==1 ? "" : "s") );
\r
861 SayString(buf, FALSE);
\r
866 for(Ypos=BOARD_HEIGHT-1; Ypos>=0; Ypos--) {
\r
867 ynum = ordinals[Ypos + (gameInfo.boardHeight < 10)];
\r
868 SayString(ynum, FALSE);
\r
869 SayString("rank", FALSE);
\r
870 for(Xpos=BOARD_LEFT; Xpos<BOARD_RGHT; Xpos++) {
\r
871 currentpiece = boards[currentMove][Ypos][Xpos];
\r
872 if(currentpiece != EmptySquare) {
\r
875 piece = PieceToName(currentpiece,1);
\r
876 while(Xpos < BOARD_RGHT && boards[currentMove][Ypos][Xpos] == currentpiece)
\r
879 sprintf(buf, "%d %ss", count, piece);
\r
880 } else sprintf(buf, "%s", piece);
\r
882 SayString(buf, FALSE);
\r
884 int count = 0, oldX = Xpos;
\r
885 while(Xpos < BOARD_RGHT && boards[currentMove][Ypos][Xpos] == EmptySquare)
\r
887 if(Xpos == BOARD_RGHT && oldX == BOARD_LEFT)
\r
888 SayString("all", FALSE);
\r
892 sprintf(buf, "%d", count);
\r
893 SayString(buf, FALSE);
\r
897 SayString("empty", FALSE);
\r
907 if(gameMode == MachinePlaysBlack || gameMode == IcsPlayingBlack) {
\r
908 if(WhiteOnMove(currentMove))
\r
909 SayString("It is your turn", FALSE);
\r
910 else SayString("It is your opponents turn", FALSE);
\r
911 } else if(gameMode == MachinePlaysWhite || gameMode == IcsPlayingWhite) {
\r
912 if(WhiteOnMove(currentMove))
\r
913 SayString("It is your opponents turn", FALSE);
\r
914 else SayString("It is your turn", FALSE);
\r
916 if(WhiteOnMove(currentMove))
\r
917 SayString("White is on move here", FALSE);
\r
918 else SayString("Black is on move here", FALSE);
\r
924 SayMachineMove(int evenIfDuplicate)
\r
926 int len, xPos, yPos, moveNr, secondSpace = 0, castle = 0, n;
\r
927 ChessSquare currentpiece;
\r
928 char *piece, *xchar, *ynum, *p;
\r
929 char c, buf[MSG_SIZ], comment[MSG_SIZ];
\r
930 static char disambiguation[2];
\r
931 static int previousMove = 0;
\r
933 if(appData.debugMode) fprintf(debugFP, "Message = '%s'\n", messageText);
\r
934 if(gameMode == BeginningOfGame) return;
\r
935 if(messageText[0] == '[') return;
\r
937 if(isdigit(messageText[0])) { // message is move, possibly with thinking output
\r
938 int dotCount = 0, spaceCount = 0;
\r
939 sscanf(messageText, "%d", &moveNr);
\r
941 // [HGM] show: better extraction of move
\r
942 while (messageText[len] != NULLCHAR) {
\r
943 if(messageText[len] == '.' && spaceCount == 0) dotCount++;
\r
944 if(messageText[len] == ' ') { if(++spaceCount == 2) secondSpace = len; }
\r
945 if(messageText[len] == '{') { // we detected a comment
\r
946 if(isalpha(messageText[len+1]) ) sscanf(messageText+len, "{%[^}]}", comment);
\r
949 if(messageText[len] == '[') { // we detected thinking output
\r
950 int depth; float score=0; char c, lastMover = (dotCount == 3 ? 'B' : 'W');
\r
951 if(sscanf(messageText+len+1, "%d]%c%f", &depth, &c, &score) > 1) {
\r
952 if(c == ' ') { // if not explicitly specified, figure out source of thinking output
\r
954 case MachinePlaysWhite:
\r
955 case IcsPlayingWhite:
\r
957 case IcsPlayingBlack:
\r
958 case MachinePlaysBlack:
\r
964 if(c != lastMover) return; // line is thinking output of future move, ignore.
\r
965 if(2*moveNr - (dotCount < 2) == previousMove)
\r
966 return; // do not repeat same move; likely ponder output
\r
967 sprintf(buf, "score %s %d at %d ply",
\r
968 score > 0 ? "plus" : score < 0 ? "minus" : "",
\r
969 (int) (fabs(score)*100+0.5),
\r
971 SayString(buf, FALSE); // move + thinking output describing it; say it.
\r
973 while(messageText[len-1] == ' ') len--; // position just behind move;
\r
976 if(messageText[len] == '(') { // ICS time printed behind move
\r
977 while(messageText[len+1] && messageText[len] != ')') len++; // skip it
\r
981 if(secondSpace) len = secondSpace; // position behind move
\r
982 if(messageText[len-1] == '+' || messageText[len-1] == '#') { /* you are in checkmate */
\r
983 len--; // strip off check or mate indicator
\r
985 if(messageText[len-2] == '=') { /* promotion */
\r
986 len-=2; // strip off promotion piece
\r
987 SayString("promotion", FALSE);
\r
990 n = 2*moveNr - (dotCount < 2);
\r
992 if(previousMove != 2*moveNr + (dotCount > 1) || evenIfDuplicate) {
\r
994 previousMove = 2*moveNr + (dotCount > 1); // remember move nr of move last spoken
\r
995 sprintf(number, "%d", moveNr);
\r
997 yPos = CoordToNum(messageText[len-1]); /* turn char coords to ints */
\r
998 xPos = CoordToNum(messageText[len-2]);
\r
999 if(xPos < 0 || xPos > 11) return; // prevent crashes if no coord string available to speak
\r
1000 if(yPos < 0 || yPos > 9) return;
\r
1001 currentpiece = boards[n][yPos][xPos];
\r
1002 piece = PieceToName(currentpiece,0);
\r
1003 ynum = SquareToNum(yPos);
\r
1004 xchar = SquareToChar(xPos);
\r
1005 c = messageText[len-3];
\r
1006 if(c == 'x') c = messageText[len-4];
\r
1007 if(!isdigit(c) && c < 'a' && c != '@') c = 0;
\r
1008 disambiguation[0] = c;
\r
1009 SayString(WhiteOnMove(n) ? "Black" : "White", FALSE);
\r
1010 SayString("move", FALSE);
\r
1011 SayString(number, FALSE);
\r
1012 // if(c==0 || c=='@') SayString("a", FALSE);
\r
1013 // intercept castling moves
\r
1014 p = StrStr(messageText, "O-O-O");
\r
1015 if(p && p-messageText < len) {
\r
1016 SayString("queen side castling",FALSE);
\r
1019 p = StrStr(messageText, "O-O");
\r
1020 if(p && p-messageText < len) {
\r
1021 SayString("king side castling",FALSE);
\r
1026 SayString(piece, FALSE);
\r
1027 if(c == '@') SayString("dropped on", FALSE); else
\r
1028 if(c) SayString(disambiguation, FALSE);
\r
1029 SayString("to", FALSE);
\r
1030 SayString(xchar, FALSE);
\r
1031 SayString(ynum, FALSE);
\r
1032 if(messageText[len-3] == 'x') {
\r
1033 currentpiece = boards[n-1][yPos][xPos];
\r
1034 if(currentpiece != EmptySquare) {
\r
1035 piece = PieceToName(currentpiece,0);
\r
1036 SayString("Capturing a",FALSE);
\r
1037 SayString(piece, FALSE);
\r
1038 } else SayString("Capturing onn passann",FALSE);
\r
1040 if(messageText[len] == '+') SayString("check", FALSE); else
\r
1041 if(messageText[len] == '#') {
\r
1042 SayString("finishing off", FALSE);
\r
1043 SayString(WhiteOnMove(n) ? "White" : "Black", FALSE);
\r
1048 /* say comment after move, possibly with result */
\r
1050 if(StrStr(messageText, " 1-0")) p = "white wins"; else
\r
1051 if(StrStr(messageText, " 0-1")) p = "black wins"; else
\r
1052 if(StrStr(messageText, " 1/2-1/2")) p = "game ends in a draw";
\r
1055 if(!StrCaseStr(comment, "draw") &&
\r
1056 !StrCaseStr(comment, "white") &&
\r
1057 !StrCaseStr(comment, "black") ) {
\r
1058 SayString(p, FALSE);
\r
1059 SayString("due to", FALSE);
\r
1062 SayString(comment, FALSE); // alphabetic comment (usually game end)
\r
1063 } else if(p) SayString(p, FALSE);
\r
1066 /* starts not with digit */
\r
1067 if(StrCaseStr(messageText, "illegal")) PlayIcsUnfinishedSound();
\r
1068 SayString(messageText, FALSE);
\r
1076 char buf1[50], buf2[50];
\r
1077 char *str1, *str2;
\r
1078 static long int lastWhiteTime, lastBlackTime;
\r
1080 suppressClocks = 1; // if user is using alt+T command, no reason to display them
\r
1081 if(abs(lastWhiteTime - whiteTimeRemaining) < 1000 && abs(lastBlackTime - blackTimeRemaining) < 1000)
\r
1082 suppressClocks = 0; // back on after two requests in rapid succession
\r
1083 sprintf(buf1, "%s", TimeString(whiteTimeRemaining));
\r
1085 SayString("White's remaining time is", FALSE);
\r
1086 SayString(str1, FALSE);
\r
1087 sprintf(buf2, "%s", TimeString(blackTimeRemaining));
\r
1089 SayString("Black's remaining time is", FALSE);
\r
1090 SayString(str2, FALSE);
\r
1091 lastWhiteTime = whiteTimeRemaining;
\r
1092 lastBlackTime = blackTimeRemaining;
\r
1096 Toggle(Boolean *b, char *mess)
\r
1099 SayString(mess, FALSE);
\r
1100 SayString("is now", FALSE);
\r
1101 SayString(*b ? "on" : "off", FALSE);
\r
1104 /* handles keyboard moves in a click-click fashion */
\r
1106 KeyboardMove(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
1108 ChessSquare currentpiece;
\r
1111 static BOOLEAN sameAgain = FALSE;
\r
1112 switch (message) {
\r
1114 sameAgain = FALSE;
\r
1115 if(oldFromX == fromX && oldFromY == fromY) {
\r
1117 /* click on same square */
\r
1120 else if(oldFromX != -1) {
\r
1122 ChessSquare pdown, pup;
\r
1123 pdown = boards[currentMove][oldFromY][oldFromX];
\r
1124 pup = boards[currentMove][fromY][fromX];
\r
1126 if (gameMode == EditPosition ||
\r
1127 !((WhitePawn <= pdown && pdown <= WhiteKing &&
\r
1128 WhitePawn <= pup && pup <= WhiteKing) ||
\r
1129 (BlackPawn <= pdown && pdown <= BlackKing &&
\r
1130 BlackPawn <= pup && pup <= BlackKing))) {
\r
1131 /* EditPosition, empty square, or different color piece;
\r
1132 click-click move is possible */
\r
1134 if (IsPromotion(oldFromX, oldFromY, fromX, fromY)) {
\r
1135 if (appData.alwaysPromoteToQueen) {
\r
1136 UserMoveEvent(oldFromX, oldFromY, fromX, fromY, 'q');
\r
1139 toX = fromX; toY = fromY; fromX = oldFromX; fromY = oldFromY;
\r
1140 PromotionPopup(hwnd);
\r
1141 fromX = toX; fromY = toY;
\r
1145 UserMoveEvent(oldFromX, oldFromY, fromX, fromY, NULLCHAR);
\r
1147 oldFromX = oldFromY = -1;
\r
1152 /* First downclick, or restart on a square with same color piece */
\r
1153 if (OKToStartUserMove(fromX, fromY)) {
\r
1156 currentpiece = boards[currentMove][fromY][fromX];
\r
1157 piece = PieceToName(currentpiece,1);
\r
1158 SayString(piece, FALSE);
\r
1159 SayString("selected", FALSE);
\r
1162 oldFromX = oldFromY = -1;
\r
1167 if (oldFromX == fromX && oldFromY == fromY) {
\r
1168 /* Upclick on same square */
\r
1170 /* Clicked same square twice: abort click-click move */
\r
1171 oldFromX = oldFromY = -1;
\r
1172 currentpiece = boards[currentMove][fromY][fromX];
\r
1173 piece = PieceToName(currentpiece,0);
\r
1174 SayString(piece, FALSE);
\r
1175 SayString("unselected", FALSE);
\r
1183 { // return TRUE for times we want to announce
\r
1185 x = (x+50)/100; // tenth of seconds
\r
1186 if(x <= 100) return (x%10 == 0);
\r
1187 if(x <= 600) return (x%100 == 0);
\r
1188 if(x <= 6000) return (x%600 == 0);
\r
1189 return (x%3000 == 0);
\r
1192 #define JAWS_ARGS \
\r
1193 { "beepOffBoard", ArgInt, (LPVOID) beeps, TRUE },\
\r
1194 { "beepEmpty", ArgInt, (LPVOID) (beeps+1), TRUE },\
\r
1195 { "beepWhite", ArgInt, (LPVOID) (beeps+2), TRUE },\
\r
1196 { "beepBlack", ArgInt, (LPVOID) (beeps+3), TRUE },\
\r
1197 { "beepHoldings", ArgInt, (LPVOID) (beeps+4), TRUE },\
\r
1199 #define JAWS_ALT_INTERCEPT \
\r
1200 if(suppressOneKey) {\
\r
1201 suppressOneKey = 0;\
\r
1202 if(GetKeyState(VK_MENU) < 0 && GetKeyState(VK_CONTROL) < 0) break;\
\r
1204 if ((char)wParam == 022 && gameMode == EditPosition) { /* <Ctl R>. Pop up piece menu */\
\r
1205 POINT pt; int x, y;\
\r
1206 SquareToPos(fromY, fromX, &x, &y);\
\r
1207 pt.x = x; pt.y = y;\
\r
1208 if(gameInfo.variant != VariantShogi)\
\r
1209 MenuPopup(hwnd, pt, LoadMenu(hInst, "PieceMenu"), -1);\
\r
1211 MenuPopup(hwnd, pt, LoadMenu(hInst, "ShogiPieceMenu"), -1);\
\r
1215 #define JAWS_REPLAY \
\r
1216 case '\020': /* ctrl P */\
\r
1217 { char buf[MSG_SIZ];\
\r
1218 if(GetWindowText(hwnd, buf, MSG_SIZ-1))\
\r
1219 SayString(buf, FALSE);\
\r
1223 #define JAWS_KB_NAVIGATION \
\r
1227 if(GetKeyState(VK_MENU) < 0 && GetKeyState(VK_CONTROL) < 0) {\
\r
1228 /* Control + Alt + letter used for speaking piece positions */\
\r
1229 static int lastTime; static char lastChar;\
\r
1230 int mine = 0, time = GetTickCount(); char c;\
\r
1232 if((char)wParam == lastChar && time-lastTime < 250) mine = 1;\
\r
1233 lastChar = wParam; lastTime = time;\
\r
1236 if(gameMode == IcsPlayingWhite || gameMode == MachinePlaysBlack) mine = !mine;\
\r
1238 if(ToLower(c) == 'x') {\
\r
1239 SayPieces(mine ? WhitePlay : BlackPlay);\
\r
1240 suppressOneKey = 1;\
\r
1243 if(CharToPiece(c) != EmptySquare) {\
\r
1244 SayPieces(CharToPiece(mine ? ToUpper(c) : ToLower(c)));\
\r
1245 suppressOneKey = 1;\
\r
1250 switch (wParam) {\
\r
1255 KeyboardEvent(hwnd, message, wParam, lParam);\
\r
1258 KeyboardMove(hwnd, message, wParam, lParam);\
\r
1263 switch (wParam) {\
\r
1265 KeyboardMove(hwnd, message, wParam, lParam);\
\r
1270 #define JAWS_MENU_ITEMS \
\r
1271 case IDM_PossibleAttackMove: /*What can I possible attack from here */\
\r
1272 PossibleAttackMove();\
\r
1275 case IDM_PossibleAttacked: /*what can possible attack this square*/\
\r
1276 PossibleAttacked();\
\r
1279 case IDM_ReadRow: /* Read the current row of pieces */\
\r
1283 case IDM_ReadColumn: /* Read the current column of pieces */\
\r
1287 case IDM_SayCurrentPos: /* Say current position including color */\
\r
1291 case IDM_SayAllBoard: /* Say the whole board from bottom to top */\
\r
1295 case IDM_SayMachineMove: /* Say the last move made */\
\r
1297 SayMachineMove(1);\
\r
1300 case IDM_SayUpperDiagnols: /* Says the diagnol positions above you */\
\r
1301 SayUpperDiagnols();\
\r
1304 case IDM_SayLowerDiagnols: /* Say the diagnol positions below you */\
\r
1305 SayLowerDiagnols();\
\r
1308 case IDM_SayBlackPieces: /*Say the opponents pieces */\
\r
1309 SayPieces(BlackPlay);\
\r
1312 case IDM_SayWhitePieces: /*Say the opponents pieces */\
\r
1313 SayPieces(WhitePlay);\
\r
1316 case IDM_SayClockTime: /*Say the clock time */\
\r
1320 case IDM_SayWhosTurn: /* Say whos turn it its */\
\r
1324 case IDM_SayKnightMoves: /* Say Knights (L-shaped) move */\
\r
1325 SayKnightMoves();\
\r
1328 case OPT_PonderNextMove: /* Toggle option setting */\
\r
1329 Toggle(&appData.ponderNextMove, "ponder");\
\r
1332 case OPT_AnimateMoving: /* Toggle option setting */\
\r
1333 Toggle(&appData.animate, "animate moving");\
\r
1336 case OPT_AutoFlag: /* Toggle option setting */\
\r
1337 Toggle(&appData.autoCallFlag, "auto flag");\
\r
1340 case OPT_AlwaysQueen: /* Toggle option setting */\
\r
1341 Toggle(&appData.alwaysPromoteToQueen, "always promote to queen");\
\r
1344 case OPT_TestLegality: /* Toggle option setting */\
\r
1345 Toggle(&appData.testLegality, "legality testing");\
\r
1348 case OPT_HideThinkFromHuman: /* Toggle option setting */\
\r
1349 Toggle(&appData.hideThinkingFromHuman, "hide thinking");\
\r
1350 ShowThinkingEvent();\
\r
1353 case OPT_SaveExtPGN: /* Toggle option setting */\
\r
1354 Toggle(&appData.saveExtendedInfoInPGN, "extended P G N info");\
\r
1357 case OPT_ExtraInfoInMoveHistory: /* Toggle option setting */\
\r
1358 Toggle(&appData.showEvalInMoveHistory, "extra info in move histoty");\
\r
1363 #define JAWS_ACCEL \
\r
1364 !(!frozen && TranslateAccelerator(hwndMain, hAccelJAWS, &msg)) &&
\r
1366 #define JAWS_INIT if (!InitJAWS()) return (FALSE);
\r
1368 #define JAWS_DELETE(X)
\r
1370 #define JAWS_SILENCE if(suppressClocks) return;
\r
1372 #define JAWS_COPYRIGHT \
\r
1373 SetDlgItemText(hDlg, OPT_MESS, "Auditory/Keyboard Enhancements By: Ed Rodriguez (sort of)");
\r
1375 #define SAY(S) SayString((S), FALSE)
\r
1377 #define SAYMACHINEMOVE() SayMachineMove(0)
\r
1379 // After inclusion of this file somewhere early in winboard.c, the remaining part of the patch
\r
1380 // is scattered over winboard.c for actually calling the routines.
\r