Click here to Skip to main content
15,892,005 members
Articles / Programming Languages / Java / Java SE

Add Mouse Wheel support to Swing Widgets

Rate me:
Please Sign up or sign in to vote.
3.44/5 (14 votes)
2 Jul 2000 166.7K   1.4K   22  
This article shows how to add support for Mouse Wheel for Java Swing Widgets
///////////////////////////////////////////////////////////////////////////////
// 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;
}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.


Written By
United States United States
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions