1 package featurecat.lizzie.gui;
2 
3 import static java.awt.event.KeyEvent.*;
4 
5 import featurecat.lizzie.Lizzie;
6 import java.awt.event.*;
7 import javax.swing.*;
8 
9 public class Input implements MouseListener, KeyListener, MouseWheelListener, MouseMotionListener {
10   @Override
mouseClicked(MouseEvent e)11   public void mouseClicked(MouseEvent e) {}
12 
13   @Override
mousePressed(MouseEvent e)14   public void mousePressed(MouseEvent e) {
15     if (e.getButton() == MouseEvent.BUTTON1) // left click
16     Lizzie.frame.onClicked(e.getX(), e.getY());
17     else if (e.getButton() == MouseEvent.BUTTON3) // right click
18     undo();
19   }
20 
21   @Override
mouseReleased(MouseEvent e)22   public void mouseReleased(MouseEvent e) {}
23 
24   @Override
mouseEntered(MouseEvent e)25   public void mouseEntered(MouseEvent e) {}
26 
27   @Override
mouseExited(MouseEvent e)28   public void mouseExited(MouseEvent e) {}
29 
30   @Override
mouseDragged(MouseEvent e)31   public void mouseDragged(MouseEvent e) {
32     Lizzie.frame.onMouseDragged(e.getX(), e.getY());
33   }
34 
35   @Override
mouseMoved(MouseEvent e)36   public void mouseMoved(MouseEvent e) {
37     Lizzie.frame.onMouseMoved(e.getX(), e.getY());
38   }
39 
40   @Override
keyTyped(KeyEvent e)41   public void keyTyped(KeyEvent e) {}
42 
undo()43   public static void undo() {
44     undo(1);
45   }
46 
undo(int movesToAdvance)47   public static void undo(int movesToAdvance) {
48     if (Lizzie.board.inAnalysisMode()) Lizzie.board.toggleAnalysis();
49     if (Lizzie.frame.isPlayingAgainstLeelaz) {
50       Lizzie.frame.isPlayingAgainstLeelaz = false;
51     }
52     if (Lizzie.frame.incrementDisplayedBranchLength(-movesToAdvance)) {
53       return;
54     }
55 
56     for (int i = 0; i < movesToAdvance; i++) Lizzie.board.previousMove();
57   }
58 
undoToChildOfPreviousWithVariation()59   private void undoToChildOfPreviousWithVariation() {
60     // Undo until the position just after the junction position.
61     // If we are already on such a position, we go to
62     // the junction position for convenience.
63     // Use cases:
64     // [Delete branch] Call this function and then deleteMove.
65     // [Go to junction] Call this function twice.
66     if (!Lizzie.board.undoToChildOfPreviousWithVariation()) Lizzie.board.previousMove();
67   }
68 
undoToFirstParentWithVariations()69   private void undoToFirstParentWithVariations() {
70     if (Lizzie.board.undoToChildOfPreviousWithVariation()) {
71       Lizzie.board.previousMove();
72     }
73   }
74 
goCommentNode(boolean moveForward)75   private void goCommentNode(boolean moveForward) {
76     if (moveForward) {
77       redo(Lizzie.board.getHistory().getCurrentHistoryNode().goToNextNodeWithComment());
78     } else {
79       undo(Lizzie.board.getHistory().getCurrentHistoryNode().goToPreviousNodeWithComment());
80     }
81   }
82 
redo()83   private void redo() {
84     redo(1);
85   }
86 
redo(int movesToAdvance)87   private void redo(int movesToAdvance) {
88     if (Lizzie.board.inAnalysisMode()) Lizzie.board.toggleAnalysis();
89     if (Lizzie.frame.isPlayingAgainstLeelaz) {
90       Lizzie.frame.isPlayingAgainstLeelaz = false;
91     }
92     if (Lizzie.frame.incrementDisplayedBranchLength(movesToAdvance)) {
93       return;
94     }
95 
96     for (int i = 0; i < movesToAdvance; i++) Lizzie.board.nextMove();
97   }
98 
startTemporaryBoard()99   private void startTemporaryBoard() {
100     if (Lizzie.config.showBestMoves) {
101       startRawBoard();
102     } else {
103       Lizzie.config.showBestMovesTemporarily = true;
104     }
105   }
106 
startRawBoard()107   private void startRawBoard() {
108     if (!Lizzie.config.showRawBoard) {
109       Lizzie.frame.startRawBoard();
110     }
111     Lizzie.config.showRawBoard = true;
112   }
113 
stopRawBoard()114   private void stopRawBoard() {
115     Lizzie.frame.stopRawBoard();
116     Lizzie.config.showRawBoard = false;
117   }
118 
stopTemporaryBoard()119   private void stopTemporaryBoard() {
120     stopRawBoard();
121     Lizzie.config.showBestMovesTemporarily = false;
122   }
123 
toggleHints()124   private void toggleHints() {
125     Lizzie.config.toggleShowBranch();
126     Lizzie.config.showSubBoard =
127         Lizzie.config.showNextMoves = Lizzie.config.showBestMoves = Lizzie.config.showBranch;
128   }
129 
nextBranch()130   private void nextBranch() {
131     if (Lizzie.frame.isPlayingAgainstLeelaz) {
132       Lizzie.frame.isPlayingAgainstLeelaz = false;
133     }
134     Lizzie.board.nextBranch();
135   }
136 
previousBranch()137   private void previousBranch() {
138     if (Lizzie.frame.isPlayingAgainstLeelaz) {
139       Lizzie.frame.isPlayingAgainstLeelaz = false;
140     }
141     Lizzie.board.previousBranch();
142   }
143 
moveBranchUp()144   private void moveBranchUp() {
145     Lizzie.board.moveBranchUp();
146   }
147 
moveBranchDown()148   private void moveBranchDown() {
149     Lizzie.board.moveBranchDown();
150   }
151 
deleteMove()152   private void deleteMove() {
153     Lizzie.board.deleteMove();
154   }
155 
deleteBranch()156   private void deleteBranch() {
157     Lizzie.board.deleteBranch();
158   }
159 
controlIsPressed(KeyEvent e)160   private boolean controlIsPressed(KeyEvent e) {
161     boolean mac = System.getProperty("os.name", "").toUpperCase().startsWith("MAC");
162     return e.isControlDown() || (mac && e.isMetaDown());
163   }
164 
toggleShowDynamicKomi()165   private void toggleShowDynamicKomi() {
166     Lizzie.config.showDynamicKomi = !Lizzie.config.showDynamicKomi;
167   }
168 
169   @Override
keyPressed(KeyEvent e)170   public void keyPressed(KeyEvent e) {
171     // If any controls key is pressed, let's disable analysis mode.
172     // This is probably the user attempting to exit analysis mode.
173     boolean shouldDisableAnalysis = true;
174 
175     switch (e.getKeyCode()) {
176       case VK_E:
177         Lizzie.frame.toggleGtpConsole();
178         break;
179       case VK_RIGHT:
180         if (e.isShiftDown()) {
181           moveBranchDown();
182         } else {
183           nextBranch();
184         }
185         break;
186 
187       case VK_LEFT:
188         if (e.isShiftDown()) {
189           moveBranchUp();
190         } else if (controlIsPressed(e)) {
191           undoToFirstParentWithVariations();
192         } else {
193           previousBranch();
194         }
195         break;
196 
197       case VK_UP:
198         if (controlIsPressed(e) && e.isShiftDown()) {
199           goCommentNode(false);
200         } else if (e.isShiftDown()) {
201           undoToChildOfPreviousWithVariation();
202         } else if (controlIsPressed(e)) {
203           undo(10);
204         } else {
205           undo();
206         }
207         break;
208 
209       case VK_PAGE_DOWN:
210         if (controlIsPressed(e) && e.isShiftDown()) {
211           Lizzie.frame.increaseMaxAlpha(-5);
212         } else {
213           redo(10);
214         }
215         break;
216 
217       case VK_DOWN:
218         if (controlIsPressed(e) && e.isShiftDown()) {
219           goCommentNode(true);
220         } else if (controlIsPressed(e)) {
221           redo(10);
222         } else {
223           redo();
224         }
225         break;
226 
227       case VK_N:
228         // stop the ponder
229         if (Lizzie.leelaz.isPondering()) Lizzie.leelaz.togglePonder();
230         LizzieFrame.startNewGame();
231         break;
232       case VK_SPACE:
233         if (Lizzie.frame.isPlayingAgainstLeelaz) {
234           Lizzie.frame.isPlayingAgainstLeelaz = false;
235           Lizzie.leelaz.isThinking = false;
236         }
237         Lizzie.leelaz.togglePonder();
238         break;
239 
240       case VK_P:
241         Lizzie.board.pass();
242         break;
243 
244       case VK_COMMA:
245         if (!Lizzie.frame.playCurrentVariation()) Lizzie.frame.playBestMove();
246         break;
247 
248       case VK_M:
249         if (e.isAltDown()) {
250           Lizzie.frame.openChangeMoveDialog();
251         } else {
252           Lizzie.config.toggleShowMoveNumber();
253         }
254         break;
255 
256       case VK_F:
257         Lizzie.config.toggleShowNextMoves();
258         break;
259 
260       case VK_H:
261         Lizzie.config.toggleHandicapInsteadOfWinrate();
262         break;
263 
264       case VK_PAGE_UP:
265         if (controlIsPressed(e) && e.isShiftDown()) {
266           Lizzie.frame.increaseMaxAlpha(5);
267         } else {
268           undo(10);
269         }
270         break;
271 
272       case VK_I:
273         // stop the ponder
274         if (Lizzie.leelaz.isPondering()) Lizzie.leelaz.togglePonder();
275         Lizzie.frame.editGameInfo();
276         break;
277       case VK_S:
278         // stop the ponder
279         if (Lizzie.leelaz.isPondering()) Lizzie.leelaz.togglePonder();
280         LizzieFrame.saveFile();
281         break;
282 
283       case VK_O:
284         if (Lizzie.leelaz.isPondering()) Lizzie.leelaz.togglePonder();
285         LizzieFrame.openFile();
286         break;
287 
288       case VK_V:
289         if (controlIsPressed(e)) {
290           Lizzie.frame.pasteSgf();
291         } else {
292           Lizzie.config.toggleShowBranch();
293         }
294         break;
295 
296       case VK_HOME:
297         if (controlIsPressed(e)) {
298           Lizzie.board.clear();
299         } else {
300           while (Lizzie.board.previousMove()) ;
301         }
302         break;
303 
304       case VK_END:
305         while (Lizzie.board.nextMove()) ;
306         break;
307 
308       case VK_X:
309         if (controlIsPressed(e)) {
310           Lizzie.frame.openConfigDialog();
311         } else {
312           if (!Lizzie.frame.showControls) {
313             if (Lizzie.leelaz.isPondering()) {
314               wasPonderingWhenControlsShown = true;
315               Lizzie.leelaz.togglePonder();
316             } else {
317               wasPonderingWhenControlsShown = false;
318             }
319             Lizzie.frame.drawControls();
320           }
321           Lizzie.frame.showControls = true;
322         }
323         break;
324 
325       case VK_W:
326         if (controlIsPressed(e)) {
327           Lizzie.config.toggleLargeWinrate();
328         } else {
329           Lizzie.config.toggleShowWinrate();
330         }
331         break;
332 
333       case VK_L:
334         Lizzie.config.toggleShowLcbWinrate();
335         break;
336 
337       case VK_G:
338         Lizzie.config.toggleShowVariationGraph();
339         break;
340 
341       case VK_T:
342         if (controlIsPressed(e)) {
343           Lizzie.config.toggleShowCommentNodeColor();
344         } else {
345           Lizzie.config.toggleShowComment();
346         }
347         break;
348 
349       case VK_Y:
350         Lizzie.config.toggleNodeColorMode();
351         break;
352 
353       case VK_C:
354         if (controlIsPressed(e)) {
355           Lizzie.frame.copySgf();
356         } else {
357           Lizzie.config.toggleCoordinates();
358         }
359         break;
360 
361       case VK_ENTER:
362         if (!Lizzie.leelaz.isThinking) {
363           Lizzie.leelaz.sendCommand(
364               "time_settings 0 "
365                   + Lizzie.config
366                       .config
367                       .getJSONObject("leelaz")
368                       .getInt("max-game-thinking-time-seconds")
369                   + " 1");
370           Lizzie.frame.playerIsBlack = !Lizzie.board.getData().blackToPlay;
371           Lizzie.frame.isPlayingAgainstLeelaz = true;
372           Lizzie.leelaz.genmove((Lizzie.board.getData().blackToPlay ? "B" : "W"));
373         }
374         break;
375 
376       case VK_DELETE:
377       case VK_BACK_SPACE:
378         if (e.isShiftDown()) {
379           deleteBranch();
380         } else {
381           deleteMove();
382         }
383         break;
384 
385       case VK_Z:
386         if (e.isShiftDown()) {
387           toggleHints();
388         } else {
389           startTemporaryBoard();
390         }
391         break;
392 
393       case VK_A:
394         shouldDisableAnalysis = false;
395         Lizzie.board.toggleAnalysis();
396         break;
397 
398       case VK_PERIOD:
399         if (!Lizzie.board.getHistory().getNext().isPresent()) {
400           Lizzie.board.setScoreMode(!Lizzie.board.inScoreMode());
401         }
402         break;
403 
404       case VK_D:
405         toggleShowDynamicKomi();
406         break;
407 
408       case VK_R:
409         Lizzie.frame.replayBranch();
410         break;
411 
412       case VK_OPEN_BRACKET:
413         if (Lizzie.frame.BoardPositionProportion > 0) Lizzie.frame.BoardPositionProportion--;
414         break;
415 
416       case VK_CLOSE_BRACKET:
417         if (Lizzie.frame.BoardPositionProportion < 8) Lizzie.frame.BoardPositionProportion++;
418         break;
419 
420       case VK_K:
421         Lizzie.config.toggleEvaluationColoring();
422         break;
423 
424         // Use Ctrl+Num to switching multiple engine
425       case VK_0:
426       case VK_1:
427       case VK_2:
428       case VK_3:
429       case VK_4:
430       case VK_5:
431       case VK_6:
432       case VK_7:
433       case VK_8:
434       case VK_9:
435         if (controlIsPressed(e)) {
436           Lizzie.switchEngine(e.getKeyCode() - VK_0);
437         }
438         break;
439       default:
440         shouldDisableAnalysis = false;
441     }
442 
443     if (shouldDisableAnalysis && Lizzie.board.inAnalysisMode()) Lizzie.board.toggleAnalysis();
444 
445     Lizzie.frame.repaint();
446   }
447 
448   private boolean wasPonderingWhenControlsShown = false;
449 
450   @Override
keyReleased(KeyEvent e)451   public void keyReleased(KeyEvent e) {
452     switch (e.getKeyCode()) {
453       case VK_X:
454         if (wasPonderingWhenControlsShown) Lizzie.leelaz.togglePonder();
455         Lizzie.frame.showControls = false;
456         Lizzie.frame.repaint();
457         break;
458 
459       case VK_Z:
460         stopTemporaryBoard();
461         Lizzie.frame.repaint();
462         break;
463 
464       default:
465     }
466   }
467 
468   @Override
mouseWheelMoved(MouseWheelEvent e)469   public void mouseWheelMoved(MouseWheelEvent e) {
470     if (Lizzie.frame.processCommentMouseWheelMoved(e)) {
471       return;
472     }
473     if (Lizzie.board.inAnalysisMode()) Lizzie.board.toggleAnalysis();
474     if (e.getWheelRotation() > 0) {
475       redo();
476     } else if (e.getWheelRotation() < 0) {
477       undo();
478     }
479     Lizzie.frame.repaint();
480   }
481 }
482