vtkInteractorObserver::GrabFocus method - c++

I'm new to VTK.
I was reading VTK sources and in Rendering/vtkInteractorStyleTrackballActor.cxx I found this method:
void vtkInteractorStyleTrackballActor::OnLeftButtonDown()
{
int x = this->Interactor->GetEventPosition()[0];
int y = this->Interactor->GetEventPosition()[1];
this->FindPokedRenderer(x, y);
this->FindPickedActor(x, y);
if (this->CurrentRenderer == NULL || this->InteractionProp == NULL)
{
return;
}
this->GrabFocus(this->EventCallbackCommand);
if (this->Interactor->GetShiftKey())
{
this->StartPan();
}
else if (this->Interactor->GetControlKey())
{
this->StartSpin();
}
else
{
this->StartRotate();
}
}
Can you explain what call
this->GrabFocus(this->EventCallbackCommand);
actually does?
In docs I found
void vtkInteractorObserver::GrabFocus(vtkCommand *mouseEvents,
vtkCommand *keypressEvents = NULL)
These methods enable an interactor observer to exclusively grab all events invoked by its associated vtkRenderWindowInteractor. (This method is typically used by widgets to grab events once an event sequence begins.) The GrabFocus() signature takes up to two vtkCommands corresponding to mouse events and keypress events. (These two commands are separated so that the widget can listen for its activation keypress, as well as listening for DeleteEvents, without actually having to process mouse events.)
But I don't really understand what they mean. Please give me some simple examples how this method is typically used.

Related

How do I assign a value in an array when a mouse is pressed SFML C++

I am trying to make a program where you are allowed to select between an option of shapes, and then drawing it. To allow for multiple shapes I created a vector of a class which creates shapes (Shapes are set up with the chosen function). My problem is the mouse click is too long, so it assigns it to everything in the vector, so you can't create a new shape. Is there a problem in my logic, or is there a problem in the code?
Here is my attempt:
for (auto& it : onCanvas) {
if (Mouse::isButtonPressed(Mouse::Left)) {
if (mousepointer.getGlobalBounds().intersects(circleOption.getGlobalBounds())) {
it.chosen(circles);
}
if (mousepointer.getGlobalBounds().intersects(rectOption.getGlobalBounds())) {
it.chosen(rectangle);
}
if (mousepointer.getGlobalBounds().intersects(triOption.getGlobalBounds())) {
it.chosen(triangles);
}
if (mousepointer.getGlobalBounds().intersects(it.shape.getGlobalBounds()) || it.dragging) {
it.shape.setPosition(mousepointer.getPosition());
it.dragging = true;
}
}
if (!Mouse::isButtonPressed) {
it.dragging = false;
}
win.draw(it.shape);
}
Your source-code is a bit incomplete (what is onCanvas and mousepointer). But I guess the problem is that this snippet is called multiple times while your mouse is clicked. To avoid that you can do two thing.
In the first solution you use events, so you only add shapes when the state of the mousebutton changes (you can additionally listen to the MouseButtonReleased to simulate a full click):
if (event.type == sf::Event::MouseButtonPressed)
{
if (event.mouseButton.button == sf::Mouse::Left)
{
// Hit Detection
}
}
or second solution you remember the last state of the button (probably do the mouse check once outside of the for loop):
bool mouse_was_up = true;
if (mouse_was_up && Mouse::isButtonPressed(Mouse::Left)) {
mouse_was_up = false;
for (auto& it : onCanvas) {
// Hit Detection
}
}
else if (!Mouse::isButtonPressed(Mouse::Left))
mouse_was_up = true;
I would rather stick to the first solution because when your click is too short and your gameloop is in another part of the game logic, you can miss the click.

How to make a loading screen state transition to game level state?

