فهرست منبع

Updates to key handling, including addition of 'raw' keys.

Mark Sibly 9 سال پیش
والد
کامیت
b905037e21

+ 27 - 18
modules/mojo/app/app.monkey2

@@ -310,9 +310,9 @@ Class AppInstance
 	
 	Field _window:Window
 	Field _key:Key
-	Field _scanCode:ScanCode
+	Field _rawKey:Key
+	Field _keyChar:String
 	Field _modifiers:Modifier
-	Field _keyText:String
 	Field _mouseButton:MouseButton
 	Field _mouseLocation:Vec2i
 	Field _mouseWheel:Vec2i
@@ -367,7 +367,7 @@ Class AppInstance
 		Local view:=KeyView
 		If view And Not view.ReallyEnabled view=Null
 		
-		Local event:=New KeyEvent( type,view,_key,_scanCode,_modifiers,_keyText )
+		Local event:=New KeyEvent( type,view,_key,_rawKey,_modifiers,_keyChar )
 		
 		KeyEventFilter( event )
 		
@@ -406,39 +406,48 @@ Class AppInstance
 		
 		Case SDL_KEYDOWN
 		
-			Local t:=Cast<SDL_KeyboardEvent Ptr>( event )
+			Local kevent:=Cast<SDL_KeyboardEvent Ptr>( event )
 			
-			_window=Window.WindowForID( t[0].windowID )
+			_window=Window.WindowForID( kevent->windowID )
 			If Not _window Return
 			
-			_key=Cast<Key>( Int( SDL_GetScancodeFromKey( t[0].keysym.sym ) ) )
-			Local tchar:=String.FromChar( t[0].keysym.sym )
-			_modifiers=Cast<Modifier>( t[0].keysym.mod_ )
-			_keyText=String.FromChar( t[0].keysym.sym )
+			_key=Keyboard.KeyCodeToKey( Int( kevent->keysym.sym ) )
+			_rawKey=Keyboard.ScanCodeToRawKey( Int( kevent->keysym.scancode ) )
+'			_modifiers=Keyboard.Modifiers
+			_keyChar=Keyboard.KeyName( _key )
 			
-			SendKeyEvent( EventType.KeyDown )
+			If kevent->repeat_
+				SendKeyEvent( EventType.KeyRepeat )
+			Else
+				SendKeyEvent( EventType.KeyDown )
+			Endif
+
+			_modifiers=Keyboard.Modifiers
 			
 		Case SDL_KEYUP
 
-			Local t:=Cast<SDL_KeyboardEvent Ptr>( event )
+			Local kevent:=Cast<SDL_KeyboardEvent Ptr>( event )
 			
-			_window=Window.WindowForID( t[0].windowID )
+			_window=Window.WindowForID( kevent->windowID )
 			If Not _window Return
 			
-			_key=Cast<Key>( Int( SDL_GetScancodeFromKey( t[0].keysym.sym ) ) )
-			_modifiers=Cast<Modifier>( t[0].keysym.mod_ )
-			_keyText=String.FromChar( t[0].keysym.sym )
+			_key=Keyboard.KeyCodeToKey( Int( kevent->keysym.sym ) )
+			_rawKey=Keyboard.ScanCodeToRawKey( Int( kevent->keysym.scancode ) )
+'			_modifiers=Keyboard.Modifiers
+			_keyChar=Keyboard.KeyName( _key )
 			
 			SendKeyEvent( EventType.KeyUp )
 
+			_modifiers=Keyboard.Modifiers
+
 		Case SDL_TEXTINPUT
 		
-			Local t:=Cast<SDL_TextInputEvent Ptr>( event )
+			Local tevent:=Cast<SDL_TextInputEvent Ptr>( event )
 
-			_window=Window.WindowForID( t[0].windowID )
+			_window=Window.WindowForID( tevent->windowID )
 			If Not _window Return
 			
-			_keyText=String.FromChar( t[0].text[0] )
+			_keyChar=String.FromChar( tevent->text[0] )
 			
 			SendKeyEvent( EventType.KeyChar )
 		

+ 8 - 6
modules/mojo/app/event.monkey2

@@ -6,6 +6,7 @@ Namespace mojo.app
 | EventType			| Description
 |:------------------|:-----------
 | KeyDown			| Key down event.
+| KeyRepeat			| Key repeat event.
 | KeyUp				| Key up event.
 | KeyChar			| Key char event.
 | MouseDown			| Mouse button down event.
@@ -24,6 +25,7 @@ Namespace mojo.app
 Enum EventType
 
 	KeyDown,
+	KeyRepeat,
 	KeyUp,
 	KeyChar,
 	
@@ -96,10 +98,10 @@ Class KeyEvent Extends Event
 
 	#rem monkeydoc @hidden
 	#end
-	Method New( type:EventType,view:View,key:Key,scanCode:ScanCode,modifiers:Modifier,text:String )
+	Method New( type:EventType,view:View,key:Key,rawKey:Key,modifiers:Modifier,text:String )
 		Super.New( type,view )
 		_key=key
-		_scanCode=ScanCode
+		_rawKey=rawKey
 		_modifiers=modifiers
 		_text=text
 	End
@@ -110,10 +112,10 @@ Class KeyEvent Extends Event
 		Return _key
 	End
 	
-	#rem monkeydoc The keyboard scan code of the key.
+	#rem monkeydoc The raw key involved in the event.
 	#end
-	Property ScanCode:ScanCode()
-		Return _scanCode
+	Property RawKey:Key()
+		Return _rawKey
 	End
 	
 	#rem monkeydoc The modifiers at the time of the event.
@@ -131,7 +133,7 @@ Class KeyEvent Extends Event
 	Private
 	
 	Field _key:Key
-	Field _scanCode:ScanCode
+	Field _rawKey:Key
 	Field _modifiers:Modifier
 	Field _text:String
 	

+ 26 - 8
modules/mojo/bananas/commanche/commanche.monkey2

@@ -73,30 +73,30 @@ Class MyWindow Extends Window
 	End Method
 	'-----------------------------------------------------------------------------------------------------------
 	Method UpdateCamera()
-		If Keyboard.KeyDown(Key.A)
+		If Keyboard.KeyDown(Key.A|Key.Raw)
 			Camera.angle+= 2* .0174532925
 		Endif
-		If Keyboard.KeyDown(Key.S)
+		If Keyboard.KeyDown(Key.S|Key.Raw)
 			Camera.x+=4 * Sin(Camera.angle)
 			Camera.y+=4 * Cos(Camera.angle)
 		Endif	
-		If Keyboard.KeyDown(Key.D)
+		If Keyboard.KeyDown(Key.D|Key.Raw)
 			Camera.angle-= 2* .0174532925
 		Endif	
-		If Keyboard.KeyDown(Key.W)
+		If Keyboard.KeyDown(Key.W|Key.Raw)
 			Camera.x-=4 * Sin(Camera.angle)
 			Camera.y-=4 * Cos(Camera.angle)
 		Endif	
-		If Keyboard.KeyDown(Key.R)
+		If Keyboard.KeyDown(Key.R|Key.Raw)
 			Camera.height+=2
 		Endif
-		If Keyboard.KeyDown(Key.F)
+		If Keyboard.KeyDown(Key.F|Key.Raw)
 			Camera.height-=2
 		Endif	
-		If Keyboard.KeyDown(Key.Q)
+		If Keyboard.KeyDown(Key.Q|Key.Raw)
 			Camera.v+=2
 		Endif
-		If Keyboard.KeyDown(Key.E)
+		If Keyboard.KeyDown(Key.E|Key.Raw)
 			Camera.v-=2
 		Endif
 	End Method
@@ -140,10 +140,28 @@ Class MyWindow Extends Window
 		Next
 	End Method
 	'-----------------------------------------------------------------------------------------------------------
+	Method OnKeyEvent( event:KeyEvent ) Override
+	
+		Select event.Type
+		Case EventType.KeyDown,EventType.KeyUp
+			Print Keyboard.KeyName( event.Key )
+			Print Int( event.Modifiers )
+			Print Int( Keyboard.Modifiers )
+		End
+		
+	End
 End
 '-----------------------------------------------------------------------------------------------------------
 Function Main()
+
 	New AppInstance
+	
+	Print "W->"+Keyboard.KeyName( Key.W | Key.Raw )
+	Print "A->"+Keyboard.KeyName( Key.A | Key.Raw )
+	Print "S->"+Keyboard.KeyName( Key.S | Key.Raw )
+	Print "D->"+Keyboard.KeyName( Key.D | Key.Raw )
+	
 	New MyWindow("Commanche",WIDTH*2,HEIGHT*2)
+
 	App.Run()
 End

+ 218 - 34
modules/mojo/input/keyboard.monkey2

@@ -1,83 +1,267 @@
 
 Namespace mojo.input
 
