Management inputs Mouse with DirectX DirectInput - c++

I try to use DirectX Input to manage input mouse. But when I try to get X and Y coordinates of my mouse, values are incorrect (negative or seem to be random).
I show you the code that I used :
bool System::frame()
{
bool result;
if (input->isButtonDown(BUTTON_L)) //if left button is down
{
result = ReadMouse();
if(!result)
return false;
ProcessInput();
}
}
bool System::ReadMouse()
{
HRESULT result;
//this->mouseState is a DIMOUSESTATE ; this->mouse is a LDIRECTINPUTDEVICE8
result = this->mouse->GetDeviceState(sizeof(DIMOUSESTATE), (LPVOID)&this->mouseState);
if(FAILED(result))
{
if((result == DIERR_INPUTLOST) || (result == DIERR_NOTACQUIRED))
this->mouse->Acquire();
else
return false;
}
return true;
}
void System::ProcessInput()
{
this->mouseX = this->mouseState.lX;
this->mouseY = this->mouseState.lY;
if(this->mouseX < 0)
this->mouseX = 0;
if(this->mouseY < 0)
this->mouseY = 0;
if(this->mouseX > this->ScreenWidth)
this->mouseX = this->ScreenWidth;
if(this->mouseY > this->ScreenHeight)
this->mouseY = this->ScreenHeight;
return;
}
My last test give this->mouseX = -657 and this->mouseY = -36 instead of 200 and 200 (approximately). I check the function when I initialize the mouse, they seem to works (I followed a tutorial).