I am trying to make my basic loading screen transition over to game level screen. So what i wanted to do is, once the loading screen is active (or has appeared onscreen), I want at this point to start loading my game state. What it is doing at the moment is loading everything at the start, and this does take a while.
So currently my project starts off with a main menu. Then when i press enter, its starts the loading screen. I have my manual state change using keypresses like so:
void Game::update()
{
static bool enterPreviouslyPressed = false;
static bool escapePreviousPressed = false;
const Uint8 *keys = SDL_GetKeyboardState(NULL);
if (keys[::SDL_SCANCODE_ESCAPE] && !escapePreviousPressed && typeid(*fsm->getState()) == typeid(GameState))
{
fsm->setState(menuState);
}
else if (keys[::SDL_SCANCODE_RETURN] && !enterPreviouslyPressed && typeid(*fsm->getState()) == typeid(MainMenuState))
{
fsm->setState(loadingState);
}
else if ((keys[::SDL_SCANCODE_RETURN] && !enterPreviouslyPressed) && typeid(*fsm->getState()) == typeid(LoadScreenState))
{
fsm->setState(gameState);
}
else if (keys[::SDL_SCANCODE_ESCAPE] && !escapePreviousPressed && typeid(*fsm->getState()) == typeid(MainMenuState))
{
exit(0);
}
enterPreviouslyPressed = keys[::SDL_SCANCODE_RETURN] != 0;
escapePreviousPressed = keys[::SDL_SCANCODE_ESCAPE] != 0;
fsm->update();
}
I did this to initially does this so i could change states manually to check that everything works. I was wondering if there was an easy(ish) way, like boolean flags for example or another simpler way to do this. I wasn't able find any tutorials online so wondering if someone knows the best solution as to how to do this. I did see a question on here, kindda similar but I wasn't sure if it answered my question as the person did this in threads which I am not familiar with how to implement. Apologies if I dont seem to have the logic correct - so please advise otherwise.
Looks fairly standard, except I would simplify it by keeping two keyboard state variables declared as class variables, like:
const Uint8 *curKeys = SDL_GetKeyboardState(NULL), *prevKeys;
// ...
void Game::update() {
prevKeys = curKeys;
curKeys = = SDL_GetKeyboardState(NULL);
//and so then compare curKeys to prevkeys
//and ditch the booleans
// ...
}

Delete Key is not triggering KeyUp & KeyDown Event

I am currently dealing with a multi-form application and am having issue registering a del key press, the application that requires the del key is a form with a frame on it with objects painted on it that can be selected, upon pressing the del key the selected objects are to be deleted via a deleteObjects method. The code I am currently using is as follows
void __fastcall TF_Image::KeyUpKbd( WORD &Key )
{
if(Key == VK_DELETE || Key == VK_DKEY)
{
deleteSelectedObjects();
}
}
(Note: There are other paramenters in the function call but they aren't used)
TF_Image inherits from TFrame
I have tried mapping other keys other than the del key ie the D key and have found that the method is called with no problem. I have discovered that when pressing (physically) the del key the methods associated with KeyUp & KeyDown are not called.
Edit: So i've attempted to add the DeleteSelectedOb() method to my WndProc method without much luck either.
void __fastcall TF_ImgBrowserOA::WndProc(TMessage &Message)
{
if (Message.Msg == WM_KEYDOWN)
{
if (Message.WParam == VK_DELETE)
{
F_Image->DeleteSelectedOb();
}
}
//code that manages window resize
TForm::WndProc(Message);
}
The WndProc method doent appear to respond to keystrokes
So after cleaning up some code in some other modules and removing unneccessary menu's I decided to go back and look at this section again after I found a similar piece of code implementing a similar function, I couldn't see much difference between them and so I recompiled and attempted to run my Delete function from the KeyDown event and for some reason it just worked, I suspect it came down to an issue of another element holding focus in the Application. As a precaution I also called a SetFocus() to the frame in which I required this code to operate in. Its still a mystery to me why this didn't work intially though.
Here is a snippet for my TRichEdit control (Script_Edit).
TWndMethod *PrevWndProc = Script_Edit->WindowProc;
Script_Edit->WindowProc = MyWndProc;
void __fastcall My_Form::MyWndProc(TMessage &Message) {
switch (Message.Msg) {
case WM_KEYDOWN: {
// Check for DELETE and BACKSPACE keys
if( Message.WParam == VK_BACK ||
Message.WParam == VK_DELETE
) {
// Do whatever you need
}
break;
default:
// call default handler if not processed
PrevWndProc(Message);
}
}
You can't get much closer to the message core than this with VCL...

Mac event tap just delays discarded events

I'm trying to write some code that discards all keyboard and mouse events when enabled on Mac OSX 10.6. My code runs as the root user. The approach I'm taking is to create an event tap that discards all events passed to it (while enabled). The event tap callback function looks like this:
CGEventRef MyTapCallback(CGEventTapProxy proxy,
CGEventType type,
CGEventRef event,
void *refcon)
{
return CKeyLocker::isEnabled() ? NULL : event;
}
And the code I'm using to enable and disable the event tap looks like this:
void CKeyLocker::enable(bool bEnable)
{
if (bEnable == m_bEnabled)
return;
if (bEnable)
{
// which events are we interested in?
CGEventMask evMask = kCGEventMaskForAllEvents;
CFMachPortRef mp = CGEventTapCreate(kCGHIDEventTap,
kCGHeadInsertEventTap,
kCGEventTapOptionDefault,
evMask,
MyTapCallback,
NULL);
if (mp)
{
qDebug() << "Tap created and active. mp =" << mp;
m_enabledTap = mp;
m_bEnabled = true;
}
}
else
{
CGEventTapEnable(m_enabledTap, false);
CFRelease(m_enabledTap);
m_enabledTap =0;
m_bEnabled = false;
qDebug() << "Tap destroyed and inactive";
}
}
This approach works very well while the event tap is active - I can hammer on the keyboard and mouse as much as I want and no events make it through the system. However, when the tap is disabled all the keys I pushed while the tap was active appear in the current window. It's like the event tap is just delaying the events, rather than destroying them, which is odd, since the Mac documentation clearly states:
If the event tap is an active filter, your callback function should return one of the following:
The (possibly modified) event that is passed in. This event is passed back to the event system.
A newly-constructed event. After the new event has been passed back to the event system, the new event will be released along with the original event.
NULL if the event passed in is to be deleted.
I'm returning NULL, but the event doesn't seem to be deleted. Any ideas?
The linked comment does not have an answer from what I see, so I'll dump some info from what I've seen when poking around with this stuff.
First, I have much better luck with CGEventTapCreateForPSN. It's as if the system gives you some leeway for restricting your tap. However, from this example it looks like this is not sufficient.
Next up - and this /may/ be all you need... In your call back, you probably want (and may need) to check for the following events:
switch (type)
{
case kCGEventTapDisabledByTimeout:
case kCGEventTapDisabledByUserInput:
{
CFMachPortRef *pTap = (CFMachPortRef*)refcon;
CGEventTapEnable( *pTap, true );
return NULL;
}
default:
break;
}
Regardless of what the various documentation does or doesn't say, it's been my observation that the OS feels like it's 'probing' for bad callbacks; basically disabling event tap callbacks that are universally eating events. If you re-register in these cases the OS seems to be ok with it, as if saying: OK, you seem to know what you're doing, but I'll probably poke you again in a bit to make sure.
It's really strange, we use event taps for the same purpose (input blocking in a given scenario) and works perfectly 10.4 - 10.8.2. excpet one thing, it should not block or receive events from a password dialog (which is not a big surprise)
What I can see now is different compared to you sample is:
we use kCGTailAppendEventTap instead of kCGHeadInsertEventTap (this should not matter)
we do some event logging in the installed callback
we have some user event data in some self injected events, that filtered out, but apart from this we simply return NULL to drop an unwanted event (like you do), I can confirm, not all events are ignorable!
we turn on/off the event tap this way:
bool SetInputFilter(bool bOn)
{
bool result = false;
CFRunLoopRef runLoopRef = CFRunLoopGetMain();
if (bOn) {
// Create an event tap.
CGEventMask eventMask = kCGEventMaskForAllEvents;
if ((m_eventTapInput = CGEventTapCreate(kCGHIDEventTap,
kCGTailAppendEventTap,
kCGEventTapOptionDefault,
eventMask, CGInputEventCallback, this)) == NULL) {
Log(L"Failed to create event tap");
return result;
}
// Create a run loop source.
m_runLoopEventTapSource = CFMachPortCreateRunLoopSource(kCFAllocatorDefault, m_eventTapInput, 0);
CFRelease(m_eventTapInput); // CFMachPortCreateRunLoopSource retains m_eventTapInput
if (m_runLoopEventTapSource == NULL) {
Log(L"Failed to create run loop source for event tap");
return result;
}
// Add to the current run loop.
CFRunLoopAddSource(runLoopRef, m_runLoopEventTapSource, kCFRunLoopCommonModes);//kCFRunLoopDefaultMode);
CFRelease(m_runLoopEventTapSource); // CFRunLoopAddSource retains m_runLoopEventTapSource
result = true;
}
else {
// Disable the event tap.
if (m_eventTapInput)
CGEventTapEnable(m_eventTapInput, false);
// Remove our run loop source from the current run loop.
if (runLoopRef && m_runLoopEventTapSource) {
CFRunLoopRemoveSource(runLoopRef, m_runLoopEventTapSource, kCFRunLoopCommonModes);//kCFRunLoopDefaultMode);
m_runLoopEventTapSource = NULL; // removing m_runLoopEventTapSource releases last reference of m_runLoopEventTapSource too
m_eventTapInput = NULL; // removing m_runLoopEventTapSource releases last reference of m_eventTapInput too
}
}
return result;
}
I can verify that returning NULL does effectively delete some events, but i have also seen times when it does not, exactly how it decides what deletions to permit is unclear but it looks like mass deletions seem to be prevented e.g.: when you delete more than 100 events or so in a row.

How to catch Ctrl+C key event with Qt when Ctrl is released before 'C'?

I would like to call some custom copy code when the user releases Ctrl+C. When C is released before Ctrl, Qt sends a key event that matches with QKeySequence::Copy. When Ctrl is released before C, the release event does not match.
When the key release event comes in with Ctrl, is there a way to see if C is still being held down?
When I don't handle Ctrl being released first, the event gets passed along and it does a regular copy, which is exactly what I don't want to happen.
bool
MyWidget::eventFilter(QObject* object, QEvent* event)
{
// the text edit box filters its events through here
if (object == m_text_edit_box)
{
if (event->type() == QEvent::KeyPress)
{
QKeyEvent *key_event = static_cast<QKeyEvent*>(event);
if (key_event->matches(QKeySequence::Copy))
{
// don't do anything and don't pass along event
return true;
}
}
else if (event->type() == QEvent::KeyRelease)
{
QKeyEvent *key_event = static_cast<QKeyEvent*>(event);
if (key_event->matches(QKeySequence::Copy))
{
// we only get in here if 'c' is released before ctrl
callCustomCopy();
return true;
}
}
}
// pass along event
return false;
}
You could query the letter 'C' and the meta key Ctrl specifically and not rely on key_even->matches(). you can of course in the object where you located the eventfilter on the keydown event store the fact wether the keydown sequence did match copy.
This (untested) might work for you, note that the static variable should be a member variable of the class that this is contained in, this just seemed clearer in the context of this example. The exact logic of what you want to accomplish might need more state information to be carried between events.
bool MyWidget::eventFilter(QObject* object, QEvent* event)
{
// Remember state between events
static foundCopy = false;
// the text edit box filters its events through here
if (object == m_text_edit_box)
{
if (event->type() == QEvent::KeyPress)
{
QKeyEvent *key_event = static_cast<QKeyEvent*>(event);
if (key_event->matches(QKeySequence::Copy))
{
foundCopy = true;
// don't do anything and don't pass along event
return true;
}
else
{
foundCopy = false;
// This is another sequence, ignore and pass event
// Note that this will trigger with ctrl+c+a and others
}
}
else if (event->type() == QEvent::KeyRelease)
{
QKeyEvent *key_event = static_cast<QKeyEvent*>(event);
if (foundCopy)
{
callCustomCopy();
foundCopy = false;
return true;
}
// This should keep the system copy from triggering
if (key_event->matches(QKeySequence::Copy))
{
return true;
}
}
}
// pass along event
return false;
}
Another way would be to collect the actual state of all the keys pressed at the current time and then when one is released see which ones are still pressed.
From a UI point of view please bear in mind that all keyboard actions are performed on press, (e.g. typeing, windows paste), performing actions on release in general might confuse the user, especially when there is a visible result to the action. I can't tell from your example what you are trying to accomplish.