+#Import "native/keyinfo.h"
+#Import "native/keyinfo.cpp"
+
+Extern Private
+
+Struct bbKeyInfo
+	Field name:Void Ptr
+	Field scanCode:Int
+	Field keyCode:Int
+End
+
+Global bbKeyInfos:bbKeyInfo Ptr
+
+Public
+
+#rem monkeydoc Global Keyboard device.
+#end
 Global Keyboard:=New KeyboardDevice
 
+#rem monkeydoc The KeyboardDevice class.
+
+The KeyboardDevice can be accessed via the [[Keyboard]] global variable.
+
+Note that all methods can also be used with 'raw' keys. 
+
+A raw key represents the physical location of a key on US keyboards. For example, `Key.Q|Key.Raw` indicates the key at the top left of the
+'qwerty' keys regardless of the current keyboard layout.
+
+Please see the [[Key]] enum for more information on raw keys.
+
+#end
 Class KeyboardDevice Extends InputDevice
 
-	#rem monkeydoc @hidden
+	#rem monkeydoc The current state of the modifier keys.
 	#end
-	Method Reset()
-		For Local i:=0 Until _numKeys
-			_pressed[i]=True
-			_released[i]=True
-		Next
+	Property Modifiers:Modifier()
+		Return _modifiers
+	End
+
+	#rem monkeydoc Gets the name of a key.
+	
+	If `key` is a raw key, returns the name 'printed' on that key.
+	
+	if `key` is a virtual key
+	
+	#end	
+	Method KeyName:String( key:Key )
+		If key & key.Raw key=TranslateKey( key )
+		Return _names[key]
+	End
+	
+	#rem monkeydoc Translates a key to/from a raw key.
+	
+	If `key` is a raw key, returns the corresponding virual key.
+	
+	If `key` is a virtual key, returns the corresponding raw key.
+	
+	#end
+	Method TranslateKey:Key( key:Key )
+		If key & Key.Raw
+			Local keyCode:=SDL_GetKeyFromScancode( Cast<SDL_Scancode>( _raw2scan[ key & ~Key.Raw ] ) )
+			Return KeyCodeToKey( keyCode )
+		Else
+			Local scanCode:=_key2scan[key]
+			Return _scan2raw[scanCode]
+		Endif
+		Return Key.None
 	End
 	
+	#rem monkeydoc Checks the current up/down state of a key.
+	
+	Returns true if `key` is currently held down.
+	
+	If `key` is a raw key, the state of the key as it is physically positioned on US keyboards is returned.
+	
+	@param key Key to check.
+	
+	#end
 	Method KeyDown:Bool( key:Key )
-		DebugAssert( key>=0 And key<_numKeys,"Key code out of range" )
-		Return _matrix[key]
+
+		Local scode:=ScanCode( key )
+
+		Return _matrix[scode]
 	End
 	
+	#rem monkeydoc Checks if a key was pressed.
+	
+	Returns true if `key` was pressed since the last call to KeyPressed with the same key.
+
+	If `key` is a raw key, the state of the key as it is physically positioned on US keyboards is returned.
+	
+	@param key Key to check.
+	
+	#end
 	Method KeyPressed:Bool( key:Key )
-		DebugAssert( key>=0 And key<_numKeys,"Key code out of range" )
-		If _matrix[key]
-			If _pressed[key] Return False
-			_pressed[key]=True
+	
+		Local scode:=ScanCode( key )
+		
+		If _matrix[scode]
+			If _pressed[scode] Return False
+			_pressed[scode]=True
 			Return True
 		Endif
-		_pressed[key]=False
+
+		_pressed[scode]=False
 		Return False
 	End
+
+	#rem monkeydoc Checks if a key was released.
+	
+	Returns true if `key` was released since the last call to KeyReleased with the same key.
+	
+	If `key` is a raw key, the state of the key as it is physically positioned on US keyboards is returned.
+	
+	@param key Key to check.
 	
+	#end
 	Method KeyReleased:Bool( key:Key )
-		DebugAssert( key>=0 And key<_numKeys,"Key code out of range" )
-		If Not _matrix[key]
-			If _released[key] Return False
-			_released[key]=True
+	
+		Local scode:=ScanCode( key )
+
+		If Not _matrix[scode]
+			If _released[scode] Return False
+			_released[scode]=True
 			Return True
 		Endif
-		_released[key]=False
+	
+		_released[scode]=False
 		Return False
 	End
 	