I think the reason is that DirectInput gives you relative data for the position of the mouse.
Please see: http://msdn.microsoft.com/en-us/library/windows/desktop/ee418272(v=vs.85).aspx for an explanation of how to interpret data from mouse and how to switch to absolute mode.
It is recommended to use the Raw Input API instead of DirectInput.
(http://msdn.microsoft.com/en-us/library/windows/desktop/ms645536(v=vs.85).aspx)

Related

How can I optimize Astar for vast empty spaces?

I am creating a game with a 3D grid for flying entities, So I have a lot of points and connections in the air where there aren't any obstructions. I didn't want to decrease the resolution of my grid so I thought I could just skip over chunks (or empties as I call them) of the Astar map while they're not containing any obstructions, and I modified Godot's Astar algorithm to do this.
Unfortunately this ended up being slower than looping through points one at a time due to the way I implemented this modification, which needs to loop through all the edge points of an empty.
2D representation of how one edge point of an empty connects to all other edge points:
This ends up looping through a larger number of points than letting the A* algorithm work it's way through the empty.
So I'm sorta stumped on how to make this more efficient while still preserving the most optimal path.
I could potentially narrow down what faces of the empty should be scanned over by first comparing the center points of all 8 faces of the empty (as my grid consists of hexagonal prisms). Or maybe I should somehow use the face center points of the empty's faces exclusively instead of all edge points.
I mainly want to know if anyone has worked on an issue like this before, and if so what would be the recommended solution?
Here is the astar loop for reference:
bool AStar::_solve(Point *begin_point, Point *end_point, int relevant_layers) {
pass++;
//make sure parallel layers are supported
// or if *relevant_layers is 0 then use all points
bool supported = relevant_layers == 0 || (relevant_layers & end_point->parallel_support_layers) > 0;
if (!end_point->enabled || !supported) {
return false;
}
bool found_route = false;
Vector<Point *> open_list;
SortArray<Point *, SortPoints> sorter;
begin_point->g_score = 0;
begin_point->f_score = _estimate_cost(begin_point->id, end_point->id);
open_list.push_back(begin_point);
while (!open_list.empty()) {
Point *p = open_list[0]; // The currently processed point
if (p == end_point) {
found_route = true;
break;
}
sorter.pop_heap(0, open_list.size(), open_list.ptrw()); // Remove the current point from the open list
open_list.remove(open_list.size() - 1);
p->closed_pass = pass; // Mark the point as closed
//if the point is part of an empty, look through all of the edge points of said empty (as to skip over any points within the empty).
OAHashMap<int, Point*> connections;
PoolVector<Empty*> enabled_empties;
int size = p->empties.size();
PoolVector<Empty*>::Read r = p->empties.read();
for (int i = 0; i < size; i++) {
Empty* e = r[i];
supported = relevant_layers == 0 || (relevant_layers & e->parallel_support_layers) > 0;
//if the empty is enabled and the end point is not within the empty
if (e->enabled && supported && !end_point->empties.has(e)) {
enabled_empties.append(e);
//can travel to any edge point
for (OAHashMap<int, Point*>::Iterator it = e->edge_points.iter(); it.valid; it = e->edge_points.next_iter(it)) {
int id = *it.key;
Point* ep = *(it.value);
ep->is_neighbour = false;
//don't connect to the same point
if (id != p->id && (i == 0 || !connections.has(id))) {
connections.set(id, ep);
}
}
}
}
//add neighbours to connections
for (OAHashMap<int, Point*>::Iterator it = p->neighbours.iter(); it.valid; it = p->neighbours.next_iter(it)) {
int id = *it.key;
Point* np = *(it.value);// The neighbour point
np->is_neighbour = true;
//don't need to check for duplicate point connections if no empties
if (size == 0 || !connections.has(id)) {
//don't add points within enabled empties since they're meant to be skipped over
if (np->empties.size() > 0 && !np->on_empty_edge) {
bool in_enabled_empty = false;
PoolVector<Empty*>::Read r1 = np->empties.read();
for (int i = 0; i < np->empties.size(); i++) {
if (enabled_empties.has(r1[i])) {
in_enabled_empty = true;
break;
}
}
if (!in_enabled_empty) {
connections.set(id, np);
}
}
else {
connections.set(id, np);
}
}
}
for (OAHashMap<int, Point *>::Iterator it = connections.iter(); it.valid; it = connections.next_iter(it)) {
Point *e = *(it.value); // The neighbour point
//make sure parallel layers are supported
// or if *relevant_layers is 0 then use all points
supported = relevant_layers == 0 || (relevant_layers & e->parallel_support_layers) > 0;
if (!e->enabled || e->closed_pass == pass || !supported) {
continue;
}
real_t tentative_g_score = p->g_score + _compute_cost(p->id, e->id) * e->weight_scale;
bool new_point = false;
if (e->open_pass != pass) { // The point wasn't inside the open list.
e->open_pass = pass;
open_list.push_back(e);
new_point = true;
} else if (tentative_g_score >= e->g_score) { // The new path is worse than the previous.
continue;
}
e->prev_point = p;
e->prev_point_connected = e->is_neighbour;
e->g_score = tentative_g_score;
e->f_score = e->g_score + _estimate_cost(e->id, end_point->id);
if (new_point) { // The position of the new points is already known.
sorter.push_heap(0, open_list.size() - 1, 0, e, open_list.ptrw());
} else {
sorter.push_heap(0, open_list.find(e), 0, e, open_list.ptrw());
}
}
}
return found_route;
}
Note: I'm still not exactly sure what the sorter does.
the entire code can be seen here in a_star.cpp and a_star.h
Edit:
if anyone wants to reference or use this, I've modified the Astar code to add user-defined octants and to use a user-defined straight line function (they are user-defined so they can work with any type of grid) to be used between octants when possible to further decrease runtime, and it works very well in terms of speed. Though the pathing is not optimal, especially when adding a lot of obstacles/restricting the available positions.

xlib XNextEvent checking if a key is held down

I am using xlib to get keyboard input I want to simulate windows its getAsynckeystate() to check if a button is being pressed I tried using a timer to fix the result but its still broken. the function should always return true if 'z' is held down even if other keys are pressed or released at the same time (not working right now)
Code below
bool KeyboardState::keyPressed(Display* d, Window curFocus,int revert, Window root) {
XEvent ev;
XNextEvent(d, &ev);
clock_t startTime;
switch (ev.type) {
case FocusOut:
if (curFocus != root)
XSelectInput(d, curFocus, 0);
XGetInputFocus(d, &curFocus, &revert);
printf("New focus is %d\n", (int) curFocus);
if (curFocus == PointerRoot)
curFocus = root;
XSelectInput(d, curFocus, KeyReleaseMask | FocusChangeMask | KeyPressMask);
break;
case KeyPress:
ks = XLookupKeysym(&(ev.xkey), 0);
if (ks == XK_z) {
keyState = true;
startTime = clock();
}
break;
case KeyRelease:
if(ks == XK_z && startTime - clock() > 0){
ks = XLookupKeysym(&(ev.xkey), 0);
keyState = false;
}
}
return keyState;
}
n.m linked following function which is accepted as answer:
tronche.com/gui/x/xlib/input/XQueryKeymap.html
I wrote the following code snippet to help do keyboard shortcuts with multiple non-modifier keys e.g. super + up + right.
#include <X11/Xlib.h>
// Returns 0 if key is not down;
// A non-zero integer if it is down.
// targetString should be appropriate for XStringToKeysym.
int is_down(Display *dis, char *targetString)
{
char keys_return[32] = {0};
KeySym targetSym = XStringToKeysym(targetString);
KeyCode targetCode = XKeysymToKeycode(dis, targetSym);
int targetByte = targetCode / 8;
int targetBit = targetCode % 8;
int targetMask = 0x01 << targetBit;
XQueryKeymap(dis, keys_return);
return keys_return[targetByte] & targetMask;
}
I've posted a more complete example with compilation instructions on GitHub. You can find a complete list of key names in a file named X11/keysymdef.h; on my Arch computer it was at /usr/include/X11/keysymdef.h. I also found an example on the web as the second Google result for x11 keysymdef.

Pops / clicks when stopping and starting DirectX sound synth in C++ / MFC

I have made a soft synthesizer in Visual Studio 2012 with C++, MFC and DirectX. Despite having added code to rapidly fade out the sound I am experiencing popping / clicking when stopping playback (also when starting).
I copied the DirectX code from this project: http://www.codeproject.com/Articles/7474/Sound-Generator-How-to-create-alien-sounds-using-m
I'm not sure if I'm allowed to cut and paste all the code from the Code Project. Basically I use the Player class from that project as is, the instance of this class is called m_player in my code. The Stop member function in that class calls the Stop function of LPDIRECTSOUNDBUFFER:
void Player::Stop()
{
DWORD status;
if (m_lpDSBuffer == NULL)
return;
HRESULT hres = m_lpDSBuffer->GetStatus(&status);
if (FAILED(hres))
EXCEP(DirectSoundErr::GetErrDesc(hres), "Player::Stop GetStatus");
if ((status & DSBSTATUS_PLAYING) == DSBSTATUS_PLAYING)
{
hres = m_lpDSBuffer->Stop();
if (FAILED(hres))
EXCEP(DirectSoundErr::GetErrDesc(hres), "Player::Stop Stop");
}
}
Here is the notification code (with some supporting code) in my project that fills the sound buffer. Note that the rend function always returns a double between -1 to 1, m_ev_smps = 441, m_n_evs = 3 and m_ev_sz = 882. subInit is called from OnInitDialog:
#define FD_STEP 0.0005
#define SC_NOT_PLYD 0
#define SC_PLYNG 1
#define SC_FD_OUT 2
#define SC_FD_IN 3
#define SC_STPNG 4
#define SC_STPD 5
bool CMainDlg::subInit()
// initialises various variables and the sound player
{
Player *pPlayer;
SOUNDFORMAT format;
std::vector<DWORD> events;
int t, buf_sz;
try
{
pPlayer = new Player();
pPlayer->SetHWnd(m_hWnd);
m_player = pPlayer;
m_player->Init();
format.NbBitsPerSample = 16;
format.NbChannels = 1;
format.SamplingRate = 44100;
m_ev_smps = 441;
m_n_evs = 3;
m_smps = new short[m_ev_smps];
m_smp_scale = (int)pow(2, format.NbBitsPerSample - 1);
m_max_tm = (int)((double)m_ev_smps / (double)(format.SamplingRate * 1000));
m_ev_sz = m_ev_smps * format.NbBitsPerSample/8;
buf_sz = m_ev_sz * m_n_evs;
m_player->CreateSoundBuffer(format, buf_sz, 0);
m_player->SetSoundEventListener(this);
for(t = 0; t < m_n_evs; t++)
events.push_back((int)((t + 1)*m_ev_sz - m_ev_sz * 0.95));
m_player->CreateEventReadNotification(events);
m_status = SC_NOT_PLYD;
}
catch(MATExceptions &e)
{
MessageBox(e.getAllExceptionStr().c_str(), "Error initializing the sound player");
EndDialog(IDCANCEL);
return FALSE;
}
return TRUE;
}
void CMainDlg::Stop()
// stop playing
{
m_player->Stop();
m_status = SC_STPD;
}
void CMainDlg::OnBnClickedStop()
// causes fade out
{
m_status = SC_FD_OUT;
}
void CMainDlg::OnSoundPlayerNotify(int ev_num)
// render some sound samples and check for errors
{
ScopeGuardMutex guard(&m_mutex);
int s, end, begin, elapsed;
if (m_status != SC_STPNG)
{
begin = GetTickCount();
try
{
for(s = 0; s < m_ev_smps; s++)
{
m_smps[s] = (int)(m_synth->rend() * 32768 * m_fade);
if (m_status == SC_FD_IN)
{
m_fade += FD_STEP;
if (m_fade > 1)
{
m_fade = 1;
m_status = SC_PLYNG;
}
}
else if (m_status == SC_FD_OUT)
{
m_fade -= FD_STEP;
if (m_fade < 0)
{
m_fade = 0;
m_status = SC_STPNG;
}
}
}
}
catch(MATExceptions &e)
{
OutputDebugString(e.getAllExceptionStr().c_str());
}
try
{
m_player->Write(((ev_num + 1) % m_n_evs)*m_ev_sz, (unsigned char*)m_smps, m_ev_sz);
}
catch(MATExceptions &e)
{
OutputDebugString(e.getAllExceptionStr().c_str());
}
end = GetTickCount();
elapsed = end - begin;
if(elapsed > m_max_tm)
m_warn_msg.Format(_T("Warning! compute time: %dms"), elapsed);
else
m_warn_msg.Format(_T("compute time: %dms"), elapsed);
}
if (m_status == SC_STPNG)
Stop();
}
It seems like the buffer is not always sounding out when the stop button is clicked. I don't have any specific code for waiting for the sound buffer to finish playing before the DirectX Stop is called. Other than that the sound playback is working just fine, so at least I am initialising the player correctly and notification code is working in that respect.
Try replacing 32768 with 32767. Not by any means sure this is your issue, but it could overflow the positive short int range (assuming your audio is 16-bit) and cause a "pop".
I got rid of the pops / clicks when stopping playback, by filling the buffer with zeros after the fade out. However I still get pops when re-starting playback, despite filling with zeros and then fading back in (it is frustrating).

Output formatted text to Screen

I have a vector that stores pairs. Each pair contains a CString and a bool.
If the CString is meant to be underlined then bool is true, else it is false.
I want to output the text in the vector to the screen making sure that text is underlined in the correct places.
So far I have the following code:
void CEmergenceView::AppendText( CString msg ) {
int nBegin;
CRichEditCtrl &rec = GetRichEditCtrl();
nBegin = rec.GetTextLength();
rec.SetSel(nBegin, nBegin); // Select last character
rec.ReplaceSel(msg); // Append, move cursor to end of text
rec.SetSel(-1,0); // Remove Black selection bars
nBegin = rec.GetTextLength(); // Get New Length
rec.SetSel(nBegin,nBegin); // Cursor to End of new text
// Fix annoying "do you want to save your changes?" when program exits
GetDocument()->SetModifiedFlag(FALSE); // -Optional- (sometimes you want this)
}
int nEnd = 0;
// loop through start of text to end of text
for(int k = 0; k < groups.size(); k++) {
rEditCtrl.SetSel(nEnd, nEnd);
rEditCtrl.GetSelectionCharFormat(cf);
if(groups.at(k).second) {
if(!cf.dwEffects & !CFE_UNDERLINE) {
CRichEditView::OnCharUnderline();
}
}
else if(!groups.at(k).second) {
if(cf.dwEffects & CFE_UNDERLINE) {
CRichEditView::OnCharUnderline();
}
}
AppendText(groups.at(k).first);
nEnd = nEnd + (groups.at(k).first.GetLength());
}
However, this is not underlining at all....Can anyone tell me what I'm doing wrong?? Thanks!
I think you should implement the OnCharUnderline
Try to call yours own function instead of the default one:
You can get it from here:
void CMyRichEditView::OnCharUnderline ()
{
CHARFORMAT2 cf;
cf = GetCharFormatSelection();
if (!(cf.dwMask & CFM_UNDERLINE) || !(cf.dwEffects & CFE_UNDERLINE))
cf.dwEffects = CFE_UNDERLINE;
else
cf.dwEffects = 0;
cf.dwMask = CFM_UNDERLINE;
SetCharFormat(cf);
}

Sending Key Presses with Interception

I have tried all the normal methods of faking keyboard actions (SendInput/SendKeys/etc) but none of them seemed to work for games that used DirectInput. After a lot of reading and searching I stumbled across Interception, which is a C++ Library that allows you to hook into your devices.
It has been a very long time since I worked with C++ (Nothing existed for C#) so I am having some trouble with this. I have pasted in the sample code below.
Does it look like there would be anyway to initiate key actions from the code using this? The samples all just hook into the devices and rewrite actions (x key prints y, inverts mouse axis, etc).
enum ScanCode
{
SCANCODE_X = 0x2D,
SCANCODE_Y = 0x15,
SCANCODE_ESC = 0x01
};
int main()
{
InterceptionContext context;
InterceptionDevice device;
InterceptionKeyStroke stroke;
raise_process_priority();
context = interception_create_context();
interception_set_filter(context, interception_is_keyboard, INTERCEPTION_FILTER_KEY_DOWN | INTERCEPTION_FILTER_KEY_UP);
/*
for (int i = 0; i < 10; i++)
{
Sleep(1000);
stroke.code = SCANCODE_Y;
interception_send(context, device, (const InterceptionStroke *)&stroke, 1);
}
*/
while(interception_receive(context, device = interception_wait(context), (InterceptionStroke *)&stroke, 1) > 0)
{
if(stroke.code == SCANCODE_X) stroke.code = SCANCODE_Y;
interception_send(context, device, (const InterceptionStroke *)&stroke, 1);
if(stroke.code == SCANCODE_ESC) break;
}
The code I commented out was something I tried that didn't work.
You need to tweak key states for UP and DOWN states to get key presses. Pay attention at the while loop that the variable device is returned by interception_wait, your commented out code would send events to what?? device is not initialized! Forget your code and try some more basic. Look at the line inside the loop with the interception_send call, make more two calls after it, but don't forget to change stroke.state before each call using INTERCEPTION_KEY_DOWN and INTERCEPTION_KEY_UP so that you fake down and up events. You'll get extra keys at each keyboard event.
Also, you may try use INTERCEPTION_FILTER_KEY_ALL instead of INTERCEPTION_FILTER_KEY_DOWN | INTERCEPTION_FILTER_KEY_UP. The arrow keys may be special ones as mentioned at the website.
void ThreadMethod()
{
while (true)
{
if (turn)
{
for (int i = 0; i < 10; i++)
{
Sleep(1000);
InterceptionKeyStroke stroke;
stroke.code = SCANCODE_Y;
stroke.state = 0;
interception_send(context, device, (const InterceptionStroke *)&stroke, 1);
Sleep(1);
stroke.state = 1;
interception_send(context, device, (const InterceptionStroke *)&stroke, 1);
turn = false;
}
}
else Sleep(1);
}
}
CreateThread(NULL, NULL, (LPTHREAD_START_ROUTINE)ThreadMethod, NULL, NULL, NULL);
while (interception_receive(context, device = interception_wait(context), (InterceptionStroke*)&stroke, 1) > 0)
{
if (stroke.code == SCANCODE_F5) turn = true;
interception_send(context, device, (InterceptionStroke*)&stroke, 1);
if (stroke.code == SCANCODE_ESC) break;
}