Created
May 2, 2022 16:13
-
-
Save JCxYIS/d3a7aa93df617a0391f8e4d9a08b28fc to your computer and use it in GitHub Desktop.
PicoVR 鍵盤工具插件:使其支援 Input Field (見 https://hackmd.io/@jcxyisncu1102/steamvr-to-pico/%2FUyRsBE57Sw-JtpjEBhz_6g )
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/// Modded by JCxYIS | |
/// 20220328 | |
using System.Collections; | |
using System.Collections.Generic; | |
using UnityEngine; | |
using UnityEngine.UI; | |
using System; | |
using UnityEngine.EventSystems; | |
using Pvr_UnitySDKAPI; | |
public class ImeDelegateImpl : ImeDelegateBase | |
{ | |
public class TextComponent | |
{ | |
public string text | |
{ | |
get { return TextGetter.Invoke(); } | |
set { TextSetter.Invoke(value); } | |
} | |
private Func<string> TextGetter; | |
private Action<string> TextSetter; | |
public static explicit operator TextComponent(InputField inputField) | |
{ | |
TextComponent tc = new TextComponent(); | |
tc.TextGetter = () => inputField.text; | |
tc.TextSetter = str => inputField.text = str; | |
return tc; | |
} | |
public static explicit operator TextComponent(Text text) | |
{ | |
TextComponent tc = new TextComponent(); | |
tc.TextGetter = () => text.text; | |
tc.TextSetter = str => text.text = str; | |
return tc; | |
} | |
} | |
public TextComponent mText; | |
public GameObject[] mKbdViews; | |
public SGViewGather mKbdView; | |
public ImeManager mManager; | |
private Texture2D mTexture; | |
private Vector2 mTextureSize = new Vector2(780,390); | |
private Vector2 mPtKbd = new Vector2(); | |
private SGClickTracker mTracker = new SGClickTracker(); | |
//ImeDelegateBase | |
public override void OnIMEShow(Vector2 vSize) | |
{ | |
Debug.Log("sogou DelegateImpl OnIMEShow"); | |
mTextureSize = vSize; | |
Debug.Log("sogou DelegateImpl OnIMEShow, size = " + mTextureSize[0] + ":" + mTextureSize[1]); | |
CreateTexture(vSize); | |
mManager.Draw(mTexture); | |
mKbdView.SetActive(true); | |
} | |
public override void OnIMEHide() | |
{ | |
Debug.Log("sogou DelegateImpl OnIMEHide"); | |
mKbdView.SetActive(false); | |
} | |
public override void OnIMECommit(string strCommit) | |
{ | |
mText.text += strCommit; | |
} | |
public override void OnIMEKey(SGImeKey key) | |
{ | |
switch (key) | |
{ | |
case SGImeKey.KEYCODE_DEL: | |
String strText = mText.text; | |
mText.text = strText.Remove(strText.Length - 1); | |
break; | |
case SGImeKey.KEYCODE_ENTER: | |
mText.text = ""; | |
break; | |
} | |
} | |
public override void OnIMEError(SGImeError nType, string strErr) | |
{ | |
} | |
//MonoBehaviour | |
void Start() | |
{ | |
mKbdView = new SGViewGather(mKbdViews); | |
CreateTexture(mTextureSize); | |
#if UNITY_EDITOR | |
#else | |
mKbdView.SetActive(false); | |
#endif | |
} | |
void Update() | |
{ | |
//Debug.Log("panel update"); | |
CheckMouseEvent(); | |
mManager.Draw(mTexture); | |
} | |
//other | |
private void CreateTexture(Vector2 vSize) | |
{ | |
if (mTexture) | |
{ | |
return; | |
} | |
#if UNITY_EDITOR | |
#else | |
// Create a texture | |
mTexture = new Texture2D((int)vSize.x, (int)vSize.y, TextureFormat.RGBA32, false); | |
// Set point filtering just so we can see the pixels clearly | |
mTexture.filterMode = FilterMode.Trilinear; | |
// Call Apply() so it's actually uploaded to the GPU | |
mTexture.Apply(); | |
Debug.Log(" sogou DelegateImpl_kbd CreateTexture: texture created"); | |
// Set texture onto cube | |
//GameObject cube = GameObject.Find("Cube"); | |
//cube.GetComponent<Renderer>().material.mainTexture = mTexture; | |
// Set texture onto kbdview | |
mKbdView.SetTexture(mTexture); | |
#endif | |
} | |
private void DispatchMessageToAndroid(SGImeMotionEventType type, Vector2 pt) | |
{ | |
if (null != mManager) | |
{ | |
mManager.OnTouch(pt.x, pt.y, type); | |
} | |
} | |
private void LogEvent(string prefix, PointerEventData eventData) | |
{ | |
Debug.Log(prefix + ": " + eventData.pointerCurrentRaycast.gameObject.name + " x=" + eventData.position.x + ",y=" + eventData.position.y); | |
} | |
private void CheckMouseEvent() | |
{ | |
if (Point2UV(mRay, ref mPtKbd)) | |
{ | |
if (mTracker.Track(mPtKbd, Input.GetKeyDown(KeyCode.JoystickButton0) || | |
Controller.UPvr_GetKeyClick(0, Pvr_KeyCode.TOUCHPAD) || Controller.UPvr_GetKeyClick(0, Pvr_KeyCode.TRIGGER) || Controller.UPvr_GetKeyClick(0, Pvr_KeyCode.X) || | |
Controller.UPvr_GetKeyClick(1, Pvr_KeyCode.TOUCHPAD) || Controller.UPvr_GetKeyClick(1, Pvr_KeyCode.TRIGGER) || Controller.UPvr_GetKeyClick(1, Pvr_KeyCode.A))) | |
{ | |
DispatchMessageToAndroid(mTracker.GetEvent(), mTracker.GetPoint()); | |
} | |
else if (mTracker.Track(mPtKbd, Controller.UPvr_GetKeyClick(0, Pvr_KeyCode.Y) || Controller.UPvr_GetKeyClick(1, Pvr_KeyCode.B) || | |
Controller.UPvr_GetKeyClick(0, Pvr_KeyCode.APP) || Controller.UPvr_GetKeyClick(1, Pvr_KeyCode.APP))) | |
{ | |
mManager.Hide(); | |
} | |
} else if (mTracker.TrackOuter() ) | |
{ | |
DispatchMessageToAndroid(mTracker.GetEvent(), mTracker.GetPoint()); | |
} | |
} | |
public Pvr_ControllerDemo_VRInput controller; | |
private Ray mRay => controller ? controller.ray : PicoVRcontroller.Instance?.Ray ?? new Ray(); | |
private bool Point2UV(Ray ray, ref Vector2 ptUV) | |
{ | |
RaycastHit hitInfo; | |
bool bRes = false; | |
if (Physics.Raycast(ray, out hitInfo)) | |
{ | |
string name = hitInfo.collider.gameObject.name; | |
if (mKbdView.FindName(name)) | |
{ | |
GameObject kbd = hitInfo.collider.gameObject; | |
Vector3 vecKbd = kbd.transform.InverseTransformPoint(hitInfo.point); | |
Vector2 pixelUV = hitInfo.textureCoord; | |
Renderer rend = hitInfo.transform.GetComponent<Renderer>(); | |
ptUV.x = pixelUV.x * mTextureSize.x; | |
ptUV.y = (1 - pixelUV.y) * mTextureSize.y; | |
//Debug.Log("ray click " + name + ": 3d point=" + vecKbd.ToString() + " uv=(" + pixelUV.x + "," + pixelUV.y + ") org=(" + ptUV.ToString() + ")" + " w=" + texSize.x + ",h=" + texSize.y); | |
bRes = true; | |
} | |
} | |
return bRes; | |
} | |
} | |
public class SGViewGather | |
{ | |
private GameObject[] mViews; | |
public SGViewGather(GameObject[] param) | |
{ | |
mViews = param; | |
} | |
public void SetActive(bool bActive) | |
{ | |
foreach (GameObject view in mViews) | |
{ | |
view.SetActive(bActive); | |
} | |
} | |
public bool FindName(string name) | |
{ | |
foreach (GameObject view in mViews) | |
{ | |
if (view.name == name) | |
{ | |
return true; | |
} | |
} | |
return false; | |
} | |
public void SetTexture(Texture2D tex) | |
{ | |
foreach (GameObject view in mViews) | |
{ | |
Renderer rend = view.GetComponent<Renderer>(); | |
rend.material.mainTexture = tex; | |
} | |
} | |
} | |
public class SGClickTracker | |
{ | |
private bool mDownOld = false; | |
private Vector2 mPtOld = new Vector2(); | |
private SGImeMotionEventType mEvent; | |
private const float mTrackRadius = 10.0f; | |
private long mTimeDown; | |
private bool mLongPressed = false; | |
private long mIntervelLongPress = 100; | |
public bool Track(Vector2 pt, bool bDown) | |
{ | |
bool bRes = false; | |
if (bDown) | |
{ | |
if (mDownOld) | |
{ | |
mEvent = SGImeMotionEventType.ACTION_MOVE; | |
if (!mLongPressed) | |
{ | |
long timeDiff = DateTime.Now.Ticks - mTimeDown; | |
if (timeDiff > mIntervelLongPress) | |
{ | |
mLongPressed = true; | |
mEvent = SGImeMotionEventType.ACTION_LONGPRESS; | |
bRes = true; //force sendmessage | |
} | |
} | |
} | |
else | |
{ | |
mEvent = SGImeMotionEventType.ACTION_DOWN; | |
mTimeDown = DateTime.Now.Ticks; | |
mLongPressed = false; | |
} | |
} | |
else | |
{ | |
if (mDownOld) | |
{ | |
mEvent = SGImeMotionEventType.ACTION_UP; | |
} | |
else | |
{ | |
//mEvent = SGImeMotionEventType.ACTION_HOVER_MOVE; | |
mEvent = SGImeMotionEventType.ACTION_MOVE; //c++代码只识别move事件 | |
} | |
} | |
if (mDownOld != bDown) | |
{ | |
bRes = true; | |
} | |
else if (PointDist(mPtOld, pt) > mTrackRadius) | |
{ | |
bRes = true; | |
} | |
mDownOld = bDown; | |
if (bRes) | |
{ | |
mPtOld = pt; | |
} | |
return bRes; | |
} | |
public bool TrackOuter() | |
{ | |
bool bRes = false; | |
if (mEvent != SGImeMotionEventType.ACTION_OUTSIDE) | |
{ | |
SGImeMotionEventType eventOld = mEvent; | |
mEvent = SGImeMotionEventType.ACTION_OUTSIDE; | |
} | |
return bRes; | |
} | |
public Vector2 GetPoint() | |
{ | |
return mPtOld; | |
} | |
public SGImeMotionEventType GetEvent() | |
{ | |
return mEvent; | |
} | |
private float PointDist(Vector2 ptNew, Vector2 ptOld) | |
{ | |
return Math.Abs(ptNew[0] - ptOld[0]) + Math.Abs(ptNew[1] - ptOld[1]); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/// Modded by JCxYIS | |
/// 20220328 | |
using Pvr_UnitySDKAPI; | |
using System.Collections; | |
using System.Collections.Generic; | |
using UnityEngine; | |
using UnityEngine.EventSystems; | |
using UnityEngine.UI; | |
public class TextHandler : MonoBehaviour,IPointerEnterHandler,IPointerExitHandler | |
{ | |
public ImeManager mManager; | |
public SGImeInputType mInputType; | |
public SGImeTextType mTextType; | |
private bool isSelect; | |
ImeDelegateImpl.TextComponent inputComponent = null; | |
// Start is called before the first frame update | |
void Start() | |
{ | |
if (GetComponent<Text>()) | |
inputComponent = (ImeDelegateImpl.TextComponent)GetComponent<Text>(); | |
else if(GetComponent<InputField>()) | |
inputComponent = (ImeDelegateImpl.TextComponent)GetComponent<InputField>(); | |
} | |
// Update is called once per frame | |
void Update() | |
{ | |
if (isSelect) | |
{ | |
if (Input.GetKeyDown(KeyCode.JoystickButton0) || Input.GetMouseButtonDown(0) || | |
Controller.UPvr_GetKeyClick(0, Pvr_KeyCode.TOUCHPAD) || Controller.UPvr_GetKeyClick(0, Pvr_KeyCode.TRIGGER) || Controller.UPvr_GetKeyClick(0, Pvr_KeyCode.X) || | |
Controller.UPvr_GetKeyClick(1, Pvr_KeyCode.TOUCHPAD) || Controller.UPvr_GetKeyClick(1, Pvr_KeyCode.TRIGGER) || Controller.UPvr_GetKeyClick(1, Pvr_KeyCode.A)) | |
{ | |
mManager.Show(mInputType, mTextType); | |
if(inputComponent == null) | |
Debug.LogError("[TextHandler] 此物件沒有可輸入的文字組件"); | |
else | |
FindObjectOfType<ImeDelegateImpl>().mText = inputComponent; | |
// inputComponent.text = "Test48763"; | |
} | |
} | |
} | |
public void OnPointerEnter(PointerEventData eventData) | |
{ | |
// Debug.Log("TextHandler OnPointerEnter"); | |
isSelect = true; | |
} | |
public void OnPointerExit(PointerEventData eventData) | |
{ | |
// Debug.Log("TextHandler OnPointerExit"); | |
isSelect = false; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment