Technology Experience

Contenuti gestiti da Igor Damiani
posts - 949, comments - 2741, trackbacks - 15120

My Links

News

  • Questo blog si propone di raccogliere riflessioni, teoriche e pratiche, su tutto quello che riguarda il world-computing che mi sta attorno: programmazione in .NET, software attuale e futuro, notizie provenienti dal web, tecnologia in generale, open-source.

    L'idea è quella di lasciare una sorta di patrimonio personale, una raccolta di idee che un giorno potrebbe farmi sorridere, al pensiero di dov'ero e cosa stavo facendo.

    10/05/2005,
    Milano

Archives

Post Categories

Generale

Gestire l'input da tastiera con DX-managed [un po' di VB.NET]

Spinto dall'entusiasmo dei webcast che sto seguendo, ho fatto qualche esperimento per vedere di prendere i tasti premuti dall'utente in modo un po' più veloce rispetto a quanto si fa tramite i classici eventi messi a disposizione del framework. Normalmente, per esempio, si utilizza il seguente codice:

Private Sub Form1_KeyDown(ByVal sender As Object, ByVal e As System.Windows.Forms.KeyEventArgs) Handles MyBase.KeyDown
 Select Case e.KeyCode
     Case Keys.A
     Case Keys.Space
 End Select
End Sub

e così via per ogni tasto di cui si vuole recuperare il valore. Però mentre seguivo l'ultimo webcast ho buttato un'occhiata veloce al codice C# che faceva la stessa cosa usando DirectX. Non ricordavo quasi nulla: solo la chiamata ad un metodo che restituisce un array di booleani con 256 elementi. Ogni elemento dell'array contiene True/False a seconda che il tasto sia stato premuto oppure no. Il codice che ho scritto, googlando un po' è:

Dim dx8 As New DxVBLibA.DirectX8
Dim dxinput As DxVBLibA.DirectInput8
Dim rileva As DxVBLibA.DirectInputEnumDevices8
Dim tast As DxVBLibA.DirectInputDeviceInstance8
Dim i As Integer
Dim tast2 As DxVBLibA.DirectInputDevice8
Dim stato As DxVBLibA.DIKEYBOARDSTATE

dxinput = dx8.DirectInputCreate()
rileva = dxinput.GetDIDevices(DxVBLibA.CONST_DI8DEVICETYPE.DI8DEVCLASS_KEYBOARD, DxVBLibA.CONST_DIENUMDEVICESFLAGS.DIEDFL_ATTACHEDONLY)

For i = 1 To rileva.GetCount
    tast = rileva.GetItem(i)
    Me.lstDevice.Items.Add(tast.GetInstanceName)
Next

La prima parte inizializza un po' di oggetti tirati fuori direttamente da DX8. Lo scopo di questa prima parte è popolare una listbox con l'elenco di tutte le periferiche di tipo tastiera gestibili da DX8. L'oggetto rileva è una sorta di collection contenente tutte le tastiere: ovviamente nei classici PC è sempre una soltanto. Ho provato a modificare i parametri del metodo GetDIDevices ed effettivamente ho recuperato anche il mouse, che però non mi interessava.
Torniamo a noi e alla nostra tastiera.

tast2 = dxinput.CreateDevice(tast.GetGuidProduct)
tast2.SetCommonDataFormat(DxVBLibA.CONST_DICOMMONDATAFORMATS.DIFORMAT_KEYBOARD)
tast2.SetCooperativeLevel(Me.Handle.ToInt32, DxVBLibA.CONST_DISCLFLAGS.DISCL_BACKGROUND Or DxVBLibA.CONST_DISCLFLAGS.DISCL_NONEXCLUSIVE)

tast2 è un oggetto di tipo DirectInputDevice8. Inizializzo la periferica usando il metodo GetGuidProduct di tast. Gli altri metodi non so (in questo momento) dettagliare per bene per mancanza di tempo. Il codice è stato recuperato da google (per la serie, declino ogni responsabilità).
A questo punto comincio un ciclo infinito, un classico Do...While sempre a True.

Do While True
    tast2.Acquire()
    tast2.GetDeviceStateKeyboard(stato)
    For i = 0 To aKeys.Length - 1
        aKeys(i) = stato.key(i) <> 0
    Next
    System.Windows.Forms.Application.DoEvents()
Loop

Ad ogni loop, con la chiamata a GetDeviceStateKeyboard inizializzo la variabile stato. stato mette a disposizione la proprietà key che ritorna True/False per ogni tasto premuto all'ultima rilevazione. Precisazione: io mi sono preparato un bel array aKeys di booleani con 212 elementi (il numero di tasti sulla tastiera?) e setto ciascun elemento come si vede dal codice qui sopra. Se stato.key(i) è diverso da zero, allora quel tasto è stato premuto, e metto l'elemento dell'array a True. Non ho messo un If, ho assegnato direttamente stato.key(i) <> 0.

Credo che in Microsoft ci abbiano pensato bene, però non mi piace una cosa. Mi aspettavo di avere in stato.key(64), per esempio, lo stato della lettera 'A' (codice ASCII), ma non è così. In stato.key(0) ho il tasto ESCAPE (in alto a sinistra), via via mentre mi sposto verso destra e scendendo, trovo tutti gli altri. Questo mi ha obbligato a definirmi una serie di costanti globali tipo:

Public Const DIK_ESCAPE = 1
Public Const DIK_1 = 2
Public Const DIK_2 = 3

e quindi scrivere codice più leggibile. Cioè, se dentro il loop volessi visualizzare in una label i tasti premuti, sarebbe un po' complicato, perchè non c'è una relazione diretta tra la posizione dell'elemento nell'array e il tasto corrispondente. Dovrei fare una Function con un enorme Select Case. Oppure un modo migliore che (non ci vuole un genio) sto già preparando.

Print | posted on martedì 17 maggio 2005 20:35 |

Feedback

Gravatar

# re: Gestire l'input da tastiera con DX-managed [un po' di VB.NET]

Ciao,
l'argomento è interessante.
Ho provato a fare un pò di ricerca sul web ma non ho trovato soluzione al "problema" che evidenzi.
L'idea di cablare la corrispondenza tra la posizione del tasto ed il suo significato non mi esalta, sarebbe più corretto farsi dare quest'informazione dal sistema operativo Caricare in memoria all'inizio la mappa della tastiera).
Il mio dubbio è legato sia al tipo di tastiera (americana, europea, etc.) sia a specifiche varianti (tastiera ergonomica, portatili di diverse marche).
Purtroppo via google non sono riuscito a trovare una soluzione (che sono certo deve esistere).
18/05/2005 00:45 | Gabriele Gaggi
Gravatar

# Visual C# 2005 e reference a DirectX 9.0 SDK

26/05/2005 02:13 | Technology Experience
Comments have been closed on this topic.

Powered by:
Powered By Subtext Powered By ASP.NET