I am using the "DirectX 11 and XAML App (Universal Window)" template in vs2015. I want to get user's keystroke in every frame. So I tried to put GetAsyncKeyState() inside of the render-loop. The render-loop is running in a separate thread:
auto workItemHandler = ref new WorkItemHandler([this](IAsyncAction ^ action)
{
// Calculate the updated frame and render once per vertical blanking interval.
while (action->Status == AsyncStatus::Started)
{
critical_section::scoped_lock lock(m_criticalSection);
Update();
m_sceneRenderer->OnKeyDown();
if (Render())
{
m_deviceResources->Present();
}
}
});
// Run task on a dedicated high priority background thread.
m_renderLoopWorker = ThreadPool::RunAsync(workItemHandler, WorkItemPriority::High, WorkItemOptions::TimeSliced);
m_sceneRenderer->OnKeyDown() is where I put GetAsyncKeyState(). But whenever I put m_sceneRenderer->OnKeyDown() inside the while loop, all the DirectX content will not be rendered. Also, m_renderLoopWorker will be nullptr and throw an exception when I close the application.
// Sample3DSceneRenderer.h, truncated
namespace UWP_DX11_XAML_
{
class Sample3DSceneRenderer
{
Sample3DSceneRenderer(Windows::UI::Core::CoreWindow^ window);
void OnKeyDown();
Platform::Agile<Windows::UI::Core::CoreWindow^> m_window;
}
}
// Sample3DSceneRenderer.cpp, truncated
UWP_DX11_XAML_::Sample3DSceneRenderer::Sample3DSceneRenderer(
Windows::UI::Core::CoreWindow^ window):
m_window(window)
{
}
void UWP_DX11_XAML_::Sample3DSceneRenderer::OnKeyDown()
{
m_window.Get()->GetAsyncKeyState(Windows::System::VirtualKey::Control);
}
Calling other member functions of m_window can cause the same problem.
You may wish to setup a dedicated input thread using CreateCoreIndependentInputSource(CoreInputDeviceTypes::Mouse | CoreInputDeviceTypes::Touch | CoreInputDeviceTypes::Pen);
There's a sample here which demonstrates this option: https://github.com/Microsoft/Windows-universal-samples/tree/master/Samples/LowLatencyInput
I also found these similar articles which discuss optimizing for low input latency.
https://learn.microsoft.com/en-us/windows/uwp/gaming/optimize-performance-for-windows-store-direct3d-11-apps-with-coredispatcher
https://blogs.windows.com/buildingapps/2013/12/18/optimizing-directx-apps-for-low-latency-input-and-longer-battery-life/#JPGhHjXExbySmTf7.97
Related
In my current LWJGL application I am using the GLFW window input handler which I have set up a class to handle called Keyboard.java which extends GLFWKeyCallback. I have correctly set up my keyboard input class but when I click on a key if i do not click if fast enough (very quickly) then it registers as multiple clicks. I have presented some documentation below:
Keyboard Class
public class Keyboard extends GLFWKeyCallback {
//Variables
public static boolean keys[] = new boolean[65536];
#Override
public void invoke(long window, int key, int scancode, int action, int mods) {
keys[key] = action == GLFW_PRESS;
}
}
Implementation
public static void handleInput() {
if (Keyboard.keys[GLFW_KEY_SPACE]) {
System.out.println("Space");
glfwPollEvents();
}
}
The above method is implemented in the main game loop and is called once a frame.
Result
Initialised LWJGL Version: 3.1.2 build 29
Space
Space
Space
Space
The above: "Space" should be outputted every time that I click space but when I click it relatively fast, Then i get the above result of many "spaces".
Conclusion: Is it possible for a click of space to be registered only once no matter how long you hold it. Thanks
In your handleInput() function, you are testing to see if Keyboard.keys[GLFW_KEY_SPACE] is true, and if it is, you execute the statement. The problem is that this test only becomes false when you stop hitting space, which could take seconds to happen.
My suggestion: once you tested for Keyboard.keys[GLFW_KEY_SPACE], make it false.
public static void handleInput() {
if (Keyboard.keys[GLFW_KEY_SPACE]) {
Keyboard.keys[GLFW_KEY_SPACE] = false;
System.out.println("Space");
glfwPollEvents();
}
}
I have an OpenGL project which loads an object file, after the object is loaded i want to be able to move it with keyboard smoothly, so i wrote this block of code to do the job:
while (remains) {
if (x_remains) {
refPosition[0] += speed.x;
if (refPosition[0] > nextPos[0]) {
x_remains = false;
}
}
if (y_remains) {
refPosition[1] += speed.y;
if (refPosition[1] > nextPos[1]) {
y_remains = false;
}
}
if (z_remains) {
refPosition[2] += speed.z;
if (refPosition[2] >= nextPos[2]) {
z_remains = false;
}
}
remains = x_remains || y_remains || z_remains;
glutPostRedisplay();
}
as you see I want to redisplay the scene in the while but when this is executed glutpostredisplay() just sets a flag and the scene is redrawn in the next iteration of the mainloop. my question is how can I redraw the scene before next loop of the while and before the function returns
You won't lose performance or see jerky rendering by going through glutPostRedisplay instead of drawing directly. (Or, if every microsecond really is that precious, why the heck are you using GLUT to begin with?)
On some systems you CAN'T draw outside the display function anyway, because the GL context won't be valid.
This is not unique to GLUT either. All the modern graphics/GUI toolkits I'm familiar with also require you to have a designated display function that gets invoked by an event handler, whether it's WM_PAINT messages, NSView drawRect:, or whatever.
If your program is not updating smoothly, it will be for some other reason.
I have a shape class in which there is a method (hitTest(int,int)) that continuously checks if the mouse is inside its bounds or not. In another method, I keep on checking if the mouse has stayed there for more than 1 sec.
If it has, trigger a function (by notification/event) that runs animation
It it has not, then don't trigger the animation
If it has already triggered the animation and the animation is running but the mouse leaves the area during this, trigger an interrupt function (by notification/event)
//OnLoad _initHover = false;
void update() //called continously in the application per frame
{
if(hitTest(getMouseX(), getMouseY())){
if(!_initHover){
_initHover = true;
_hoverStartTime = getCurrentTime(); //start hover time
cout<<"Start hist test\n";
}
//If it has hovered over the video for 1.0 sec
if((ofGetElapsedTimef() - _hoverStartTime) > 1.0){
cout<<"Hitting continously for 1 sec\n";
notificationCenter->postNotification(new AnimationStartNotification);
}
}
else{
_initHover = false;
notificationCenter->postNotification(new AnimationInterruptNotification);
}
}
The above code runs fine but there's a logical issue I am facing while trying to use. There are multiple instances of the above Shape class and each class consequently has their update() method as well. The mouse cursor has which has animationStarthandler and animationStophandlers is a single class in the whole application.
Issue 1: So, even when one of the shape just notifies the animationStarthandler to fire, the other shape classes on which hit test is false set the animation to interrupt and the animation does not run.
Issue 2: When the hit test succeeds and the cursor has been in the area for more than 1 sec, the hit test will keep on sending the notification to start the animation (anim's duration 1.5 sec approx.) How do I restrict the hit test to fire the animation only once and keep on firing the same animation again and again?
If in the main method of my application, I directly try to fire the animation by calling the method playAnimation in the pointer class, I get the required result. But I want to give this hover timing and animation functionality to the ShapeClass itself. Any suggestions?
I think that you should consider adding a new boolean, which holds the information of the triggering of the animation (called in the code sample _animationTriggered). This prevents shapes that have not triggered the animation to stop it and the animation that triggered it to make it several times.
if(hitTest(getMouseX(), getMouseY()))
{
if(!_initHover)
{
_initHover = true;
_hoverStartTime = getCurrentTime();
cout<<"Start hist test\n";
}
if((ofGetElapsedTimef() - _hoverStartTime) > 1.0)
{
if (!_animationTriggered)
{
cout<<"Hitting continously for 1 sec\n";
notificationCenter->postNotification(new AnimationStartNotification);
_animationTriggered = true;
}
}
}
else
{
if ( _animationTriggered )
{
_initHover = false;
notificationCenter->postNotification(new AnimationInterruptNotification);
_animationTriggered = false;
}
}
Don't forget to initialie this new boolean in the same place as _initHover
I'd like to know more about how this system works, specifically when and how the framework actually decides to update a UI element.
My application has a 'tools' system where a single tool can be active at a time. I used the "ON_UPDATE_COMMAND_UI" message to 'check' the tool's icon/button in the UI, which affected both the application menu and the toolbars. Anyway, this was all working great until some point in the last couple of days, when the toolbar icons stopped getting highlighted properly.
I investigated a little and found that the update command was only being received when the icon was actually clicked. What's strange is this is only affecting the toolbars, not the menu, which is still working fine. Even when the buttons in the menu are updated the toolbar icon stays the same.
Obviously I've done something to break it - any ideas?
EDIT:
Never mind. I'd overwritten the Application's OnIdle() method and hadn't called the original base class method - that is, CWinApp::OnIdle() - which I guess is where the update gets called most of the time. This code snippet from https://msdn.microsoft.com/en-us/library/3e077sxt.aspx illustrates:
BOOL CMyApp::OnIdle(LONG lCount)
{
// CWinApp's original method is involved in the update message handling!
// Removing this call will break things
BOOL bMore = CWinApp::OnIdle(lCount);
if (lCount == 0)
{
TRACE(_T("App idle for short period of time\n"));
bMore = TRUE;
}
// ... do work
return bMore;
// return TRUE as long as there are any more idle tasks
}
Here's a good article that kinda explains how to do it. Don't use his code example with WM_KICKIDLE though, instead scroll down to the comments section. There are two code samples that explain how to do it better. I quote:
//Override WM_INITMENUPOPUP
void CDialog::OnInitMenuPopup(CMenu* pPopupMenu, UINT nIndex, BOOL bSysMenu)
{
CDialog::OnInitMenuPopup(pPopupMenu, nIndex, bSysMenu);
// TODO: Add your message handler code here
if(pPopupMenu &&
!bSysMenu)
{
CCmdUI CmdUI;
CmdUI.m_nIndexMax = pPopupMenu->GetMenuItemCount();
for(UINT i = 0; i < CmdUI.m_nIndexMax; i++)
{
CmdUI.m_nIndex = i;
CmdUI.m_nID = pPopupMenu->GetMenuItemID(i);
CmdUI.m_pMenu = pPopupMenu;
// There are two options:
// Option 1. All handlers are in dialog
CmdUI.DoUpdate(this, FALSE);
// Option 2. There are handlers in dialog and controls
/*
CmdUI.DoUpdate( this, FALSE );
// If dialog handler doesn't change state route update
// request to child controls. The last DoUpdate will
// disable menu item with no handler
if( FALSE == CmdUI.m_bEnableChanged )
CmdUI.DoUpdate( m_pControl_1, FALSE );
...
if( FALSE == CmdUI.m_bEnableChanged )
CmdUI.DoUpdate( m_pControl_Last, TRUE );
*/
}
}
}
See if this helps - http://msdn.microsoft.com/en-us/library/essk9ab2(v=vs.80).aspx
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.