Re: [OT] Win32 JNI Console Class [was: Re: Clear the Screen]

From: Russell Allen (whoopass069_at_hotmail.com)
Date: 01/29/04

  • Next message: baby pink: "Solve the problem....its urgent"
    Date: 28 Jan 2004 19:15:16 -0800
    
    

    Can anyone help me with this one? I am looking for a makefile to fill
    in for the one mentioned in the previous posting for so I can compile
    this all myself. I have the Borland v5.5 command line tools. I have no
    clue where to go here. I tried skipping the 'makefile' idea and tried
    using following syntax and it compiled but I don't think it compiled
    the way it supposed to (windows freaked when I tried to use the DLL)

    cpp32 -I\j2sdk1.4.2_03\include -I\j2sdk1.4.2_03\include\win
    32 -I\Borland\BCC55\Include -oConsoleImp.dll ConsoleImp.cpp

    So I am assuming I am missing a lot here. Any help would be
    appreciated.

    Russ

    "Anthony Borla" <ajborla@bigpond.com> wrote in message news:<UOcMb.6483$Wa.2950@news-server.bigpond.net.au>...
    > "Denz" <RUBBISH@RUBBISHhotmail.com> wrote in message
    > news:Hz%Lb.4898$Wa.2751@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.java, 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.java
    >
    > :: 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.loadLibrary("ConsoleImp");
    > }
    >
    > catch (UnsatisfiedLinkError e)
    > {
    > System.out.println("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.java =====================
    > public class TestConsole
    > {
    > public static void main(String[] args)
    > {
    > System.out.println("Start...");
    >
    > Console.cls();
    >
    > System.out.println(Console.getMaxRows());
    > System.out.println(Console.getMaxCols());
    >
    > Console.setCurPos(10, 5);
    >
    > System.out.println(Console.getCurRow());
    > System.out.println(Console.getCurCol());
    >
    > char key;
    > int[] keyData = new int[]{0, 0};
    >
    > System.out.print("Press a key: ");
    > key = Console.inputKey(keyData);
    >
    > System.out.print(key + ", " + (int)key);
    >
    > if (key == 0)
    > System.out.println("A special key was pressed");
    >
    > System.out.println("Key Code: " + keyData[0]);
    > System.out.println("Key Scan: " + keyData[1]);
    >
    > System.out.println("End...");
    > }
    > }
    >
    >
    > // FILE: Console.h ========================
    > /* DO NOT EDIT THIS FILE - it is machine generated */
    > #include <jni.h>
    > /* Header for class Console */
    >
    > #ifndef _Included_Console
    > #define _Included_Console
    > #ifdef __cplusplus
    > extern "C" {
    > #endif
    > /*
    > * Class: Console
    > * Method: getMaxRows
    > * Signature: ()I
    > */
    > JNIEXPORT jint JNICALL Java_Console_getMaxRows
    > (JNIEnv *, jclass);
    >
    > /*
    > * Class: Console
    > * Method: getMaxCols
    > * Signature: ()I
    > */
    > JNIEXPORT jint JNICALL Java_Console_getMaxCols
    > (JNIEnv *, jclass);
    >
    > /*
    > * Class: Console
    > * Method: cls
    > * Signature: ()V
    > */
    > JNIEXPORT void JNICALL Java_Console_cls
    > (JNIEnv *, jclass);
    >
    > /*
    > * Class: Console
    > * Method: getCurRow
    > * Signature: ()I
    > */
    > JNIEXPORT jint JNICALL Java_Console_getCurRow
    > (JNIEnv *, jclass);
    >
    > /*
    > * Class: Console
    > * Method: getCurCol
    > * Signature: ()I
    > */
    > JNIEXPORT jint JNICALL Java_Console_getCurCol
    > (JNIEnv *, jclass);
    >
    > /*
    > * Class: Console
    > * Method: setCurPos
    > * Signature: (II)V
    > */
    > JNIEXPORT void JNICALL Java_Console_setCurPos
    > (JNIEnv *, jclass, jint, jint);
    >
    > /*
    > * Class: Console
    > * Method: inputKey
    > * Signature: ([I)C
    > */
    > JNIEXPORT jchar JNICALL Java_Console_inputKey
    > (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_getMaxRows(JNIEnv *, jclass)
    > {
    > CONSOLE_SCREEN_BUFFER_INFO csbi;
    >
    > ::GetConsoleScreenBufferInfo(
    > ::GetStdHandle(STD_OUTPUT_HANDLE), &csbi);
    >
    > return csbi.dwSize.Y;
    > }
    >
    > JNIEXPORT jint JNICALL Java_Console_getMaxCols(JNIEnv *, jclass)
    > {
    > CONSOLE_SCREEN_BUFFER_INFO csbi;
    >
    > ::GetConsoleScreenBufferInfo(
    > ::GetStdHandle(STD_OUTPUT_HANDLE), &csbi);
    >
    > return csbi.dwSize.X;
    > }
    >
    > JNIEXPORT void JNICALL Java_Console_cls(JNIEnv *, jclass)
    > {
    > COORD coordScreen = { 0, 0 };
    > CONSOLE_SCREEN_BUFFER_INFO csbi;
    >
    > DWORD cCharsWritten;
    > DWORD dwConSize;
    >
    > HANDLE hConsole = ::GetStdHandle(STD_OUTPUT_HANDLE);
    >
    > // Get the number of character cells in the current buffer
    > ::GetConsoleScreenBufferInfo(hConsole, &csbi);
    >
    > // Compute Console size
    > dwConSize = csbi.dwSize.X * csbi.dwSize.Y;
    >
    > // Fill the entire screen with blanks
    > ::FillConsoleOutputCharacter(hConsole, (TCHAR) ' ',
    > dwConSize, coordScreen, &cCharsWritten);
    >
    > // Get the current text attribute
    > ::GetConsoleScreenBufferInfo(hConsole, &csbi);
    >
    > // Set the buffer's attributes accordingly
    > ::FillConsoleOutputAttribute(hConsole, csbi.wAttributes,
    > dwConSize, coordScreen, &cCharsWritten);
    >
    > // Home the cursor at (0, 0)
    > ::SetConsoleCursorPosition(hConsole, coordScreen);
    >
    > return;
    > }
    >
    > JNIEXPORT jint JNICALL Java_Console_getCurRow(JNIEnv *, jclass)
    > {
    > CONSOLE_SCREEN_BUFFER_INFO csbi;
    >
    > ::GetConsoleScreenBufferInfo(
    > ::GetStdHandle(STD_OUTPUT_HANDLE), &csbi);
    >
    > return csbi.dwCursorPosition.Y;
    > }
    >
    > JNIEXPORT jint JNICALL Java_Console_getCurCol(JNIEnv *, jclass)
    > {
    > CONSOLE_SCREEN_BUFFER_INFO csbi;
    >
    > ::GetConsoleScreenBufferInfo(
    > ::GetStdHandle(STD_OUTPUT_HANDLE), &csbi);
    >
    > return csbi.dwCursorPosition.X;
    > }
    >
    > JNIEXPORT void JNICALL Java_Console_setCurPos(JNIEnv* env, jclass obj, jint
    > row, jint col)
    > {
    > COORD coord; coord.X = col; coord.Y = row;
    >
    > ::SetConsoleCursorPosition(
    > ::GetStdHandle(STD_OUTPUT_HANDLE), coord);
    > }
    >
    > JNIEXPORT jchar JNICALL Java_Console_inputKey(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->GetIntArrayElements(keyData, 0);
    >
    > DWORD omode, nmode; DWORD itemsRead = 0;
    > INPUT_RECORD ir;
    > char inputBuffer[4] = { NUL };
    >
    > HANDLE hConsole = ::GetStdHandle(STD_INPUT_HANDLE);
    >
    > ::GetConsoleMode(hConsole, &omode);
    > nmode = omode & ~ENABLE_LINE_INPUT & ~ENABLE_ECHO_INPUT;
    > ::SetConsoleMode(hConsole, nmode);
    >
    > do
    > {
    > ::FlushConsoleInputBuffer(hConsole);
    > ::WaitForSingleObject(hConsole, TIMEOUT_MILLIS);
    > ::PeekConsoleInput(hConsole, &ir, 1, &itemsRead);
    >
    > if (itemsRead > 0)
    > {
    > if (ir.EventType == KEY_EVENT)
    > {
    > // Discard all non-keydown events
    > if (ir.Event.KeyEvent.bKeyDown == FALSE)
    > {
    > ::ReadConsoleInput(hConsole, &ir, 1, &itemsRead);
    > continue;
    > }
    >
    > // Got ASCII key, so extract, flush, and exit
    > if (ir.Event.KeyEvent.uChar.AsciiChar != NUL)
    > {
    > if (ir.Event.KeyEvent.uChar.AsciiChar == ESC)
    > {
    > ::ReadConsoleInput(hConsole, &ir, 1, &itemsRead);
    > inputBuffer[0] = ESC;
    > }
    > else
    > ::ReadFile(hConsole, inputBuffer, 1, &itemsRead, NULL);
    >
    > keyData_[0] = ir.Event.KeyEvent.wVirtualKeyCode;
    > keyData_[1] = ir.Event.KeyEvent.wVirtualScanCode;
    >
    > break;
    > }
    >
    > // Got 'special' key, so determine appropriate actions
    > switch (ir.Event.KeyEvent.dwControlKeyState)
    > {
    > case ENHANCED_KEY:
    > ::ReadConsoleInput(hConsole, &ir, 1, &itemsRead);
    > break;
    >
    > case LEFT_ALT_PRESSED: case LEFT_CTRL_PRESSED:
    > case RIGHT_ALT_PRESSED: case RIGHT_CTRL_PRESSED:
    > ::ReadFile(hConsole, inputBuffer, 1, &itemsRead, NULL);
    > inputBuffer[0] = NUL;
    > break;
    >
    > case SHIFT_PRESSED:
    > ::ReadFile(hConsole, inputBuffer, 1, &itemsRead, NULL);
    > break;
    > }
    >
    > keyData_[0] = ir.Event.KeyEvent.wVirtualKeyCode;
    > keyData_[1] = ir.Event.KeyEvent.wVirtualScanCode;
    > }
    > else
    > {
    > // Not Key Event, so just extract and discard
    > ::ReadConsoleInput(hConsole, &ir, 1, &itemsRead);
    > }
    > }
    >
    > } while (itemsRead == 0);
    >
    > ::FlushConsoleInputBuffer(hConsole);
    > ::SetConsoleMode(hConsole, omode);
    >
    > env->ReleaseIntArrayElements(keyData, keyData_, 0);
    >
    > return inputBuffer[0];
    > }


  • Next message: baby pink: "Solve the problem....its urgent"