How can i capture all user raised events in my application, is there any specific event which is parrent for all of user based(raised) events ?
eg :
mouse click,
key press,
etc.,
these all events are raised by user can i able to capture it under one method???
In one single method: yes.
You have to implement the DefWindowProc function, which handles all events and messages. Unfortunately, not just user generated events but all. But you should be able to filter those out easily.
Use the SetWindowsHookEx API to set up a thread-local WH_CALLWNDPROC hook. See the MSDN documentation for full details.
That will call a single function in your application for every message you receive from Windows.
If you're using Windows forms .NET, add the following to your main application form:
protected override void OnControlAdded(ControlEventArgs e)
{
e.Control.Click += new EventHandler(Control_Click);
e.Control.KeyDown += new KeyEventHandler(Control_KeyDown);
base.OnControlAdded(e);
}
void Control_KeyDown(object sender, KeyEventArgs e)
{
// Hande all keydown events, sender is the control
Debug.WriteLine( sender.ToString() + " - KeyDown");
}
void Control_Click(object sender, EventArgs e)
{
// Hande all click events, sender is the control
Debug.WriteLine(sender.ToString() + " - Click");
}
protected override void OnControlRemoved(ControlEventArgs e)
{
e.Control.KeyDown -= Control_KeyDown;
e.Control.Click -= Control_Click;
base.OnControlRemoved(e);
}
Just add any extra events you require (such as KeyPress, MouseEnter, MouseDown etc) in a similar manner. This is a bit cleaner and simpler then delving into the Windows API.
Related
I’m making a HoloLens 2 app using Unity and MRTK, I need to instantiate a gameObject in the coordinates of the user hand when the user performs an Air-tap gesture, I was trying to achieve this using IMixedRealityInputHandler, but the problem is that in order to detect the air-tap gesture, the user need to be pointing towards the gameObject that has the script to implements that interface attached,
Any idea about how can I detect the air-tap mid-air without the need of pointing something directly?
To listens for input events and disregarding what GameObject in focus, you can create a component registered global input handlers, more information please see:Register for global input events
To provide a more specific answer, I've provided test code below. This is based on the answer by Hernando.
...you can create a component registered global input handlers, more
information please see:Register for global input events
using Microsoft.MixedReality.Toolkit;
using Microsoft.MixedReality.Toolkit.Input;
using UnityEngine;
public class AirTapper : MonoBehaviour, IMixedRealityGestureHandler
{
private void OnEnable()
{
// Instruct Input System that we would like to receive all input events of type IMixedRealityGestureHandler
CoreServices.InputSystem?.RegisterHandler<IMixedRealityGestureHandler>(this);
}
private void OnDisable()
{
// Instruct Input System to disregard all input events of type IMixedRealityGestureHandler
CoreServices.InputSystem?.UnregisterHandler<IMixedRealityGestureHandler>(this);
}
public void OnGestureStarted(InputEventData eventData)
{
Debug.Log("Gesture started: " + eventData.MixedRealityInputAction.Description);
}
public void OnGestureUpdated(InputEventData eventData)
{
}
public void OnGestureCompleted(InputEventData eventData)
{
Debug.Log("Gesture completed: " + eventData.MixedRealityInputAction.Description);
}
public void OnGestureCanceled(InputEventData eventData)
{
}
}
I find it very difficult to find a simple reliable library to use, in Unity, for a simple websocket client. WebSocketSharp (ie, https://github.com/sta/websocket-sharp ) seems fine but many items are unexplained.
When incoming messages arrive,
wssharp_connection.OnMessage += (sender, e) =>
{
if (!e.IsText) { return; }
Debug.Log(">> OnMessage, " + e.Data);
Handle(e.Data);
// but wait, not the main Unity thread??
};
void Handle(string msg)
{
.. your conventional Unity call, in a monobehavior
}
Testing shows it seems to arrive on (always? sometimes?) not the main Unity thread.
Does anyone know
In fact is it always not the main thread, or can it vary?
If always another thread, in fact is it always the same one thread, or does it vary/many?
Since every single Unity app that uses a websocket client has to do this, I'm surprised that there are not 100s of discussion about how to handle incoming messages, including on the WebSocketSharp page,
but here's what I would do, just in the usual way you handle "threading" in a frame-based engine like Unity:
wssharp_connection.OnMessage += (sender, e) =>
{
if (!e.IsText) { return; }
incoming_messages.Enqueue(e.Data);
};
// and ...
ConcurrentQueue<string> incoming_messages = new ConcurrentQueue<string>();
void Update()
{
if (incoming_messages.TryDequeue(out var message))
{
Handle(message);
}
}
So then
Is that indeed the usual way to handle the threading problem in WebSocketSharp, when using inside Unity?
Given how many billion Unity apps there are with websockets clients, this must be a pretty well-trodden path.
I am using IResourceChangeListener to listen to changes in resource.
my code is:
public void createPartControl(Composite parent) {
// Graph will hold all other objects
graph = new Graph(parent, SWT.NONE);
// create the graph with the right nodes and connections.
init();
//listen to changes in the resource.
workspace = ResourcesPlugin.getWorkspace();
resourceChangeListener = new IResourceChangeListener() {
public void resourceChanged(IResourceChangeEvent event) {
//IResourceDelta delta = event.getDelta();
Display.getDefault().asyncExec(new Runnable() {
public void run() {
init();
System.out.println("Something changed!");
}
});
}
};
workspace.addResourceChangeListener(resourceChangeListener);
}
public void dispose() {
workspace.removeResourceChangeListener(resourceChangeListener);
}
But, when I am doing just one change in the resource, and save it, the listener called more than once! (usually twice, but sometimes even 6 times!!!)
I tried to use delta to see if it's called in the project,folder,file..
and I didn't saw differences between the calls (maybe I didn't used it properly).
I found this link, but I didn't found there solution to solve my problem
IResourceChangeListener being called twice with one change
How can I fix my code?
Thanks.
There is nothing you can do in the listener code to change how many resource change events you get. It depends entirely on how the code making the changes is doing the change.
You may find that IResourceDelta.getKind and IResourceDelta.getFlags return different values in the events. Also something getMovedFromPath and getMovedToPath for rename or move operations.
If it is your code doing the change you can use a WorkspaceJob or WorkspaceModifyOperation to do atomic changes to the workspace which will also reduce the number of resource change events.
You might also want to check that your old listeners are being removed correctly.
I have a mouse listener. It has some code to respond to mouseUp and mouseDown events. This works correctly.
However, as soon as I add a DragSource, my mouseDown event is no longer delivered -- until I release the mouse button!
This is trivial to reproduce - below is a simple program which contains a plain shell with just a mouse listener and a drag listener. When I run this (on a Mac), and I press and hold the mouse button, nothing happens - but as soon as I release the mouse button, I instantly see both the mouse down and mouse up events delivered. If I comment out the drag source, then the mouse events are delivered the way they should be.
I've searched for others with similar problems, and the closest I've found to an explanation is this:
https://bugs.eclipse.org/bugs/show_bug.cgi?id=26605#c16
"If you hook drag detect, the operating system needs to eat mouse events until it determines that you have either dragged or not."
However, I don't understand why that's true -- why must the operating system eat mouse events to determine if I have a drag or not? The drag doesn't start until I have a mouse -move- event with the button pressed.
More importantly: Can anyone suggest a workaround? (I tried dynamically adding and removing my drag source when the mouse is pressed, but then I couldn't get drag & drop to function properly since it never saw the initial key press - and I can't find a way to programmatically initiate a drag.)
Here's the sample program:
package swttest;
import org.eclipse.swt.dnd.DND;
import org.eclipse.swt.dnd.DragSource;
import org.eclipse.swt.dnd.DragSourceEvent;
import org.eclipse.swt.dnd.DragSourceListener;
import org.eclipse.swt.events.MouseEvent;
import org.eclipse.swt.events.MouseListener;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Shell;
public class SwtTest {
public static void main(String[] args) {
final Display display = new Display();
final Shell shell = new Shell(display);
shell.addMouseListener(new MouseListener() {
public void mouseUp(MouseEvent e) {
System.out.println("mouseUp");
}
public void mouseDown(MouseEvent e) {
System.out.println("mouseDown");
}
public void mouseDoubleClick(MouseEvent e) {
System.out.println("mouseDoubleClick");
}
});
DragSourceListener dragListener = new DragSourceListener() {
public void dragFinished(DragSourceEvent event) {
System.out.println("dragFinished");
}
public void dragSetData(DragSourceEvent event) {
System.out.println("dragSetData");
}
public void dragStart(DragSourceEvent event) {
System.out.println("dragStart");
}
};
DragSource dragSource = new DragSource(shell, DND.DROP_COPY | DND.DROP_MOVE);
dragSource.addDragListener(dragListener);
shell.pack();
shell.open();
while (!shell.isDisposed()) {
if (!display.readAndDispatch())
display.sleep();
}
display.dispose();
}
}
To answer your specific question about why this happens -- on Cocoa we don't consider a drag to have started until the mouse has moved a few pixels. This ensures against 'accidental' drags if you're sloppy with the clicks. On Linux and Win32 the window toolkit can do the drag detection. If you just hold down the button the detection times out and the mouse down is delivered. On Cocoa we have no time out, which is why nothing happens until the drag is detected or a mouse up happens.
That's a lot of detail, but the conclusion is that the behavior is inconsistent, and we should always be able to deliver the mouse down immediately, without waiting for the drag detection to complete.
I don't see a workaround, since this is happening before the Control sees the event.
See this bug which has patches for win32, gtk and cocoa SWT.
I had faced the same problem and found a solution. Once you attach a DragSource to your custom widget, the event loop will be blocked in that widget's mouse down hook and will eat mouse move events to detect a drag. (I've only looked into the GTK code of SWT to find this out, so it may work a little differently on other platforms, but my solution works on GTK, Win32 and Cocoa.) In my situation, I wasn't so much interested in detecting the mouse down event right when it happened, but I was interested in significantly reducing the drag detection delay, since the whole purpose of my Canvas implementation was for the user to drag stuff. To turn off the event loop blocking and built-in drag detection, all you have to do is:
setDragDetect(false);
In my code, I am doing this before attaching the DragSource. As you already pointed out, this will leave you with the problem that you can't initiate a drag anymore. But I have found a solution for that as well. Luckily, the drag event generation is pure Java and not platform specific in SWT (only the drag detection is). So you can just generate your own DragDetect event at a time when it is convenient for you. I have attached a MouseMoveListener to my Canvas, and it stores the last mouse position, the accumulated drag distance and whether or not it already generated a DragDetect event (among other useful things). This is the mouseMove() implementation:
public void mouseMove(MouseEvent e) {
if (/* some condition that tell you are expecting a drag*/) {
int deltaX = fLastMouseX - e.x;
int deltaY = fLastMouseY - e.y;
fDragDistance += deltaX * deltaX + deltaY * deltaY;
if (!fDragEventGenerated && fDragDistance > 3) {
fDragEventGenerated = true;
// Create drag event and notify listeners.
Event event = new Event();
event.type = SWT.DragDetect;
event.display = getDisplay();
event.widget = /* your Canvas class */.this;
event.button = e.button;
event.stateMask = e.stateMask;
event.time = e.time;
event.x = e.x;
event.y = e.y;
if ((getStyle() & SWT.MIRRORED) != 0)
event.x = getBounds().width - event.x;
notifyListeners(SWT.DragDetect, event);
}
}
fLastMouseX = e.x;
fLastMouseY = e.y;
}
And that will replace the built-in, blocking drag detection for you.
Which event from which widget should I catch when I need to run some code when ScrolledWindow is scrolled?
Ths widgets tree I am using is:
(my widget : Gtk.Container) > Viewport > ScrolledWindow
I tried many combinations of ScrollEvent, ScrollChild, etc. event handlers connected to all of them, but the only one that runs anything is an event from Viewport that about SetScrollAdjutstments being changed to (x=0,y=0) when the application starts.
You should attach to the GtkAdjustment living in the relevant scrollbar, and react to its "changed" event. Since Scrollbars are Ranges, you use the gtk_range_get_adjustment() call to do this.
unwind's answer was correct.
Just posting my code in case someone needs a full solution:
// in the xxx : Gtk.Container class:
protected override void OnParentSet(Widget previous_parent) {
Parent.ParentSet += HandleParentParentSet;
}
void HandleParentParentSet(object o, ParentSetArgs args) {
ScrolledWindow swn = (o as Widget).Parent as ScrolledWindow;
swn.Vadjustment.ValueChanged += HandleScrollChanged;
}
void HandleScrollChanged(object sender, EventArgs e) {
// vertical value changed
}
If you need to change the parent of any of those widgets, or may need to change the types and change the hardcoded types and handle disconnecting from the previous parent.