"Denz" <RU*****@RUBBIS Hhotmail.com> wrote in message
news:Hz******** ********@news-server.bigpond. net.au...
Something like this Console class would be
great. Ive just downloaded JCurses but so far looks
like overkill- when just a few methods like clear screen
and cursor position would go such a long way...
I quite like JCurses, *but* I fully agree with you - too much functionality.
Having thought about it a little more, all that is minimally required:
* Console information accessor [e.g. get max lines, columns, etc]
* A clear screen method
* Cursor position set / get methods
* A character read method i.e. accept a sing;le character
without needing to press ENTER [could be designed to
also accept 'special' keys like F1, though best, I think, to
keep it simple and ignore non-standard keys]
with other functionality such as:
* A string read method [e.g. up to X characters in
length without pressing ENTER; ESC could abort
input process; extend to not echo typed keys so
as to allow password-type input]
* Support character atributes like colour etc
* Cursor hide / unhide
would be purely optional.
It is easy enough to make a start with this by creating a Console class:
public class Console
{
public static native int getMaxRows();
public static native int getMaxCols();
public static native void cls();
public static native int getCurRow();
public static native int getCurCol();
public static native void setCurPos(int row, int col);
public static native char inputKey(int[] keyData);
}
Below you will find a JNI implementation for such a class. Since we're
dealing with JNI such code is strictly system-specific, so will work only on
the targeted platform, in this case, Win32 i.e. it should run ok on all
Win9x and up platforms.
The included files:
* A batch file called 'mkConsole.bat' used to document / generate
the steps in creating the native code
* The Java source files:
- Console.java, the Java interface to the JNI routines
- TestConsole.jav a, a minimal test harness for these routines
* C++ source files:
- Console.h
- ConsoleImp.cpp
Assuming you use a Win32 system [I hope so :)] you will need to provide:
* C++ Compiler capable of generating Win32 DLL's
* Suitable 'make' file for this compiler
The code was tested with Borland 5.5.1 and J2SDK 1.4.1, and appears to work
ok. The code is provided 'as is' for educational purposes. It goes without
saying that I accept no reponsibility for this code's use by others.
It may be worthwhile for anyone contemplating the use of this code to first:
* Read the JNI tutorial on the Sun site
* Consult Win32 documentation regarding 'console applications'
for some insight into the code
Sadly, the codes its provision alienates a substantial segment of the Java
community. It is hoped, though, that other may be motivated to implement
this, or similar functionality, for their own platform, and - hopefully -
post it. It would be interesting to see how these simple tasks are performed
on other platforms.
I hope this helps.
Anthony Borla
// FILE: mkConsole.bat =============== =========
@echo off
:: Compile JAVA Source containing Native Method calls
javac -deprecation TestConsole.jav a
:: Create .h header from Java Source
javah -jni TestConsole
:: Implement Native Method (C++) and create a .DLL
:: 1) Compile ConsoleImp.cpp
:: 2) Create ConsoleImp.dll
:: *** You need to implement this for your compiler ***
make -fConsoleImp.mak
:: Execute Java Program which calls Native Method
:: 1) Loads ConsoleImp.dll
:: 2) Calls 'Console' native method
java TestConsole
// FILE: Console.java =============== =========
public class Console
{
// Load DLL
static
{
try
{
System.loadLibr ary("ConsoleImp ");
}
catch (UnsatisfiedLin kError e)
{
System.out.prin tln("Could not locate DLL");
System.exit(1);
}
}
public static native int getMaxRows();
public static native int getMaxCols();
public static native void cls();
public static native int getCurRow();
public static native int getCurCol();
public static native void setCurPos(int row, int col);
public static native char inputKey(int[] keyData);
}
// FILE: TestConsole.jav a =============== ======
public class TestConsole
{
public static void main(String[] args)
{
System.out.prin tln("Start...") ;
Console.cls();
System.out.prin tln(Console.get MaxRows());
System.out.prin tln(Console.get MaxCols());
Console.setCurP os(10, 5);
System.out.prin tln(Console.get CurRow());
System.out.prin tln(Console.get CurCol());
char key;
int[] keyData = new int[]{0, 0};
System.out.prin t("Press a key: ");
key = Console.inputKe y(keyData);
System.out.prin t(key + ", " + (int)key);
if (key == 0)
System.out.prin tln("A special key was pressed");
System.out.prin tln("Key Code: " + keyData[0]);
System.out.prin tln("Key Scan: " + keyData[1]);
System.out.prin tln("End...");
}
}
// FILE: Console.h =============== =========
/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class Console */
#ifndef _Included_Conso le
#define _Included_Conso le
#ifdef __cplusplus
extern "C" {
#endif
/*
* Class: Console
* Method: getMaxRows
* Signature: ()I
*/
JNIEXPORT jint JNICALL Java_Console_ge tMaxRows
(JNIEnv *, jclass);
/*
* Class: Console
* Method: getMaxCols
* Signature: ()I
*/
JNIEXPORT jint JNICALL Java_Console_ge tMaxCols
(JNIEnv *, jclass);
/*
* Class: Console
* Method: cls
* Signature: ()V
*/
JNIEXPORT void JNICALL Java_Console_cl s
(JNIEnv *, jclass);
/*
* Class: Console
* Method: getCurRow
* Signature: ()I
*/
JNIEXPORT jint JNICALL Java_Console_ge tCurRow
(JNIEnv *, jclass);
/*
* Class: Console
* Method: getCurCol
* Signature: ()I
*/
JNIEXPORT jint JNICALL Java_Console_ge tCurCol
(JNIEnv *, jclass);
/*
* Class: Console
* Method: setCurPos
* Signature: (II)V
*/
JNIEXPORT void JNICALL Java_Console_se tCurPos
(JNIEnv *, jclass, jint, jint);
/*
* Class: Console
* Method: inputKey
* Signature: ([I)C
*/
JNIEXPORT jchar JNICALL Java_Console_in putKey
(JNIEnv *, jclass, jintArray);
#ifdef __cplusplus
}
#endif
#endif
// FILE: ConsoleImp.cpp =============== =======
// *** Plaform-specific Header(s)
// *** Here is for Win32
#include <windows.h>
// ***
#include <jni.h>
#include "Console.h"
JNIEXPORT jint JNICALL Java_Console_ge tMaxRows(JNIEnv *, jclass)
{
CONSOLE_SCREEN_ BUFFER_INFO csbi;
::GetConsoleScr eenBufferInfo(
::GetStdHandle( STD_OUTPUT_HAND LE), &csbi);
return csbi.dwSize.Y;
}
JNIEXPORT jint JNICALL Java_Console_ge tMaxCols(JNIEnv *, jclass)
{
CONSOLE_SCREEN_ BUFFER_INFO csbi;
::GetConsoleScr eenBufferInfo(
::GetStdHandle( STD_OUTPUT_HAND LE), &csbi);
return csbi.dwSize.X;
}
JNIEXPORT void JNICALL Java_Console_cl s(JNIEnv *, jclass)
{
COORD coordScreen = { 0, 0 };
CONSOLE_SCREEN_ BUFFER_INFO csbi;
DWORD cCharsWritten;
DWORD dwConSize;
HANDLE hConsole = ::GetStdHandle( STD_OUTPUT_HAND LE);
// Get the number of character cells in the current buffer
::GetConsoleScr eenBufferInfo(h Console, &csbi);
// Compute Console size
dwConSize = csbi.dwSize.X * csbi.dwSize.Y;
// Fill the entire screen with blanks
::FillConsoleOu tputCharacter(h Console, (TCHAR) ' ',
dwConSize, coordScreen, &cCharsWritten) ;
// Get the current text attribute
::GetConsoleScr eenBufferInfo(h Console, &csbi);
// Set the buffer's attributes accordingly
::FillConsoleOu tputAttribute(h Console, csbi.wAttribute s,
dwConSize, coordScreen, &cCharsWritten) ;
// Home the cursor at (0, 0)
::SetConsoleCur sorPosition(hCo nsole, coordScreen);
return;
}
JNIEXPORT jint JNICALL Java_Console_ge tCurRow(JNIEnv *, jclass)
{
CONSOLE_SCREEN_ BUFFER_INFO csbi;
::GetConsoleScr eenBufferInfo(
::GetStdHandle( STD_OUTPUT_HAND LE), &csbi);
return csbi.dwCursorPo sition.Y;
}
JNIEXPORT jint JNICALL Java_Console_ge tCurCol(JNIEnv *, jclass)
{
CONSOLE_SCREEN_ BUFFER_INFO csbi;
::GetConsoleScr eenBufferInfo(
::GetStdHandle( STD_OUTPUT_HAND LE), &csbi);
return csbi.dwCursorPo sition.X;
}
JNIEXPORT void JNICALL Java_Console_se tCurPos(JNIEnv* env, jclass obj, jint
row, jint col)
{
COORD coord; coord.X = col; coord.Y = row;
::SetConsoleCur sorPosition(
::GetStdHandle( STD_OUTPUT_HAND LE), coord);
}
JNIEXPORT jchar JNICALL Java_Console_in putKey(JNIEnv* env, jclass obj,
jintArray keyData)
{
const char NUL = '\0',
ESC = '\x1B';
const int TIMEOUT_MILLIS = 1000;
jsize len = env->GetArrayLength (keyData);
jint* keyData_ = env->GetIntArrayEle ments(keyData, 0);
DWORD omode, nmode; DWORD itemsRead = 0;
INPUT_RECORD ir;
char inputBuffer[4] = { NUL };
HANDLE hConsole = ::GetStdHandle( STD_INPUT_HANDL E);
::GetConsoleMod e(hConsole, &omode);
nmode = omode & ~ENABLE_LINE_IN PUT & ~ENABLE_ECHO_IN PUT;
::SetConsoleMod e(hConsole, nmode);
do
{
::FlushConsoleI nputBuffer(hCon sole);
::WaitForSingle Object(hConsole , TIMEOUT_MILLIS) ;
::PeekConsoleIn put(hConsole, &ir, 1, &itemsRead);
if (itemsRead > 0)
{
if (ir.EventType == KEY_EVENT)
{
// Discard all non-keydown events
if (ir.Event.KeyEv ent.bKeyDown == FALSE)
{
::ReadConsoleIn put(hConsole, &ir, 1, &itemsRead);
continue;
}
// Got ASCII key, so extract, flush, and exit
if (ir.Event.KeyEv ent.uChar.Ascii Char != NUL)
{
if (ir.Event.KeyEv ent.uChar.Ascii Char == ESC)
{
::ReadConsoleIn put(hConsole, &ir, 1, &itemsRead);
inputBuffer[0] = ESC;
}
else
::ReadFile(hCon sole, inputBuffer, 1, &itemsRead, NULL);
keyData_[0] = ir.Event.KeyEve nt.wVirtualKeyC ode;
keyData_[1] = ir.Event.KeyEve nt.wVirtualScan Code;
break;
}
// Got 'special' key, so determine appropriate actions
switch (ir.Event.KeyEv ent.dwControlKe yState)
{
case ENHANCED_KEY:
::ReadConsoleIn put(hConsole, &ir, 1, &itemsRead);
break;
case LEFT_ALT_PRESSE D: case LEFT_CTRL_PRESS ED:
case RIGHT_ALT_PRESS ED: case RIGHT_CTRL_PRES SED:
::ReadFile(hCon sole, inputBuffer, 1, &itemsRead, NULL);
inputBuffer[0] = NUL;
break;
case SHIFT_PRESSED:
::ReadFile(hCon sole, inputBuffer, 1, &itemsRead, NULL);
break;
}
keyData_[0] = ir.Event.KeyEve nt.wVirtualKeyC ode;
keyData_[1] = ir.Event.KeyEve nt.wVirtualScan Code;
}
else
{
// Not Key Event, so just extract and discard
::ReadConsoleIn put(hConsole, &ir, 1, &itemsRead);
}
}
} while (itemsRead == 0);
::FlushConsoleI nputBuffer(hCon sole);
::SetConsoleMod e(hConsole, omode);
env->ReleaseIntArra yElements(keyDa ta, keyData_, 0);
return inputBuffer[0];
}