/* * This file is part of lanterna (http://code.google.com/p/lanterna/). * * lanterna is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. * * Copyright (C) 2010-2012 Martin */ package com.googlecode.lanterna.terminal; import com.googlecode.lanterna.LanternaException; import com.googlecode.lanterna.input.InputDecoder; import com.googlecode.lanterna.input.InputProvider; import com.googlecode.lanterna.input.Key; import com.googlecode.lanterna.input.KeyMappingProfile; import java.io.IOException; import java.util.LinkedList; import java.util.Queue; /** * This is an abstract terminal that can also read input events (keys), with a * default implementation of the methods from {@code InputProvider}. * @author Martin */ public abstract class InputEnabledAbstractTerminal extends AbstractTerminal implements InputProvider { private final InputDecoder inputDecoder; private final Queue<Key> keyQueue; private final Object readMutex; public InputEnabledAbstractTerminal(InputDecoder inputDecoder) { this.inputDecoder = inputDecoder; this.keyQueue = new LinkedList<Key>(); this.readMutex = new Object(); } @Override public void addInputProfile(KeyMappingProfile profile) { inputDecoder.addProfile(profile); } protected TerminalSize waitForTerminalSizeReport(int timeoutMs) { long startTime = System.currentTimeMillis(); synchronized(readMutex) { while(System.currentTimeMillis() - startTime < timeoutMs) { Key key = inputDecoder.getNextCharacter(); if(key == null) { try { Thread.sleep(1); } catch(InterruptedException e) {} continue; } if(key.getKind() != Key.Kind.CursorLocation) { keyQueue.add(key); } else { TerminalPosition reportedTerminalPosition = inputDecoder.getLastReportedTerminalPosition(); if(reportedTerminalPosition != null) onResized(reportedTerminalPosition.getColumn(), reportedTerminalPosition.getRow()); else throw new LanternaException(new IOException("Unexpected: inputDecoder.getLastReportedTerminalPosition() " + "returned null after position was reported")); return new TerminalSize(reportedTerminalPosition.getColumn(), reportedTerminalPosition.getRow()); } } } throw new LanternaException( new IOException( "Timeout while waiting for terminal size report! " + "Maybe your terminal doesn't support cursor position report, please " + "consider using a custom size querier")); } @Override public Key readInput() { synchronized(readMutex) { if(!keyQueue.isEmpty()) return keyQueue.poll(); Key key = inputDecoder.getNextCharacter(); if (key != null && key.getKind() == Key.Kind.CursorLocation) { TerminalPosition reportedTerminalPosition = inputDecoder.getLastReportedTerminalPosition(); if (reportedTerminalPosition != null) onResized(reportedTerminalPosition.getColumn(), reportedTerminalPosition.getRow()); return readInput(); } else { return key; } } } }