+	#rem monkeydoc @hidden
+	#end
 	Method KeyHit:Bool( key:Key )
+
 		Return KeyPressed( key )
 	End
 	
+	'***** Internal *****
+	
+	#rem  monkeydoc @hidden
+	#end
+	Method Reset()
+		For Local i:=0 Until 512
+			_matrix[i]=False
+			_pressed[i]=True
+			_released[i]=True
+		Next
+		_modifiers=Null
+	End
+
 	#rem monkeydoc @hidden
 	#end
-	Method KeyName:String( key:Key )
-		DebugAssert( key>0 And key<_numKeys,"Key code out of range" )
-		Local ikey:=Int( key )
+	Method ScanCode:Int( key:Key )
+		If key & Key.Raw Return _raw2scan[ key & ~Key.Raw ]
+		Return _key2scan[ key ]
+	End
 	
-		If ikey>=Int( Key.A ) And ikey<=Int( Key.Z ) Return String.FromChar( ikey-Int( Key.A )+65 )
-
-		If ikey>=Int( Key.F1 ) And ikey<=Int( Key.F12 ) Return "F"+( ikey-Int( Key.F1 )+1 )
-		
-		Return "?"
+	#rem monkeydoc @hidden
+	#end
+	Method KeyCodeToKey:Key( keyCode:Int )
+		If (keyCode & $40000000) keyCode=(keyCode & ~$40000000)-$39+$80
+		Return Cast<Key>( keyCode )
 	End
 	
-	'***** Internal *****
+	#rem monkeydoc @hidden
+	#end
+	Method ScanCodeToRawKey:Key( scanCode:Int )
+		Return _scan2raw[ scanCode ]
+	End
 	
+	#rem monkeydoc @hidden
+	#end
 	Method Init()
 		If _init Return
-		_matrix=SDL_GetKeyboardState( Varptr _numKeys )
-		_pressed=New Bool[_numKeys]
-		_released=New Bool[_numKeys]
 		_init=True
+		
+		Local p:=bbKeyInfos
+		
+		While p->name
+		
+			Local name:=String.FromCString( p->name )
+			Local scanCode:=p->scanCode
+			Local keyCode:=p->keyCode
+			
+			Local key:=KeyCodeToKey( keyCode )
+			
+			_names[key]=name
+			_key2scan[key]=SDL_GetScancodeFromKey( Cast<SDL_Keycode>( keyCode ) )
+			_raw2scan[key]=scanCode
+			_scan2raw[scanCode]=key | Key.Raw
+			
+			p=p+1
+		Wend
+		
+		SDL_AddEventWatch( _EventFilter,Null )
+		
 		Reset()
 	End
 
 	Private
 	
 	Field _init:Bool
-	Field _numKeys:Int
-	Field _matrix:UByte Ptr
-	Field _pressed:Bool[]
-	Field _released:Bool[]
+	Field _modifiers:Modifier
+	Field _matrix:=New Bool[512]
+	Field _pressed:=New Bool[512]
+	Field _released:=New Bool[512]
+	Field _names:=New String[512]
+	Field _key2scan:=New Int[512]
+	Field _raw2scan:=New Int[512]
+	Field _scan2raw:=New Key[512]
 	
 	Method New()
 	End
 	
+	Function _EventFilter:Int( userData:Void Ptr,event:SDL_Event Ptr )
+	
+		Return Keyboard.EventFilter( userData,event )
+	End
+	
+	Method EventFilter:Int( userData:Void Ptr,event:SDL_Event Ptr )
+
+		Select event->type
+			
+		Case SDL_KEYDOWN
+		
+			Local kevent:=Cast<SDL_KeyboardEvent Ptr>( event )
+		
+			_matrix[kevent->keysym.scancode]=True
+			
+			Select kevent->keysym.sym
+			Case $400000e0 _modifiers|=Modifier.LeftControl
+			Case $400000e1 _modifiers|=Modifier.LeftShift
+			Case $400000e2 _modifiers|=Modifier.LeftAlt
+			Case $400000e3 _modifiers|=Modifier.LeftGui
+			Case $400000e4 _modifiers|=Modifier.RightControl
+			Case $400000e5 _modifiers|=Modifier.RightShift
+			Case $400000e6 _modifiers|=Modifier.RightAlt
+			Case $400000e7 _modifiers|=Modifier.RightGui
+			End
+
+		Case SDL_KEYUP
+		
+			Local kevent:=Cast<SDL_KeyboardEvent Ptr>( event )
+		
+			_matrix[kevent->keysym.scancode]=False
+
+			Select kevent->keysym.sym
+			Case $400000e0 _modifiers&=~Modifier.LeftControl
+			Case $400000e1 _modifiers&=~Modifier.LeftShift
+			Case $400000e2 _modifiers&=~Modifier.LeftAlt
+			Case $400000e3 _modifiers&=~Modifier.LeftGui
+			Case $400000e4 _modifiers&=~Modifier.RightControl
+			Case $400000e5 _modifiers&=~Modifier.RightShift
+			Case $400000e6 _modifiers&=~Modifier.RightAlt
+			Case $400000e7 _modifiers&=~Modifier.RightGui
+			End
+
+		End
+		
+		Return 1
+	End
+
 End

