any ideas for detecting button presses

Post » Fri Nov 16, 2012 9:30 pm

was trying to figure out a way I could have a script that would detect when the player presses a key/button to measure time between presses and if it was being held down,
basically im trying to alter the mechanics of combat which goes beyond what papyrus can do.


I know that DirectInput or Xinput(the later I think) can be used but im uncertain about how to add this functionality to work within a script to have it effect game play.

any ideas would be a massive help cheers
User avatar
mishionary
 
Posts: 3414
Joined: Tue Feb 20, 2007 6:19 am

Post » Fri Nov 16, 2012 8:01 pm

SKSE adds Input.PSC to the mix, allowing keypress detection. Input Events are on their way, but you can already poll with IsKeyPressed.

Spoiler
ScriptName YourQuestScript Extends QuestInt iHotkey = [dxscancode here]Bool bIsHotkeyPressedFloat fPressedTimeEvent OnInit()	RegisterForSingleUpdate(0.25)EndEventEvent OnUpdate()	If bIsHotkeyPressed != IsKeyPressed(iHotkey)		bIsHotkeyPressed = !bIsHotkeyPressed		If bIsHotkeyPressed			fPressedTime = Utility.GetCurrentRealTime()			Debug.Trace("Key Pressed at: " + fPressedTime)		Else			Debug.Trace("Hotkey Released " + (Utility.GetCurrentRealTime() - fPressedTime) + " seconds later")		EndIf	EndIf	RegisterForSingleUpdate(0.25)EndEvent
...will spit out something like...
Spoiler
[07/06/2012 - 10:21:50AM] Key Pressed at: 35.833000[07/06/2012 - 10:21:52AM] Hotkey Released 1.516998 seconds later[07/06/2012 - 10:21:54AM] Key Pressed at: 39.372002[07/06/2012 - 10:21:56AM] Hotkey Released 2.528000 seconds later
User avatar
CHARLODDE
 
Posts: 3408
Joined: Mon Apr 23, 2007 5:33 pm

Post » Fri Nov 16, 2012 11:29 pm

great thanks for the help cant wait to get started on this, i had thought about skse but didn't know it enabled key press detection.
i tip my hat to you for you are a gentlemen and a scholar
User avatar
Neliel Kudoh
 
Posts: 3348
Joined: Thu Oct 26, 2006 2:39 am

Post » Sat Nov 17, 2012 3:55 am

Glad to have been able to help :)
User avatar
Dominic Vaughan
 
Posts: 3531
Joined: Mon May 14, 2007 1:47 pm

Post » Fri Nov 16, 2012 8:50 pm

okay i took a break from modding to get back to c++ stuff and finally got to trying this out but i ran into a problem getting the compiler to recognise IsKeyPressed, i have added all the psc files and pex file to the skyrim/data/scripts and data/scripts/source directory but when i try to save the script i get this error

c:\program files (x86)\steam\steamapps\common\skyrim\Data\Scripts\Source\temp\TestSwingScript.psc(12,31): IsKeyPressed is not a function or does not existc:\program files (x86)\steam\steamapps\common\skyrim\Data\Scripts\Source\temp\TestSwingScript.psc(12,28): cannot compare a bool to a none (cast missing or types unrelated)No output generated for TestSwingScript, compilation failed.


so the compiler doesn't recognise the added skse function of IsKeyPressed is there anything i forgot to do to get the compiler to recognise the skse scripts?
User avatar
Adam
 
Posts: 3446
Joined: Sat Jun 02, 2007 2:56 pm

Post » Fri Nov 16, 2012 7:16 pm

oh never mind just had to add input.IsKeyPressed, could have also changed the script to


criptname TestScript extends Quest import inputInt iHotkey = 257Bool bIsHotkeyPressedFloat fPressedTimeEvent OnInit()	    RegisterForSingleUpdate(0.25)EndEventEvent OnUpdate()	    If bIsHotkeyPressed != IsKeyPressed(iHotkey)			    bIsHotkeyPressed = !bIsHotkeyPressed			    If bIsHotkeyPressed					    fPressedTime = Utility.GetCurrentRealTime()					    Debug.Trace("Key Pressed at: " + fPressedTime)			    Else					    Debug.Trace("Hotkey Released " + (Utility.GetCurrentRealTime() - fPressedTime) + " seconds later")			    EndIf	    EndIf	    RegisterForSingleUpdate(0.25)EndEvent
User avatar
Phoenix Draven
 
Posts: 3443
Joined: Thu Jun 29, 2006 3:50 am

Post » Fri Nov 16, 2012 6:24 pm

Depending on what keypresses you are trying to detect, you may not need SKSE. I do this with conditionals in a repeating-stage quest to detect User pressing WASD (getMovementDirection). Also, sneak and sprint (cntl/alt) can be detected by isSneaking and isSprinting. You'd then add those above checks for time before and after to measure the difference.
User avatar
Nuno Castro
 
Posts: 3414
Joined: Sat Oct 13, 2007 1:40 am

Post » Fri Nov 16, 2012 9:33 pm

basically im looking at the time between when the player attacks,
i want to be able to detect if the user has pressed the attack button a set time after the last attack (within a given time frame),
so if the user repetitively hacks at the attack button (say twice before the animation of the first attack finishes) the script will know.

but it seems that when i looked at the c++ files that define IsKeyPressed() it uses input of the GameState, not raw input.

in the C++ files that define the scripts has a flag argument that lets you define which state to use, allowing the raw input from the user but ...

it appears to be auto set to Game state (0) within the header and if within the script you pass a second argument as it appears in the skse c++ file the script tells you you have two many arugments.

from papyrusInput.cpp found in src\skse\skse:

bool IsKeyPressed(StaticFunctionTag* thisInput, UInt32 dxKeycode){  return DIHookControl::GetSingleton().IsKeyPressed(dxKeycode);}


then within hooks_DIrectInput8Create.cpp (same folder):

bool DIHookControl::_IsKeyPressed(KeyInfo* info, UInt32 flags){bool result = false;//bool isMouseButton = keycode >= kMacro_MouseButtonOffset;// data sourcesif(flags & kFlag_GameState)  result |= info->gameState;if(flags & kFlag_RawState)  result |= info->rawState;if(flags & kFlag_InsertedState) result |= info->insertedState;// modifiersbool disable = false;if((flags & kFlag_IgnoreDisabled_User) && info->userDisable)  disable = true;if((flags & kFlag_IgnoreDisabled_Script) && info->scriptDisable)  disable = true;if(disable) result = false;return result;}bool DIHookControl::IsKeyPressed(UInt32 keycode, UInt32 flags){if(keycode >= kMaxMacros) return false;// default modeif(!flags) flags = kFlag_DefaultBackCompat;KeyInfo * info = &m_keys[keycode];return _IsKeyPressed(info, flags);}

so from this as far as i can tell the script version calls the isKeyPressed from PapyrusInput.cpp,
this calls the isKeyPressed in Hooks_directInput8Create.cpp, which will call _IsKeyPressed defined just above it

not sure if i have this right of if there is an easier way to just get the raw time of the button pressed when i used the code as it appears above but replaced trace with debug.Notification() (used notification instead to get instant feed back) it appears to disregard presses made while the animation of the attack occurs, leads me to believe that the input is check after the game has filtered it.
User avatar
Liii BLATES
 
Posts: 3423
Joined: Tue Aug 22, 2006 10:41 am

Post » Sat Nov 17, 2012 8:08 am

just found this page on-line not sure where its from but i just searched kFlag_GameState, its in the C++ code and found this.

ftp://87.224.239.222/games/rpg/The%20Elder%20Scrolls%20V%20Skyrim/src/skse/skse/Hooks_DirectInput8Create.h

it looks like a different version of Hooks_DirectInput8Create.h from the one found in the directory

seems to explain the flags and there meaning, hmmm....
User avatar
Nina Mccormick
 
Posts: 3507
Joined: Mon Sep 18, 2006 5:38 pm

Post » Fri Nov 16, 2012 11:56 pm

The reason why there are multiple state arrays is that SKSE allows to disable keys (and maybe the game lets you disable them as well if there's still something like DisablePlayerControls), and SKSE lets you insert fake key presses by script.
So the idea is probably something like rawState = original input, gameState = input as received by the game (may filter out certain keys), insertedState = input including scripted key presses.
It doesn't have to do anything with the timing.
User avatar
roxanna matoorah
 
Posts: 3368
Joined: Fri Oct 13, 2006 6:01 am

Post » Sat Nov 17, 2012 1:48 am

tested this out some more the problem was the time set on Register for update the game can pick up on the smallest input time, but needs lower register for input, this can make this form of of it a bit resource intensive but im not sure if there is a alternative.

im still interested in the inner workings of the skse though.
User avatar
Juanita Hernandez
 
Posts: 3269
Joined: Sat Jan 06, 2007 10:36 am

Post » Fri Nov 16, 2012 7:13 pm

The reason why there are multiple state arrays is that SKSE allows to disable keys (and maybe the game lets you disable them as well if there's still something like DisablePlayerControls), and SKSE lets you insert fake key presses by script.
So the idea is probably something like rawState = original input, gameState = input as received by the game (may filter out certain keys), insertedState = input including scripted key presses.
It doesn't have to do anything with the timing.

i got that thats what the skse does put i thought that it forced the game state on the call and that using game state only used hooks that respond to feedback from the game rather than i/o, i was wrong that wasn't my problem it was much simpler than that.

though i didn't quite understand the use of disabled states, cheers
User avatar
Rebekah Rebekah Nicole
 
Posts: 3477
Joined: Fri Oct 13, 2006 8:47 pm

Post » Sat Nov 17, 2012 12:28 am

I'd warn against setting your onUpdate to register too fast. This can cause over-stacking and dumping of iterations, freezing the VM, and even CTD. It also interferes with other game processes (such as onCellAttach events) and other mods' scripting.

http://www.gamesas.com/topic/1386736-performance-timing-testing-using-scripted-movement/
http://www.gamesas.com/topic/1383987-performance-characteristics-of-papyrus-functions-and-operations/
User avatar
Adam Baumgartner
 
Posts: 3344
Joined: Wed May 30, 2007 12:12 pm

Post » Fri Nov 16, 2012 6:17 pm

I'd warn against setting your onUpdate to register too fast.
RegisterForSingleUpdate works perfectly for this application in an OnUpdate event and the code will never stagger, even if the update interval is decreased.
User avatar
Kelsey Hall
 
Posts: 3355
Joined: Sat Dec 16, 2006 8:10 pm


Return to V - Skyrim