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, 2010, 2011 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
86 // from moves.c, added WinBoard_F piece types and ranks / files
\r
88 char *squareToChar[] = { "ay", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l" };
\r
90 char *squareToNum[] = {"naught", "1", "2", "3", "4", "5", "6", "7", "8", "9" };
\r
92 char *ordinals[] = {"zeroth", "first", "second", "third", "fourth", "fifth", "sixth", "seventh", "eighth", "nineth"};
\r
94 char *pieceToName[] = {
\r
95 "White Pawn", "White Knight", "White Bishop", "White Rook", "White Queen",
\r
96 "White Guard", "White Elephant", "White Arch Bishop", "White Chancellor",
\r
97 "White General", "White Man", "White Cannon", "White Night Rider",
\r
98 "White Crowned Bishop", "White Crowned Rook", "White Grass Hopper", "White Veteran",
\r
99 "White Falcon", "White Amazon", "White Snake", "White Unicorn",
\r
101 "Black Pawn", "Black Knight", "Black Bishop", "Black Rook", "Black Queen",
\r
102 "Black Guard", "Black Elephant", "Black Arch Bishop", "Black Chancellor",
\r
103 "Black General", "Black Man", "Black Cannon", "Black Night Rider",
\r
104 "Black Crowned Bishop", "Black Crowned Rook", "Black Grass Hopper", "Black Veteran",
\r
105 "Black Falcon", "Black Amazon", "Black Snake", "Black Unicorn",
\r
110 char *pieceTypeName[] = {
\r
111 "Pawn", "Knight", "Bishop", "Rook", "Queen",
\r
112 "Guard", "Elephant", "Arch Bishop", "Chancellor",
\r
113 "General", "Man", "Cannon", "Night Rider",
\r
114 "Crowned Bishop", "Crowned Rook", "Grass Hopper", "Veteran",
\r
115 "Falcon", "Amazon", "Snake", "Unicorn",
\r
117 "Pawn", "Knight", "Bishop", "Rook", "Queen",
\r
118 "Guard", "Elephant", "Arch Bishop", "Chancellor",
\r
119 "General", "Man", "Cannon", "Night Rider",
\r
120 "Crowned Bishop", "Crowned Rook", "Grass Hopper", "Veteran",
\r
121 "Falcon", "Amazon", "Snake", "Unicorn",
\r
129 if(isdigit(c)) return c - ONE;
\r
130 if(c >= 'a') return c - AAA;
\r
134 char* PieceToName(p, i)
\r
138 if(i) return pieceToName[(int) p];
\r
139 return pieceTypeName[(int) p];
\r
142 char* SquareToChar(x)
\r
145 return squareToChar[x - BOARD_LEFT];
\r
148 char* SquareToNum(y)
\r
151 return squareToNum[y + (gameInfo.boardHeight < 10)];
\r
155 // from winboard.c: all new routines
\r
156 #define JFWAPI __declspec(dllimport)
\r
157 JFWAPI BOOL WINAPI JFWSayString (LPCTSTR lpszStrinToSpeak, BOOL bInterrupt);
\r
159 typedef JFWAPI BOOL (WINAPI *PSAYSTRING)(LPCTSTR lpszStrinToSpeak, BOOL bInterrupt);
\r
161 PSAYSTRING RealSayString;
\r
163 VOID SayString(char *mess, BOOL flag)
\r
164 { // for debug file
\r
165 static char buf[8000], *p;
\r
166 int l = strlen(buf);
\r
167 if(appData.debugMode) fprintf(debugFP, "SAY '%s'\n", mess);
\r
168 if(l) buf[l++] = ' '; // separate by space from previous
\r
169 safeStrCpy(buf+l, _(mess), 8000-1-l); // buffer
\r
170 if(!flag) return; // wait for flush
\r
171 if(p = StrCaseStr(buf, "Xboard adjudication:")) {
\r
173 for(i=19; i>1; i--) p[i] = p[i-1];
\r
176 RealSayString(buf, !strcmp(mess, " ")); // kludge to indicate flushing of interruptable speach
\r
177 if(appData.debugMode) fprintf(debugFP, "SPEAK '%s'\n", buf);
\r
181 //static int fromX = 0, fromY = 0;
\r
182 static int oldFromX, oldFromY;
\r
183 static int timeflag;
\r
184 static int suppressClocks = 0;
\r
185 static int suppressOneKey = 0;
\r
186 static HANDLE hAccelJAWS;
\r
188 typedef struct { char *name; int code; } MenuItemDesc;
\r
190 MenuItemDesc menuItemJAWS[] = {
\r
191 {"Say Clock &Time\tAlt+T", IDM_SayClockTime },
\r
193 {"Say Last &Move\tAlt+M", IDM_SayMachineMove },
\r
194 {"Say W&ho's Turn\tAlt+X", IDM_SayWhosTurn },
\r
196 {"Say Complete &Position\tAlt+P",IDM_SayAllBoard },
\r
197 {"Say &White Pieces\tAlt+W", IDM_SayWhitePieces },
\r
198 {"Say &Black Pieces\tAlt+B", IDM_SayBlackPieces },
\r
199 {"Say Board &Rank\tAlt+R", IDM_ReadRow },
\r
200 {"Say Board &File\tAlt+F", IDM_ReadColumn },
\r
202 {"Say &Upper Diagonals\tAlt+U", IDM_SayUpperDiagnols },
\r
203 {"Say &Lower Diagonals\tAlt+L", IDM_SayLowerDiagnols },
\r
204 {"Say K&night Moves\tAlt+N", IDM_SayKnightMoves },
\r
205 {"Say Current &Square\tAlt+S", IDM_SayCurrentPos },
\r
206 {"Say &Attacks\tAlt+A", IDM_PossibleAttackMove },
\r
207 {"Say Attacke&d\tAlt+D", IDM_PossibleAttacked },
\r
211 ACCEL acceleratorsJAWS[] = {
\r
212 {FVIRTKEY|FALT, 'T', IDM_SayClockTime },
\r
213 {FVIRTKEY|FALT, 'M', IDM_SayMachineMove },
\r
214 {FVIRTKEY|FALT, 'X', IDM_SayWhosTurn },
\r
215 {FVIRTKEY|FALT, 'P', IDM_SayAllBoard },
\r
216 {FVIRTKEY|FALT, 'W', IDM_SayWhitePieces },
\r
217 {FVIRTKEY|FALT, 'B', IDM_SayBlackPieces },
\r
218 {FVIRTKEY|FALT, 'R', IDM_ReadRow },
\r
219 {FVIRTKEY|FALT, 'F', IDM_ReadColumn },
\r
220 {FVIRTKEY|FALT, 'U', IDM_SayUpperDiagnols },
\r
221 {FVIRTKEY|FALT, 'L', IDM_SayLowerDiagnols },
\r
222 {FVIRTKEY|FALT, 'N', IDM_SayKnightMoves },
\r
223 {FVIRTKEY|FALT, 'S', IDM_SayCurrentPos },
\r
224 {FVIRTKEY|FALT, 'A', IDM_PossibleAttackMove },
\r
225 {FVIRTKEY|FALT, 'D', IDM_PossibleAttacked }
\r
231 HMENU menuMain, menuJAWS;
\r
232 MENUBARINFO helpMenuInfo;
\r
235 helpMenuInfo.cbSize = sizeof(helpMenuInfo);
\r
236 menuMain = GetMenu(hwndMain);
\r
237 menuJAWS = CreatePopupMenu();
\r
239 for(i=0; menuItemJAWS[i].name; i++) {
\r
240 if(menuItemJAWS[i].name[0] == '-')
\r
241 AppendMenu(menuJAWS, MF_SEPARATOR, (UINT_PTR) 0, NULL);
\r
242 else AppendMenu(menuJAWS, MF_ENABLED|MF_STRING,
\r
243 (UINT_PTR) menuItemJAWS[i].code, (LPCTSTR) _(menuItemJAWS[i].name));
\r
245 InsertMenu(menuMain, 7, MF_BYPOSITION|MF_POPUP|MF_ENABLED|MF_STRING,
\r
246 (UINT_PTR) menuJAWS, "&JAWS");
\r
247 oldMenuItemState[8] = oldMenuItemState[7];
\r
248 DrawMenuBar(hwndMain);
\r
253 { // to be called at beginning of WinMain, after InitApplication and InitInstance
\r
254 HINSTANCE hApi = LoadLibrary("jfwapi32.dll");
\r
256 DisplayInformation("Missing jfwapi32.dll");
\r
260 RealSayString = (PSAYSTRING)GetProcAddress(hApi, "JFWSayString");
\r
261 if(!RealSayString) {
\r
262 DisplayInformation("SayString returned a null pointer");
\r
267 // [HGM] kludge to reduce need for modification of winboard.c: make tinyLayout menu identical
\r
268 // to standard layout, so that code for switching between them does not have to be deleted
\r
272 menuBarText[0][8] = menuBarText[0][7]; menuBarText[0][7] = "&JAWS";
\r
273 for(i=0; i<9; i++) menuBarText[1][i] = menuBarText[0][i];
\r
276 hAccelJAWS = CreateAcceleratorTable(acceleratorsJAWS, 14);
\r
278 /* initialize cursor position */
\r
280 SetHighlights(fromX, fromY, -1, -1);
\r
281 DrawPosition(FALSE, NULL);
\r
282 oldFromX = oldFromY = -1;
\r
284 if(hwndConsole) SetFocus(hwndConsole);
\r
288 int beeps[] = { 1, 0, 0, 0, 0 };
\r
289 int beepCodes[] = { 0, MB_OK, MB_ICONERROR, MB_ICONQUESTION, MB_ICONEXCLAMATION, MB_ICONASTERISK };
\r
290 static int dropX = -1, dropY = -1;
\r
293 KeyboardEvent(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
295 ChessSquare currentPiece;
\r
296 char *piece, *xchar, *ynum ;
\r
297 int n, beepType = 1; // empty beep
\r
299 if(fromX == -1 || fromY == -1) { // if we just dropped piece, stay at that square
\r
300 fromX = dropX; fromY = dropY;
\r
301 dropX = dropY = -1; // but only once
\r
303 if(fromX == -1 || fromY == -1) {
\r
304 fromX = BOARD_LEFT; fromY = 0;
\r
308 if(fromX == BOARD_RGHT+1) fromX -= 2; else
\r
309 if(fromX == BOARD_LEFT) { if(fromY >= BOARD_HEIGHT - gameInfo.holdingsSize) fromX -= 2; else beepType = 0; } else
\r
310 if(fromX > BOARD_LEFT) fromX--; else beepType = 0; // off-board beep
\r
313 if(fromX == BOARD_LEFT-2) fromX += 2; else
\r
314 if(fromX == BOARD_RGHT-1) { if(fromY < gameInfo.holdingsSize) fromX += 2; else beepType = 0; } else
\r
315 if(fromX < BOARD_RGHT-1) fromX++; else beepType = 0;
\r
318 if(fromX == BOARD_RGHT+1) { if(fromY < gameInfo.holdingsSize - 1) fromY++; else beepType = 0; } else
\r
319 if(fromY < BOARD_HEIGHT-1) fromY++; else beepType = 0;
\r
322 if(fromX == BOARD_LEFT-2) { if(fromY > BOARD_HEIGHT - gameInfo.holdingsSize) fromY--; else beepType = 0; } else
\r
323 if(fromY > 0) fromY--; else beepType = 0;
\r
326 SetHighlights(fromX, fromY, -1, -1);
\r
327 DrawPosition(FALSE, NULL);
\r
328 currentPiece = boards[currentMove][fromY][fromX];
\r
329 piece = PieceToName(currentPiece,1);
\r
330 if(beepType == 1 && currentPiece != EmptySquare) beepType = currentPiece < (int) BlackPawn ? 2 : 3; // white or black beep
\r
331 if(beeps[beepType] == beeps[1] && (fromX == BOARD_RGHT+1 || fromX == BOARD_LEFT-2)) beepType = 4; // holdings beep
\r
332 beepType = beeps[beepType]%6;
\r
333 if(beepType) MessageBeep(beepCodes[beepType]);
\r
334 if(fromX == BOARD_LEFT - 2) {
\r
335 SayString("black holdings", FALSE);
\r
336 if(currentPiece != EmptySquare) {
\r
338 n = boards[currentMove][fromY][1];
\r
339 snprintf(buf, MSG_SIZ, "%d %s%s", n, PieceToName(currentPiece,0), n == 1 ? "" : "s");
\r
340 SayString(buf, FALSE);
\r
342 SayString(" ", 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 snprintf(buf, MSG_SIZ,"%d %s%s", n, PieceToName(currentPiece,0), n == 1 ? "" : "s");
\r
350 SayString(buf, FALSE);
\r
352 SayString(" ", TRUE);
\r
354 if(fromX >= BOARD_LEFT && fromX < BOARD_RGHT) {
\r
356 xchar = SquareToChar(fromX);
\r
357 ynum = SquareToNum(fromY);
\r
358 if(currentPiece != EmptySquare) {
\r
359 snprintf(buf, MSG_SIZ, "%s %s %s", xchar, ynum, piece);
\r
360 } else snprintf(buf, MSG_SIZ, "%s %s", xchar, ynum);
\r
361 SayString(buf, FALSE);
\r
362 SayString(" ", TRUE);
\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",TRUE); 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", TRUE); 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), ReadCallback, (VOIDSTAR) &cl);
\r
446 if(cl.count == 0) SayString("None", FALSE);
\r
447 SayString("", TRUE); // flush
\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",TRUE); 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), ReadCallback, (VOIDSTAR) &cl);
\r
474 if(cl.count == 0) SayString("None", FALSE);
\r
476 SayString("You are defended by", FALSE);
\r
478 boards[currentMove][fromY][fromX] = WhiteOnMove(currentMove) ? BlackQueen : WhiteQueen;
\r
479 cl.count = 0; cl.rt = fromY; cl.ft = fromX; cl.rf = cl.ff = -1;
\r
480 GenLegal(boards[currentMove], PosFlags(currentMove), ReadCallback, (VOIDSTAR) &cl);
\r
481 if(cl.count == 0) SayString("None", FALSE);
\r
482 SayString("", TRUE); // flush
\r
483 boards[currentMove][fromY][fromX] = victim; // put back original occupant
\r
485 if(oldFromX >= 0 && oldFromY >= 0) { // put back possibl selected piece
\r
486 boards[currentMove][oldFromY][oldFromX] = piece;
\r
493 ChessSquare currentpiece;
\r
494 char *piece, *xchar, *ynum ;
\r
496 ynum = SquareToNum(fromY);
\r
498 if(fromY < 0) return;
\r
500 for (xPos=BOARD_LEFT; xPos<BOARD_RGHT; xPos++) {
\r
501 currentpiece = boards[currentMove][fromY][xPos];
\r
502 if(currentpiece != EmptySquare) {
\r
503 piece = PieceToName(currentpiece,1);
\r
504 xchar = SquareToChar(xPos);
\r
505 SayString(xchar , FALSE);
\r
506 SayString(ynum, FALSE);
\r
507 SayString(piece, FALSE);
\r
512 SayString("rank", FALSE);
\r
513 SayString(ynum, FALSE);
\r
514 SayString("empty", FALSE);
\r
516 SayString("", TRUE); // flush
\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
544 SayString("", TRUE); // flush
\r
550 ChessSquare currentpiece;
\r
551 char *piece, *xchar, *ynum ;
\r
554 if(fromX < 0 || fromY < 0) return;
\r
556 if(fromX < BOARD_RGHT-1 && fromY < BOARD_HEIGHT-1) {
\r
557 SayString("The diagnol squares to your upper right contain", FALSE);
\r
560 while(yPos<BOARD_HEIGHT && xPos<BOARD_RGHT) {
\r
561 currentpiece = boards[currentMove][yPos][xPos];
\r
562 piece = PieceToName(currentpiece,1);
\r
563 xchar = SquareToChar(xPos);
\r
564 ynum = SquareToNum(yPos);
\r
565 SayString(xchar , FALSE);
\r
566 SayString(ynum, FALSE);
\r
567 SayString(piece, FALSE);
\r
572 else SayString("There is no squares to your upper right", FALSE);
\r
574 if(fromX > BOARD_LEFT && fromY < BOARD_HEIGHT-1) {
\r
575 SayString("The diagnol squares to your upper left contain", FALSE);
\r
578 while(yPos<BOARD_HEIGHT && xPos>=BOARD_LEFT) {
\r
579 currentpiece = boards[currentMove][yPos][xPos];
\r
580 piece = PieceToName(currentpiece,1);
\r
581 xchar = SquareToChar(xPos);
\r
582 ynum = SquareToNum(yPos);
\r
583 SayString(xchar , FALSE);
\r
584 SayString(ynum, FALSE);
\r
585 SayString(piece, FALSE);
\r
590 else SayString("There is no squares to your upper left", FALSE);
\r
591 SayString("", TRUE); // flush
\r
597 ChessSquare currentpiece;
\r
598 char *piece, *xchar, *ynum ;
\r
601 if(fromX < 0 || fromY < 0) return;
\r
603 if(fromX < BOARD_RGHT-1 && fromY > 0) {
\r
604 SayString("The diagnol squares to your lower right contain", FALSE);
\r
607 while(yPos>=0 && xPos<BOARD_RGHT) {
\r
608 currentpiece = boards[currentMove][yPos][xPos];
\r
609 piece = PieceToName(currentpiece,1);
\r
610 xchar = SquareToChar(xPos);
\r
611 ynum = SquareToNum(yPos);
\r
612 SayString(xchar , FALSE);
\r
613 SayString(ynum, FALSE);
\r
614 SayString(piece, FALSE);
\r
619 else SayString("There is no squares to your lower right", FALSE);
\r
621 if(fromX > BOARD_LEFT && fromY > 0) {
\r
622 SayString("The diagnol squares to your lower left contain", FALSE);
\r
625 while(yPos>=0 && xPos>=BOARD_LEFT) {
\r
626 currentpiece = boards[currentMove][yPos][xPos];
\r
627 piece = PieceToName(currentpiece,1);
\r
628 xchar = SquareToChar(xPos);
\r
629 ynum = SquareToNum(yPos);
\r
630 SayString(xchar , FALSE);
\r
631 SayString(ynum, FALSE);
\r
632 SayString(piece, FALSE);
\r
637 else SayString("There is no squares to your lower left", FALSE);
\r
638 SayString("", TRUE); // flush
\r
644 ChessSquare currentpiece, oldpiece;
\r
645 char *piece, *xchar, *ynum ;
\r
647 oldpiece = boards[currentMove][fromY][fromX];
\r
648 if(oldpiece == WhiteKnight || oldpiece == BlackKnight)
\r
649 SayString("The possible squares a Knight could move to are", FALSE);
\r
651 SayString("The squares a Knight could possibly attack from are", FALSE);
\r
653 if (fromY+2 < BOARD_HEIGHT && fromX-1 >= BOARD_LEFT) {
\r
654 currentpiece = boards[currentMove][fromY+2][fromX-1];
\r
655 if(((oldpiece == WhiteKnight) && (currentpiece > WhiteKing))
\r
656 || ((oldpiece == BlackKnight) && (currentpiece < BlackPawn || currentpiece == EmptySquare))
\r
657 || (oldpiece == EmptySquare) && (currentpiece == WhiteKnight || currentpiece == BlackKnight))
\r
659 piece = PieceToName(currentpiece,1);
\r
660 xchar = SquareToChar(fromX-1);
\r
661 ynum = SquareToNum(fromY+2);
\r
662 SayString(xchar , FALSE);
\r
663 SayString(ynum, FALSE);
\r
664 SayString(piece, FALSE);
\r
668 if (fromY+2 < BOARD_HEIGHT && fromX+1 < BOARD_RGHT) {
\r
669 currentpiece = boards[currentMove][fromY+2][fromX+1];
\r
670 if(((oldpiece == WhiteKnight) && (currentpiece > WhiteKing))
\r
671 || ((oldpiece == BlackKnight) && (currentpiece < BlackPawn || currentpiece == EmptySquare))
\r
672 || (oldpiece == EmptySquare) && (currentpiece == WhiteKnight || currentpiece == BlackKnight))
\r
674 piece = PieceToName(currentpiece,1);
\r
675 xchar = SquareToChar(fromX+1);
\r
676 ynum = SquareToNum(fromY+2);
\r
677 SayString(xchar , FALSE);
\r
678 SayString(ynum, FALSE);
\r
679 SayString(piece, FALSE);
\r
683 if (fromY+1 < BOARD_HEIGHT && fromX+2 < BOARD_RGHT) {
\r
684 currentpiece = boards[currentMove][fromY+1][fromX+2];
\r
685 if(((oldpiece == WhiteKnight) && (currentpiece > WhiteKing))
\r
686 || ((oldpiece == BlackKnight) && (currentpiece < BlackPawn || currentpiece == EmptySquare))
\r
687 || (oldpiece == EmptySquare) && (currentpiece == WhiteKnight || currentpiece == BlackKnight))
\r
689 piece = PieceToName(currentpiece,1);
\r
690 xchar = SquareToChar(fromX+2);
\r
691 ynum = SquareToNum(fromY+1);
\r
692 SayString(xchar , FALSE);
\r
693 SayString(ynum, FALSE);
\r
694 SayString(piece, FALSE);
\r
698 if (fromY-1 >= 0 && fromX+2 < BOARD_RGHT) {
\r
699 currentpiece = boards[currentMove][fromY-1][fromX+2];
\r
700 if(((oldpiece == WhiteKnight) && (currentpiece > WhiteKing))
\r
701 || ((oldpiece == BlackKnight) && (currentpiece < BlackPawn || currentpiece == EmptySquare))
\r
702 || (oldpiece == EmptySquare) && (currentpiece == WhiteKnight || currentpiece == BlackKnight))
\r
704 piece = PieceToName(currentpiece,1);
\r
705 xchar = SquareToChar(fromX+2);
\r
706 ynum = SquareToNum(fromY-1);
\r
707 SayString(xchar , FALSE);
\r
708 SayString(ynum, FALSE);
\r
709 SayString(piece, FALSE);
\r
713 if (fromY-2 >= 0 && fromX+1 < BOARD_RGHT) {
\r
714 currentpiece = boards[currentMove][fromY-2][fromX+1];
\r
715 if(((oldpiece == WhiteKnight) && (currentpiece > WhiteKing))
\r
716 || ((oldpiece == BlackKnight) && (currentpiece < BlackPawn || currentpiece == EmptySquare))
\r
717 || (oldpiece == EmptySquare) && (currentpiece == WhiteKnight || currentpiece == BlackKnight))
\r
719 piece = PieceToName(currentpiece,1);
\r
720 xchar = SquareToChar(fromX+1);
\r
721 ynum = SquareToNum(fromY-2);
\r
722 SayString(xchar , FALSE);
\r
723 SayString(ynum, FALSE);
\r
724 SayString(piece, FALSE);
\r
728 if (fromY-2 >= 0 && fromX-1 >= BOARD_LEFT) {
\r
729 currentpiece = boards[currentMove][fromY-2][fromX-1];
\r
730 if(((oldpiece == WhiteKnight) && (currentpiece > WhiteKing))
\r
731 || ((oldpiece == BlackKnight) && (currentpiece < BlackPawn || currentpiece == EmptySquare))
\r
732 || (oldpiece == EmptySquare) && (currentpiece == WhiteKnight || currentpiece == BlackKnight))
\r
734 piece = PieceToName(currentpiece,1);
\r
735 xchar = SquareToChar(fromX-1);
\r
736 ynum = SquareToNum(fromY-2);
\r
737 SayString(xchar , FALSE);
\r
738 SayString(ynum, FALSE);
\r
739 SayString(piece, FALSE);
\r
743 if (fromY-1 >= 0 && fromX-2 >= BOARD_LEFT) {
\r
744 currentpiece = boards[currentMove][fromY-1][fromX-2];
\r
745 if(((oldpiece == WhiteKnight) && (currentpiece > WhiteKing))
\r
746 || ((oldpiece == BlackKnight) && (currentpiece < BlackPawn || currentpiece == EmptySquare))
\r
747 || (oldpiece == EmptySquare) && (currentpiece == WhiteKnight || currentpiece == BlackKnight))
\r
749 piece = PieceToName(currentpiece,1);
\r
750 xchar = SquareToChar(fromX-2);
\r
751 ynum = SquareToNum(fromY-1);
\r
752 SayString(xchar , FALSE);
\r
753 SayString(ynum, FALSE);
\r
754 SayString(piece, FALSE);
\r
758 if (fromY+1 < BOARD_HEIGHT && fromX-2 >= BOARD_LEFT) {
\r
759 currentpiece = boards[currentMove][fromY+1][fromX-2];
\r
760 if(((oldpiece == WhiteKnight) && (currentpiece > WhiteKing))
\r
761 || ((oldpiece == BlackKnight) && (currentpiece < BlackPawn || currentpiece == EmptySquare))
\r
762 || (oldpiece == EmptySquare) && (currentpiece == WhiteKnight || currentpiece == BlackKnight))
\r
764 piece = PieceToName(currentpiece,1);
\r
765 xchar = SquareToChar(fromX-2);
\r
766 ynum = SquareToNum(fromY+1);
\r
767 SayString(xchar , FALSE);
\r
768 SayString(ynum, FALSE);
\r
769 SayString(piece, FALSE);
\r
772 SayString("", TRUE); // flush
\r
776 SayPieces(ChessSquare p)
\r
778 ChessSquare currentpiece;
\r
779 char *piece, *xchar, *ynum ;
\r
780 int yPos, xPos, count = 0;
\r
783 if(p == WhitePlay) SayString("White pieces", FALSE); else
\r
784 if(p == BlackPlay) SayString("Black pieces", FALSE); else
\r
785 if(p == EmptySquare) SayString("Pieces", FALSE); else {
\r
786 snprintf(buf, sizeof(buf)/sizeof(buf[0]),"%ss", PieceToName(p,1));
\r
787 SayString(buf, FALSE);
\r
789 SayString("are located", FALSE);
\r
790 for(yPos=0; yPos<BOARD_HEIGHT; yPos++) {
\r
791 for(xPos=BOARD_LEFT; xPos<BOARD_RGHT; xPos++) {
\r
792 currentpiece = boards[currentMove][yPos][xPos];
\r
793 if(p == BlackPlay && currentpiece >= BlackPawn && currentpiece <= BlackKing ||
\r
794 p == WhitePlay && currentpiece >= WhitePawn && currentpiece <= WhiteKing )
\r
795 piece = PieceToName(currentpiece,0);
\r
796 else if(p == EmptySquare && currentpiece != EmptySquare)
\r
797 piece = PieceToName(currentpiece,1);
\r
798 else if(p == currentpiece)
\r
802 if(count == 0) SayString("at", FALSE);
\r
803 xchar = SquareToChar(xPos);
\r
804 ynum = SquareToNum(yPos);
\r
805 SayString(xchar , FALSE);
\r
806 SayString(ynum, FALSE);
\r
807 if(piece) SayString(piece, FALSE);
\r
811 if(count == 0) SayString("nowhere", FALSE);
\r
812 SayString("", TRUE); // flush
\r
818 ChessSquare currentpiece;
\r
819 char *piece, *xchar, *ynum ;
\r
820 if(fromX < BOARD_LEFT) { SayString("You strayed into the white holdings", FALSE); return; }
\r
821 if(fromX >= BOARD_RGHT) { SayString("You strayed into the black holdings", FALSE); return; }
\r
822 currentpiece = boards[currentMove][fromY][fromX];
\r
823 piece = PieceToName(currentpiece,1);
\r
824 ynum = SquareToNum(fromY);
\r
825 xchar = SquareToChar(fromX);
\r
826 SayString("Your current position is", FALSE);
\r
827 SayString(xchar, FALSE);
\r
828 SayString(ynum, FALSE);
\r
829 SayString(piece, FALSE);
\r
830 if(((fromX-BOARD_LEFT) ^ fromY)&1)
\r
831 SayString("on a light square",FALSE);
\r
833 SayString("on a dark square",FALSE);
\r
835 PossibleAttacked();
\r
836 SayString("", TRUE); // flush
\r
843 ChessSquare currentpiece;
\r
844 char *piece, *ynum ;
\r
846 if(gameInfo.holdingsWidth) {
\r
848 for(Ypos=0; Ypos<gameInfo.holdingsSize; Ypos++) {
\r
849 int n = boards[currentMove][Ypos][BOARD_WIDTH-2];
\r
853 SayString("white holds", FALSE);
\r
854 currentpiece = boards[currentMove][Ypos][BOARD_WIDTH-1];
\r
855 piece = PieceToName(currentpiece,0);
\r
856 snprintf(buf, MSG_SIZ,"%d %s%s", n, piece, (n==1 ? "" : "s") );
\r
857 SayString(buf, FALSE);
\r
861 for(Ypos=BOARD_HEIGHT-1; Ypos>=BOARD_HEIGHT - gameInfo.holdingsSize; Ypos--) {
\r
862 int n = boards[currentMove][Ypos][1];
\r
866 SayString("black holds", FALSE);
\r
867 currentpiece = boards[currentMove][Ypos][0];
\r
868 piece = PieceToName(currentpiece,0);
\r
869 snprintf(buf, MSG_SIZ, "%d %s%s", n, piece, (n==1 ? "" : "s") );
\r
870 SayString(buf, FALSE);
\r
875 for(Ypos=BOARD_HEIGHT-1; Ypos>=0; Ypos--) {
\r
876 ynum = ordinals[Ypos + (gameInfo.boardHeight < 10)];
\r
877 SayString(ynum, FALSE);
\r
878 SayString("rank", FALSE);
\r
879 for(Xpos=BOARD_LEFT; Xpos<BOARD_RGHT; Xpos++) {
\r
880 currentpiece = boards[currentMove][Ypos][Xpos];
\r
881 if(currentpiece != EmptySquare) {
\r
884 piece = PieceToName(currentpiece,1);
\r
885 while(Xpos < BOARD_RGHT && boards[currentMove][Ypos][Xpos] == currentpiece)
\r
888 snprintf(buf, sizeof(buf)/sizeof(buf[0]), "%d %ss", count, piece);
\r
890 snprintf(buf, sizeof(buf)/sizeof(buf[0]), "%s", piece);
\r
892 SayString(buf, FALSE);
\r
894 int count = 0, oldX = Xpos;
\r
895 while(Xpos < BOARD_RGHT && boards[currentMove][Ypos][Xpos] == EmptySquare)
\r
897 if(Xpos == BOARD_RGHT && oldX == BOARD_LEFT)
\r
898 SayString("all", FALSE);
\r
902 snprintf(buf, sizeof(buf)/sizeof(buf[0]),"%d", count);
\r
903 SayString(buf, FALSE);
\r
907 SayString("empty", FALSE);
\r
911 SayString("", TRUE); // flush
\r
917 if(gameMode == MachinePlaysBlack || gameMode == IcsPlayingWhite) {
\r
918 if(WhiteOnMove(currentMove))
\r
919 SayString("It is your turn", FALSE);
\r
920 else SayString("It is your opponents turn", FALSE);
\r
921 } else if(gameMode == MachinePlaysWhite || gameMode == IcsPlayingBlack) {
\r
922 if(WhiteOnMove(currentMove))
\r
923 SayString("It is your opponents turn", FALSE);
\r
924 else SayString("It is your turn", FALSE);
\r
926 if(WhiteOnMove(currentMove))
\r
927 SayString("White is on move here", FALSE);
\r
928 else SayString("Black is on move here", FALSE);
\r
930 SayString("", TRUE); // flush
\r
933 extern char *commentList[];
\r
936 SayMachineMove(int evenIfDuplicate)
\r
938 int len, xPos, yPos, moveNr, secondSpace = 0, castle = 0, n;
\r
939 ChessSquare currentpiece;
\r
940 char *piece, *xchar, *ynum, *p, checkMark = 0;
\r
941 char c, buf[MSG_SIZ], comment[MSG_SIZ];
\r
942 static char disambiguation[2];
\r
943 static int previousMove = 0;
\r
945 if(appData.debugMode) fprintf(debugFP, "Message = '%s'\n", messageText);
\r
946 if(gameMode == BeginningOfGame) return;
\r
947 if(messageText[0] == '[') return;
\r
949 if(isdigit(messageText[0])) { // message is move, possibly with thinking output
\r
950 int dotCount = 0, spaceCount = 0;
\r
951 sscanf(messageText, "%d", &moveNr);
\r
953 // [HGM] show: better extraction of move
\r
954 while (messageText[len] != NULLCHAR) {
\r
955 if(messageText[len] == '.' && spaceCount == 0) dotCount++;
\r
956 if(messageText[len] == ' ') { if(++spaceCount == 2) secondSpace = len; }
\r
957 if(messageText[len] == '{') { // we detected a comment
\r
958 if(isalpha(messageText[len+1]) ) sscanf(messageText+len, "{%[^}]}", comment);
\r
961 if(messageText[len] == '[') { // we detected thinking output
\r
962 int depth; float score=0; char c, lastMover = (dotCount == 3 ? 'B' : 'W');
\r
963 if(sscanf(messageText+len+1, "%d]%c%f", &depth, &c, &score) > 1) {
\r
964 if(c == ' ') { // if not explicitly specified, figure out source of thinking output
\r
966 case MachinePlaysWhite:
\r
967 case IcsPlayingWhite:
\r
969 case IcsPlayingBlack:
\r
970 case MachinePlaysBlack:
\r
976 if(c != lastMover && !evenIfDuplicate) return; // line is thinking output of future move, ignore.
\r
977 if(2*moveNr - (dotCount < 2) == previousMove)
\r
978 return; // do not repeat same move; likely ponder output
\r
979 snprintf(buf, MSG_SIZ, "score %s %d at %d ply",
\r
980 score > 0 ? "plus" : score < 0 ? "minus" : "",
\r
981 (int) (fabs(score)*100+0.5),
\r
983 SayString(buf, FALSE); // move + thinking output describing it; say it.
\r
985 while(messageText[len-1] == ' ') len--; // position just behind move;
\r
988 if(messageText[len] == '(') { // ICS time printed behind move
\r
989 while(messageText[len+1] && messageText[len] != ')') len++; // skip it
\r
993 if(secondSpace) len = secondSpace; // position behind move
\r
994 if(messageText[len-1] == '+' || messageText[len-1] == '#') { /* you are in checkmate */
\r
995 len--; // strip off check or mate indicator
\r
996 checkMark = messageText[len]; // make sure still seen after we stip off promo piece
\r
998 if(messageText[len-2] == '=') { /* promotion */
\r
999 len-=2; // strip off promotion piece
\r
1000 SayString("promotion", FALSE);
\r
1003 n = 2*moveNr - (dotCount < 2);
\r
1005 if(previousMove != 2*moveNr + (dotCount > 1) || evenIfDuplicate) {
\r
1007 previousMove = 2*moveNr + (dotCount > 1); // remember move nr of move last spoken
\r
1008 snprintf(number, sizeof(number)/sizeof(number[0]),"%d", moveNr);
\r
1010 yPos = CoordToNum(messageText[len-1]); /* turn char coords to ints */
\r
1011 xPos = CoordToNum(messageText[len-2]);
\r
1012 if(xPos < 0 || xPos > 11) return; // prevent crashes if no coord string available to speak
\r
1013 if(yPos < 0 || yPos > 9) return;
\r
1014 currentpiece = boards[n][yPos][xPos];
\r
1015 piece = PieceToName(currentpiece,0);
\r
1016 ynum = SquareToNum(yPos);
\r
1017 xchar = SquareToChar(xPos);
\r
1018 c = messageText[len-3];
\r
1019 if(c == 'x') c = messageText[len-4];
\r
1020 if(!isdigit(c) && c < 'a' && c != '@') c = 0;
\r
1021 disambiguation[0] = c;
\r
1022 SayString(WhiteOnMove(n) ? "Black" : "White", FALSE);
\r
1023 SayString("move", FALSE);
\r
1024 SayString(number, FALSE);
\r
1025 // if(c==0 || c=='@') SayString("a", FALSE);
\r
1026 // intercept castling moves
\r
1027 p = StrStr(messageText, "O-O-O");
\r
1028 if(p && p-messageText < len) {
\r
1029 SayString("queen side castling",FALSE);
\r
1032 p = StrStr(messageText, "O-O");
\r
1033 if(p && p-messageText < len) {
\r
1034 SayString("king side castling",FALSE);
\r
1039 SayString(piece, FALSE);
\r
1040 if(c == '@') SayString("dropped on", FALSE); else
\r
1041 if(c) SayString(disambiguation, FALSE);
\r
1042 SayString("to", FALSE);
\r
1043 SayString(xchar, FALSE);
\r
1044 SayString(ynum, FALSE);
\r
1045 if(messageText[len-3] == 'x') {
\r
1046 currentpiece = boards[n-1][yPos][xPos];
\r
1047 if(currentpiece != EmptySquare) {
\r
1048 piece = PieceToName(currentpiece,0);
\r
1049 SayString("Capturing a",FALSE);
\r
1050 SayString(piece, FALSE);
\r
1051 } else SayString("Capturing onn passann",FALSE);
\r
1054 if(checkMark == '+') SayString("check", FALSE); else
\r
1055 if(checkMark == '#') {
\r
1056 SayString("finishing off", FALSE);
\r
1057 SayString(WhiteOnMove(n) ? "White" : "Black", FALSE);
\r
1061 /* say comment after move, possibly with result */
\r
1063 if(StrStr(messageText, " 1-0")) p = "white wins"; else
\r
1064 if(StrStr(messageText, " 0-1")) p = "black wins"; else
\r
1065 if(StrStr(messageText, " 1/2-1/2")) p = "game ends in a draw";
\r
1068 if(!StrCaseStr(comment, "draw") &&
\r
1069 !StrCaseStr(comment, "white") &&
\r
1070 !StrCaseStr(comment, "black") ) {
\r
1071 SayString(p, FALSE);
\r
1072 SayString("due to", FALSE);
\r
1075 SayString(comment, FALSE); // alphabetic comment (usually game end)
\r
1076 } else if(p) SayString(p, FALSE);
\r
1078 if(commentDialog && commentList[currentMove]) SetFocus(commentDialog);
\r
1081 /* starts not with digit */
\r
1082 if(StrCaseStr(messageText, "illegal")) PlayIcsUnfinishedSound();
\r
1083 SayString(messageText, FALSE);
\r
1086 SayString("", TRUE); // flush
\r
1092 char buf1[50], buf2[50];
\r
1093 char *str1, *str2;
\r
1094 static long int lastWhiteTime, lastBlackTime;
\r
1096 suppressClocks = 1; // if user is using alt+T command, no reason to display them
\r
1097 if(abs(lastWhiteTime - whiteTimeRemaining) < 1000 && abs(lastBlackTime - blackTimeRemaining) < 1000)
\r
1098 suppressClocks = 0; // back on after two requests in rapid succession
\r
1099 snprintf(buf1, sizeof(buf1)/sizeof(buf1[0]),"%s", TimeString(whiteTimeRemaining));
\r
1101 SayString("White clock", FALSE);
\r
1102 SayString(str1, FALSE);
\r
1103 snprintf(buf2, sizeof(buf2)/sizeof(buf2[0]), "%s", TimeString(blackTimeRemaining));
\r
1105 SayString("Black clock", FALSE);
\r
1106 SayString(str2, FALSE);
\r
1107 lastWhiteTime = whiteTimeRemaining;
\r
1108 lastBlackTime = blackTimeRemaining;
\r
1109 SayString("", TRUE); // flush
\r
1113 Toggle(Boolean *b, char *mess)
\r
1116 SayString(mess, FALSE);
\r
1117 SayString("is now", FALSE);
\r
1118 SayString(*b ? "on" : "off", FALSE);
\r
1119 SayString("", TRUE); // flush
\r
1122 /* handles keyboard moves in a click-click fashion */
\r
1124 KeyboardMove(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
1126 ChessSquare currentpiece;
\r
1129 static BOOLEAN sameAgain = FALSE;
\r
1130 switch (message) {
\r
1132 sameAgain = FALSE;
\r
1133 if(oldFromX == fromX && oldFromY == fromY) {
\r
1135 /* click on same square */
\r
1138 else if(oldFromX != -1) {
\r
1140 ChessSquare pdown, pup;
\r
1141 pdown = boards[currentMove][oldFromY][oldFromX];
\r
1142 pup = boards[currentMove][fromY][fromX];
\r
1144 if (gameMode == EditPosition ||
\r
1145 !((WhitePawn <= pdown && pdown <= WhiteKing &&
\r
1146 WhitePawn <= pup && pup <= WhiteKing) ||
\r
1147 (BlackPawn <= pdown && pdown <= BlackKing &&
\r
1148 BlackPawn <= pup && pup <= BlackKing))) {
\r
1149 /* EditPosition, empty square, or different color piece;
\r
1150 click-click move is possible */
\r
1151 char promoChoice = NULLCHAR;
\r
1153 if (HasPromotionChoice(oldFromX, oldFromY, fromX, fromY, &promoChoice)) {
\r
1154 if (appData.alwaysPromoteToQueen) {
\r
1155 UserMoveEvent(oldFromX, oldFromY, fromX, fromY, 'q');
\r
1158 toX = fromX; toY = fromY; fromX = oldFromX; fromY = oldFromY;
\r
1159 PromotionPopup(hwnd);
\r
1160 fromX = toX; fromY = toY;
\r
1164 UserMoveEvent(oldFromX, oldFromY, fromX, fromY, promoChoice);
\r
1166 oldFromX = oldFromY = -1;
\r
1171 /* First downclick, or restart on a square with same color piece */
\r
1172 if (OKToStartUserMove(fromX, fromY)) {
\r
1175 currentpiece = boards[currentMove][fromY][fromX];
\r
1176 piece = PieceToName(currentpiece,1);
\r
1177 SayString(piece, FALSE);
\r
1178 SayString("selected", TRUE);
\r
1181 oldFromX = oldFromY = -1;
\r
1186 if (oldFromX == fromX && oldFromY == fromY) {
\r
1187 /* Upclick on same square */
\r
1189 /* Clicked same square twice: abort click-click move */
\r
1190 oldFromX = oldFromY = -1;
\r
1191 currentpiece = boards[currentMove][fromY][fromX];
\r
1192 piece = PieceToName(currentpiece,0);
\r
1193 SayString(piece, FALSE);
\r
1194 SayString("unselected", TRUE);
\r
1202 { // return TRUE for times we want to announce
\r
1204 x = (x+50)/100; // tenth of seconds
\r
1205 if(x <= 100) return (x%10 == 0);
\r
1206 if(x <= 600) return (x%100 == 0);
\r
1207 if(x <= 6000) return (x%600 == 0);
\r
1208 return (x%3000 == 0);
\r
1211 #define JAWS_ARGS \
\r
1212 { "beepOffBoard", ArgInt, (LPVOID) beeps, TRUE, (ArgIniType) 1 },\
\r
1213 { "beepEmpty", ArgInt, (LPVOID) (beeps+1), TRUE, (ArgIniType) 0 },\
\r
1214 { "beepWhite", ArgInt, (LPVOID) (beeps+2), TRUE, (ArgIniType) 0 },\
\r
1215 { "beepBlack", ArgInt, (LPVOID) (beeps+3), TRUE, (ArgIniType) 0 },\
\r
1216 { "beepHoldings", ArgInt, (LPVOID) (beeps+4), TRUE, (ArgIniType) 0 },\
\r
1218 #define JAWS_ALT_INTERCEPT \
\r
1219 if(suppressOneKey) {\
\r
1220 suppressOneKey = 0;\
\r
1221 if(GetKeyState(VK_MENU) < 0 && GetKeyState(VK_CONTROL) < 0) break;\
\r
1223 if ((char)wParam == 022 && gameMode == EditPosition) { /* <Ctl R>. Pop up piece menu */\
\r
1224 POINT pt; int x, y;\
\r
1225 SquareToPos(fromY, fromX, &x, &y);\
\r
1226 dropX = fromX; dropY = fromY;\
\r
1227 pt.x = x; pt.y = y;\
\r
1228 if(gameInfo.variant != VariantShogi)\
\r
1229 MenuPopup(hwnd, pt, LoadMenu(hInst, "PieceMenu"), -1);\
\r
1231 MenuPopup(hwnd, pt, LoadMenu(hInst, "ShogiPieceMenu"), -1);\
\r
1235 #define JAWS_REPLAY \
\r
1236 case '\020': /* ctrl P */\
\r
1237 { char buf[MSG_SIZ];\
\r
1238 if(GetWindowText(hwnd, buf, MSG_SIZ-1))\
\r
1239 SayString(buf, TRUE);\
\r
1243 #define JAWS_KB_NAVIGATION \
\r
1247 if(GetKeyState(VK_MENU) < 0 && GetKeyState(VK_CONTROL) < 0) {\
\r
1248 /* Control + Alt + letter used for speaking piece positions */\
\r
1249 static int lastTime; static char lastChar;\
\r
1250 int mine = 0, time = GetTickCount(); char c;\
\r
1252 if((char)wParam == lastChar && time-lastTime < 250) mine = 1;\
\r
1253 lastChar = wParam; lastTime = time;\
\r
1256 if(gameMode == IcsPlayingWhite || gameMode == MachinePlaysBlack) mine = !mine;\
\r
1258 if(ToLower(c) == 'x') {\
\r
1259 SayPieces(mine ? WhitePlay : BlackPlay);\
\r
1260 suppressOneKey = 1;\
\r
1263 if(CharToPiece(c) != EmptySquare) {\
\r
1264 SayPieces(CharToPiece(mine ? ToUpper(c) : ToLower(c)));\
\r
1265 suppressOneKey = 1;\
\r
1270 switch (wParam) {\
\r
1275 KeyboardEvent(hwnd, message, wParam, lParam);\
\r
1278 shiftKey = GetKeyState(VK_SHIFT) < 0;\
\r
1279 KeyboardMove(hwnd, message, wParam, lParam);\
\r
1284 switch (wParam) {\
\r
1286 KeyboardMove(hwnd, message, wParam, lParam);\
\r
1291 #define JAWS_MENU_ITEMS \
\r
1292 case IDM_PossibleAttackMove: /*What can I possible attack from here */\
\r
1293 PossibleAttackMove();\
\r
1296 case IDM_PossibleAttacked: /*what can possible attack this square*/\
\r
1297 PossibleAttacked();\
\r
1300 case IDM_ReadRow: /* Read the current row of pieces */\
\r
1304 case IDM_ReadColumn: /* Read the current column of pieces */\
\r
1308 case IDM_SayCurrentPos: /* Say current position including color */\
\r
1312 case IDM_SayAllBoard: /* Say the whole board from bottom to top */\
\r
1316 case IDM_SayMachineMove: /* Say the last move made */\
\r
1318 SayMachineMove(1);\
\r
1321 case IDM_SayUpperDiagnols: /* Says the diagnol positions above you */\
\r
1322 SayUpperDiagnols();\
\r
1325 case IDM_SayLowerDiagnols: /* Say the diagnol positions below you */\
\r
1326 SayLowerDiagnols();\
\r
1329 case IDM_SayBlackPieces: /*Say the opponents pieces */\
\r
1330 SayPieces(BlackPlay);\
\r
1333 case IDM_SayWhitePieces: /*Say the opponents pieces */\
\r
1334 SayPieces(WhitePlay);\
\r
1337 case IDM_SayClockTime: /*Say the clock time */\
\r
1341 case IDM_SayWhosTurn: /* Say whos turn it its */\
\r
1345 case IDM_SayKnightMoves: /* Say Knights (L-shaped) move */\
\r
1346 SayKnightMoves();\
\r
1349 case OPT_PonderNextMove: /* Toggle option setting */\
\r
1350 Toggle(&appData.ponderNextMove, "ponder");\
\r
1353 case OPT_AnimateMoving: /* Toggle option setting */\
\r
1354 Toggle(&appData.animate, "animate moving");\
\r
1357 case OPT_AutoFlag: /* Toggle option setting */\
\r
1358 Toggle(&appData.autoCallFlag, "auto flag");\
\r
1361 case OPT_AlwaysQueen: /* Toggle option setting */\
\r
1362 Toggle(&appData.alwaysPromoteToQueen, "always promote to queen");\
\r
1365 case OPT_TestLegality: /* Toggle option setting */\
\r
1366 Toggle(&appData.testLegality, "legality testing");\
\r
1369 case OPT_HideThinkFromHuman: /* Toggle option setting */\
\r
1370 Toggle(&appData.hideThinkingFromHuman, "hide thinking");\
\r
1371 ShowThinkingEvent();\
\r
1374 case OPT_SaveExtPGN: /* Toggle option setting */\
\r
1375 Toggle(&appData.saveExtendedInfoInPGN, "extended P G N info");\
\r
1378 case OPT_ExtraInfoInMoveHistory: /* Toggle option setting */\
\r
1379 Toggle(&appData.showEvalInMoveHistory, "extra info in move histoty");\
\r
1384 #define JAWS_ACCEL \
\r
1385 !(!frozen && TranslateAccelerator(hwndMain, hAccelJAWS, &msg)) &&
\r
1387 #define JAWS_INIT if (!InitJAWS()) return (FALSE);
\r
1389 #define JAWS_DELETE(X)
\r
1391 #define JAWS_SILENCE if(suppressClocks) return;
\r
1393 #define JAWS_COPYRIGHT \
\r
1394 SetDlgItemText(hDlg, OPT_MESS, "Auditory/Keyboard Enhancements By: Ed Rodriguez (sort of)");
\r
1396 #define SAY(S) SayString((S), TRUE)
\r
1398 #define SAYMACHINEMOVE() SayMachineMove(0)
\r
1400 // After inclusion of this file somewhere early in winboard.c, the remaining part of the patch
\r
1401 // is scattered over winboard.c for actually calling the routines.
\r