001: /*
002: * SSHTools - Java SSH2 API
003: *
004: * Copyright (C) 2002-2003 Lee David Painter and Contributors.
005: *
006: * Contributions made by:
007: *
008: * Brett Smith
009: * Richard Pernavas
010: * Erwin Bolwidt
011: *
012: * This program is free software; you can redistribute it and/or
013: * modify it under the terms of the GNU General Public License
014: * as published by the Free Software Foundation; either version 2
015: * of the License, or (at your option) any later version.
016: *
017: * This program is distributed in the hope that it will be useful,
018: * but WITHOUT ANY WARRANTY; without even the implied warranty of
019: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
020: * GNU General Public License for more details.
021: *
022: * You should have received a copy of the GNU General Public License
023: * along with this program; if not, write to the Free Software
024: * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
025: */
026: /**
027: * SSHTools - Java SSH API The contents of this package has been derived from
028: * the TelnetD library available from http://sourceforge.net/projects/telnetd
029: * The original license of the source code is as follows: TelnetD library
030: * (embeddable telnet daemon) Copyright (C) 2000 Dieter Wimberger This library
031: * is free software; you can either redistribute it and/or modify it under the
032: * terms of the GNU Lesser General Public License version 2.1,1999 as
033: * published by the Free Software Foundation (see copy received along with the
034: * library), or under the terms of the BSD-style license received along with
035: * this library.
036: */package com.sshtools.daemon.terminal;
037:
038: import java.io.IOException;
039: import java.io.OutputStream;
040:
041: /**
042: *
043: *
044: * @author $author$
045: * @version $Revision: 1.12 $
046: */
047: public class UserInput implements Runnable {
048: //Aggregations (inner class!)
049: private Buffer buf;
050:
051: //Members
052: private TerminalIO myIO;
053: private int Cursor = 0;
054: private boolean InsertMode = true;
055: private int lastSize = 0;
056: private boolean hardwrapped = false;
057: private char lastread;
058: private int lastcurspos = 0;
059: private boolean maskInput = false;
060: private char mask = '*';
061: private OutputStream pout;
062:
063: /**
064: * Creates a new UserInput object.
065: *
066: * @param io
067: * @param pout
068: */
069: public UserInput(TerminalIO io, OutputStream pout) {
070: myIO = io;
071: this .pout = pout;
072:
073: //allways full length
074: buf = new Buffer(myIO.getColumns() - 1);
075: Cursor = 0;
076: InsertMode = true;
077:
078: Thread thread = new Thread(this );
079: thread.setDaemon(true);
080: thread.start();
081: }
082:
083: //constructor
084: public int size() {
085: return buf.size();
086: }
087:
088: //getSize
089: public String getValue() {
090: return buf.toString();
091: }
092:
093: //getValue
094: public void setValue(String str) throws BufferOverflowException,
095: IOException {
096: storeSize();
097:
098: //buffer
099: buf.clear();
100:
101: //cursor
102: Cursor = 0;
103:
104: //screen
105: myIO.moveLeft(lastSize);
106: myIO.eraseToEndOfLine();
107: append(str);
108: }
109:
110: //setValue
111: public void maskInput(boolean maskInput) {
112: this .maskInput = maskInput;
113: }
114:
115: /**
116: *
117: *
118: * @param mask
119: */
120: public void setMask(char mask) {
121: this .mask = mask;
122: }
123:
124: /**
125: *
126: *
127: * @throws IOException
128: */
129: public void clear() throws IOException {
130: storeSize();
131:
132: //Buffer
133: buf.clear();
134:
135: //Cursor
136: Cursor = 0;
137:
138: //Screen
139: draw();
140: }
141:
142: //clear
143: public String getSoftwrap() throws IndexOutOfBoundsException,
144: IOException {
145: //Wrap from Buffer
146: String content = buf.toString();
147: int idx = content.lastIndexOf(" ");
148:
149: if (idx == -1) {
150: content = "";
151: } else {
152: //System.out.println("Line:softwrap:lastspace:"+idx);
153: content = content.substring(idx + 1, content.length());
154:
155: //System.out.println("Line:softwrap:wraplength:"+content.length());
156: //Cursor
157: //remeber relative cursor pos
158: Cursor = size();
159: Cursor = Cursor - content.length();
160:
161: //buffer
162: for (int i = 0; i < content.length(); i++) {
163: buf.removeCharAt(Cursor);
164: }
165:
166: //screen
167: myIO.moveLeft(content.length());
168: myIO.eraseToEndOfLine();
169:
170: //System.out.println("Line:softwrap:buffercontent:"+buf.toString());
171: }
172:
173: return content + getLastRead();
174: }
175:
176: //getSoftWrap
177: public String getHardwrap() throws IndexOutOfBoundsException,
178: IOException {
179: //Buffer
180: String content = buf.toString();
181: content = content.substring(Cursor, content.length());
182:
183: //System.out.println("buffer:tostring:"+buf.toString()+":");
184: //System.out.println("buffer:size:"+buf.size());
185: int lastsize = buf.size();
186:
187: for (int i = Cursor; i < lastsize; i++) {
188: buf.removeCharAt(Cursor);
189:
190: //System.out.println("buffer:removing char #"+i);
191: }
192:
193: //System.out.println("buffer:tostring:"+buf.toString()+":");
194: //cursor stays
195: //screen
196: myIO.eraseToEndOfLine();
197:
198: return content;
199: }
200:
201: //getHardWrap
202: private void setCharAt(int pos, char ch)
203: throws IndexOutOfBoundsException, IOException {
204: //buffer
205: buf.setCharAt(pos, ch);
206:
207: //cursor
208: //implements overwrite mode no change
209: //screen
210: draw();
211: }
212:
213: //setCharAt
214: private void insertCharAt(int pos, char ch)
215: throws BufferOverflowException, IndexOutOfBoundsException,
216: IOException {
217: storeSize();
218:
219: //buffer
220: buf.ensureSpace(1);
221: buf.insertCharAt(pos, ch);
222:
223: //cursor adjustment (so that it stays in "same" pos)
224: if (Cursor >= pos) {
225: Cursor++;
226: }
227:
228: //screen
229: draw();
230: }
231:
232: //insertCharAt
233: private void removeCharAt(int pos)
234: throws IndexOutOfBoundsException, IOException {
235: storeSize();
236:
237: //buffer
238: buf.removeCharAt(pos);
239:
240: //cursor
241: if (Cursor > pos) {
242: Cursor--;
243: }
244:
245: //screen
246: draw();
247: }
248:
249: //removeChatAt
250: private void insertStringAt(int pos, String str)
251: throws BufferOverflowException, IndexOutOfBoundsException,
252: IOException {
253: storeSize();
254:
255: //buffer
256: buf.ensureSpace(str.length());
257:
258: for (int i = 0; i < str.length(); i++) {
259: buf.insertCharAt(pos, str.charAt(i));
260:
261: //Cursor
262: Cursor++;
263: }
264:
265: //screen
266: draw();
267: }
268:
269: //insertStringAt
270: public void append(char ch) throws BufferOverflowException,
271: IOException {
272: storeSize();
273:
274: //buffer
275: buf.ensureSpace(1);
276: buf.append(ch);
277:
278: //cursor
279: Cursor++;
280:
281: //screen
282: if (!maskInput) {
283: myIO.write(ch);
284: } else {
285: myIO.write(mask);
286: }
287: }
288:
289: //append(char)
290: public void append(String str) throws BufferOverflowException,
291: IOException {
292: storeSize();
293:
294: //buffer
295: buf.ensureSpace(str.length());
296:
297: for (int i = 0; i < str.length(); i++) {
298: buf.append(str.charAt(i));
299:
300: //Cursor
301: Cursor++;
302: }
303:
304: //screen
305: if (!maskInput) {
306: myIO.write(str);
307: } else {
308: for (int i = 0; i < str.length(); i++) {
309: myIO.write(mask);
310: }
311: }
312: }
313:
314: //append(String)
315: public int getCursorPosition() {
316: return Cursor;
317: }
318:
319: //getCursorPosition
320: public void setCursorPosition(int pos) {
321: if (buf.size() < pos) {
322: Cursor = buf.size();
323: } else {
324: Cursor = pos;
325: }
326:
327: //System.out.println("Editline:cursor:"+Cursor);
328: }
329:
330: //setCursorPosition
331: private char getLastRead() {
332: return lastread;
333: }
334:
335: //getLastRead
336: private void setLastRead(char ch) {
337: lastread = ch;
338: }
339:
340: //setLastRead
341: public boolean isInInsertMode() {
342: return InsertMode;
343: }
344:
345: //isInInsertMode
346: public void setInsertMode(boolean b) {
347: InsertMode = b;
348: }
349:
350: //setInsertMode
351: public boolean isHardwrapped() {
352: return hardwrapped;
353: }
354:
355: //isHardwrapped
356: public void setHardwrapped(boolean b) {
357: hardwrapped = b;
358: }
359:
360: //setHardwrapped
361: public void run() {
362: try {
363: int in = 0;
364:
365: do {
366: //get next key
367: in = myIO.read();
368:
369: //store cursorpos
370: lastcurspos = Cursor;
371:
372: switch (in) {
373: case TerminalIO.LEFT:
374: moveLeft();
375:
376: break;
377:
378: case TerminalIO.RIGHT:
379: moveRight();
380:
381: break;
382:
383: case TerminalIO.BACKSPACE:
384:
385: try {
386: if (Cursor != 0) {
387: removeCharAt(Cursor - 1);
388: }
389: } catch (IndexOutOfBoundsException ioobex) {
390: myIO.bell();
391: }
392:
393: break;
394:
395: case TerminalIO.DELETE:
396:
397: try {
398: removeCharAt(Cursor);
399: } catch (IndexOutOfBoundsException ioobex) {
400: myIO.bell();
401: }
402:
403: break;
404:
405: case TerminalIO.ENTER:
406: myIO.write(myIO.getEOLString());
407:
408: if (buf.size() > 0) {
409: pout.write(buf.toString().getBytes());
410: }
411:
412: buf.clear();
413: Cursor = 0;
414: pout.write(TerminalIO.CRLF.getBytes());
415:
416: break;
417:
418: case TerminalIO.UP:
419: case TerminalIO.DOWN:
420: case TerminalIO.TABULATOR:
421: default:
422:
423: try {
424: handleCharInput(in);
425: } catch (BufferOverflowException boex) {
426: setLastRead((char) in);
427: }
428: }
429:
430: myIO.flush();
431: } while (true);
432: } catch (IOException ioe) {
433: return;
434: }
435: }
436:
437: //run
438: public void draw() throws IOException {
439: myIO.moveLeft(lastcurspos);
440: myIO.eraseToEndOfLine();
441:
442: if (!maskInput) {
443: myIO.write(buf.toString());
444: } else {
445: for (int i = 0; i < buf.size(); i++) {
446: myIO.write(mask);
447: }
448: }
449:
450: //adjust screen cursor hmm
451: if (Cursor < buf.size()) {
452: myIO.moveLeft(buf.size() - Cursor);
453: }
454: }
455:
456: private boolean moveRight() throws IOException {
457: //cursor
458: if (Cursor < buf.size()) {
459: Cursor++;
460:
461: //screen
462: myIO.moveRight(1);
463:
464: return true;
465: } else {
466: return false;
467: }
468: }
469:
470: private boolean moveLeft() throws IOException {
471: //cursor
472: if (Cursor > 0) {
473: Cursor--;
474:
475: //screen
476: myIO.moveLeft(1);
477:
478: return true;
479: } else {
480: return false;
481: }
482: }
483:
484: private boolean isCursorAtEnd() {
485: return (Cursor == buf.size());
486: }
487:
488: private void handleCharInput(int ch)
489: throws BufferOverflowException, IOException {
490: if (isCursorAtEnd()) {
491: append((char) ch);
492: } else {
493: if (isInInsertMode()) {
494: try {
495: insertCharAt(Cursor, (char) ch);
496: } catch (BufferOverflowException ex) {
497: //ignore buffer overflow on insert
498: myIO.bell();
499: }
500: } else {
501: setCharAt(Cursor, (char) ch);
502: }
503: }
504: }
505:
506: private void storeSize() {
507: lastSize = buf.size();
508: }
509:
510: class Buffer extends CharBuffer {
511: public Buffer(int size) {
512: super(size);
513: }
514: }
515: }
|