+ 40 - 18
modules/mojo/input/keycodes.monkey2

@@ -1,10 +1,17 @@
 
 Namespace mojo.input
 
-'These are actually SDL 'scan codes', ie: what's written on US keyboard keys...
-'
 #rem monkeydoc Key codes.
 
+By default, key codes refer to 'virtual' keys. For example, `KEY_W` refers to the key with 'W' printed on it. However, this key may be not
+be in the same physical location on all users' keyboards, due to OS language and keyboard settings.
+
+To deal with this, mojo also provides support for 'raw' keys. A raw key code is simply a virtual key code 'or'ed with the special key code
+`Key.Raw`.
+
+A raw key represents the physical location of a key on US keyboards. For example, `Key.Q|Key.Raw` indicates the key at the top left of the
+'qwerty' (or 'azerty' etc) keys regardless of the current OS settings.
+
 | Key
 |:---
 | A
@@ -95,38 +102,54 @@ Namespace mojo.input
 | RightGui
 
 #end
+
 Enum Key
 
 	None=0
 
-	A=4,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z
+	Backspace=8,Tab
+	Enter=13
+	Escape=27
+	Space=32
+	Comma=44,Minus,Period,Slash
+	Key0=48,Key1,Key2,Key3,Key4,Key5,Key6,Key7,Key8,Key9
+	Semicolon=59,
+	LeftBracket=91,Backslash,RightBracket
+	Backquote=96
+	A=97,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z
+	KeyDelete=127
 	
-	Key1=30,Key2,Key3,Key4,Key5,Key6,Key7,Key8,Key9,Key0
+	CapsLock=$80,F1,F2,F3,F4,F5,F6,F7,F8,F9,F10,F11,F12
+	PrintScreen,ScrollLock,Pause,Insert,Home,PageUp,nop,KeyEnd,PageDown
+	Right,Left,Down,Up
+	KeypadNumLock,KeypadDivide,KeypadMultiply,KeypadMinus,KeypadPlus,KeypadEnter
+	Keypad1,Keypad2,Keypad3,Keypad4,Keypad5,Keypad6,Keypad7,Keypad8,Keypad9,Keypad0
+	KeypadPeriod
 	
-	Enter=40,Escape,Backspace,Tab,Space
+	LeftControl=$e0,LeftShift,LeftAlt,LeftGui,RightControl,RightShift,RightAlt,RightGui
 	
-	Minus=45,Equals,LeftBracket,RightBracket,Blackslash
+	Raw=$10000
 	
+End
+
+#rem gone?
+Enum ScanCode
+
+	None=0
+	A=4,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z
+	Key1=30,Key2,Key3,Key4,Key5,Key6,Key7,Key8,Key9,Key0
+	Enter=40,Escape,Backspace,Tab,Space
+	Minus=45,Equals,LeftBracket,RightBracket,Blackslash
 	Semicolon=51,Apostrophe,Grave,Comma,Period,Slash
-	
 	CapsLock=57
-	
 	F1=58,F2,F3,F4,F5,F6,F7,F8,F9,F10,F11,F12
-	
 	PrintScreen=70,ScrollLock,Pause,Insert
-	
 	Home=74,PageUp,KeyDelete,KeyEnd,PageDown,Right,Left,Down,Up
-
 	LeftControl=224,LeftShift,LeftAlt,LeftGui
-	
 	RightControl=228,RightShift,RightAlt,RightGui
-
+	
 End
-
-#rem monkeydoc @hidden
 #end
-Enum ScanCode
-End
 
 #rem monkeydoc Modifier masks.
 
@@ -167,4 +190,3 @@ Enum Modifier
 	Alt=			LeftAlt|RightAlt
 	Gui=			LeftGui|RightGui
 End
-