///////////////////////////////////////////////////////////////////////////////
// Copyright (C) 2000 Davanum Srinivas (dims@geocities.com)
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// 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 General Public License for more
// details.
//
// You should have received a copy of the GNU General Public License along with
// this program; if not, write to the
// Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
///////////////////////////////////////////////////////////////////////////////
#define _WIN32_WINNT (0x0400)
#include <windows.h>
#include <windowsx.h>
#include <process.h>
#include "JFrameEx.h"
// JVM independent entry point for getting the current JVM.
extern "C" {
typedef jint (JNICALL *pJNI_GetCreatedJavaVMs)(JavaVM **, jsize, jsize *);
}
// Thread for notifying the java code.
void WINAPIV StartNotifyThread(LPVOID lpVoid);
// Using STL for storing the callback information.
#include <map>
using namespace std;
typedef map<HWND, jobject, less<HWND> > HWND2OBJECT;
typedef map<HWND, WNDPROC, less<HWND> > HWND2PROC;
// Shared Data
#pragma data_seg(".shared")
static HWND2PROC theProcMap;
static HWND2OBJECT theFrameMap;
#pragma data_seg()
// Helpers for getting and storing the JFrameEx object
void setFrame(HWND hwnd, jobject object)
{
theFrameMap.insert(HWND2OBJECT::value_type(hwnd,object));
}
jobject getFrame(HWND hwnd)
{
HWND2OBJECT::iterator iterator;
iterator = theFrameMap.find(hwnd);
if(iterator != theFrameMap.end())
return (*iterator).second;
return 0;
}
// Helpers for getting and storing the initial window proc's
void setProc(HWND hwnd, WNDPROC proc)
{
theProcMap.insert(HWND2PROC::value_type(hwnd,proc));
}
WNDPROC getProc(HWND hwnd)
{
HWND2PROC::iterator iterator;
iterator = theProcMap.find(hwnd);
if(iterator != theProcMap.end())
return (*iterator).second;
return 0;
}
// Window Proc for subclassing.
LRESULT CALLBACK FrameWindowProc(
HWND hwnd, // handle to window
UINT uMsg, // message identifier
WPARAM wParam, // first message parameter
LPARAM lParam // second message parameter
)
{
// Get the WindowProc for this window.
WNDPROC oldProc = getProc((HWND)hwnd);
// When we get a mouse wheel message
if(uMsg == WM_MOUSEWHEEL)
{
MSG *pMsg = new MSG;
pMsg->hwnd = hwnd;
pMsg->message = uMsg;
pMsg->wParam = wParam;
pMsg->lParam = lParam;
// send it to the java code.
_beginthread(StartNotifyThread, 0, pMsg);
return 0;
}
return ::CallWindowProc(oldProc, hwnd, uMsg, wParam, lParam);
}
// JNI native entry point for subclassing the window
JNIEXPORT void JNICALL Java_JFrameEx_setHook
(JNIEnv *pEnv, jobject f, jint hwnd)
{
// ensure that the java object can be called from any thread.
jobject frame = pEnv->NewGlobalRef(f);
WNDPROC oldProc = (WNDPROC)::SetWindowLong((HWND)hwnd, GWL_WNDPROC, (LONG)FrameWindowProc);
// store the java object
setFrame((HWND)hwnd, frame);
// store the old window proc
setProc ((HWND)hwnd, oldProc);
}
// JNI native entry point remving subclassing from the window
JNIEXPORT void JNICALL Java_JFrameEx_resetHook
(JNIEnv *pEnv, jobject f, jint hwnd)
{
WNDPROC oldProc = getProc((HWND)hwnd);
jobject frame = getFrame((HWND)hwnd);
::SetWindowLong((HWND)hwnd, GWL_WNDPROC, (LONG)oldProc);
pEnv->DeleteGlobalRef(frame);
}
// JVM independent helper for getting the current JVM.
pJNI_GetCreatedJavaVMs getJavaVM()
{
// Use the entrypoint of the current VM.
HINSTANCE hMod = ::GetModuleHandle("msjava");
if(hMod == NULL)
hMod = ::GetModuleHandle("jvm");
if(hMod == NULL)
hMod = ::GetModuleHandle("javai");
pJNI_GetCreatedJavaVMs pFunc = (pJNI_GetCreatedJavaVMs)::GetProcAddress(hMod,"JNI_GetCreatedJavaVMs");
return pFunc;
}
// This helper is the one that actually invokes the java JFrameEx's notifyMouseWheel method
void notifyMouseWheel(jobject frame,short fwKeys,short zDelta,long xPos, long yPos)
{
HMODULE hMod = NULL;
JavaVM *vmBuf = NULL;
JNIEnv *pEnv = NULL;
jsize bufLen = 1;
jint nVMs = 0;
// Get the Java VM.
pJNI_GetCreatedJavaVMs pFunc = getJavaVM();
jint nRet = (*pFunc)(&vmBuf,bufLen,&nVMs);
// Attach this thread.
vmBuf->AttachCurrentThread((void **)&pEnv,NULL);
// Inform the java object that the child has been created.
jclass cls = pEnv->GetObjectClass(frame);
jmethodID mid = pEnv->GetMethodID(cls, "notifyMouseWheel", "(SSJJ)V");
if (mid == 0)
return;
pEnv->CallVoidMethod(frame, mid, (jshort)fwKeys, (jshort)zDelta, (jlong)xPos, (jlong)yPos);
// Detach this thread.
vmBuf->DetachCurrentThread();
}
// Helper Thread for notification.
void WINAPIV StartNotifyThread(LPVOID lpVoid)
{
MSG *pMsg = (MSG *)lpVoid;
// This is the java object that needs to be notified.
jobject frame = getFrame(pMsg->hwnd);
// extract info from the wparam and lparam.
WPARAM fwKeys = LOWORD(pMsg->wParam);
short zDelta = HIWORD(pMsg->wParam);
LPARAM xPos = GET_X_LPARAM(pMsg->lParam);
LPARAM yPos = GET_Y_LPARAM(pMsg->lParam);
// call the helper function.
notifyMouseWheel(frame,fwKeys,zDelta,xPos,yPos);
delete pMsg;
}