protected override void processData(byte[] dataChunk) { /* the expected data here is .. * 1 byte = total touches * * 1 byte = touch id * 2 bytes = touch x * 2 bytes = touch y * * 1 byte = touch id for next touch (optional) * ... etc * * */ if (dataChunk == emptyByte) { return; } uint touchScreenId = dataChunk[0]; //if a device has multiple screens, this is how we distinguish them. (this also tells us the orientation of the given screen) uint totalTouches = dataChunk[1]; if (dataChunk.Length != (totalTouches * 5) + 2) //unexpected chunk length! Assume it is corrupted, and dump it. { return; } //assume no one is touched. //this code assumes that touches for all touch screens are sent together during every frame (not a Unity frame, but a hardware frame). //as opposed to touch panel A sends something frame 1, then panel B sends it's own thing the next frame. This will not work. for (int t = 0; t < touchScreens.Length; t++) { if (touchScreens[t].active) { touchScreens[t].prepareNextFrame(); } } rawTouchData d = new rawTouchData(); for (int i = 2; i < dataChunk.Length; i = i + 5) //start at 1 and jump 5 each time. { d.id = dataChunk[i]; d.o = (touchScreenOrientation)touchScreenId; d.iX = System.BitConverter.ToUInt16(dataChunk, i + 1); d.iY = System.BitConverter.ToUInt16(dataChunk, i + 3); d.x = (float)d.iX; d.y = (float)d.iY; touchScreens[touchScreenId]._interface(d); } }
//this is the method through which the touchScreenInputManager injects data into the touchScreen object public void _interface(rawTouchData d) { if (!active) { active = true; //if we get touch events, automatically activate this touch screen. (it obviously exists on this device) } //sometimes the hardware sends us funky data. //if the stats are funky, throw it out. if (d.id == 0 || d.id >= maxTouches) { return; } if (d.x < 0 || d.x > screenResX) { return; } if (d.y < 0 || d.y > screenResY) { return; } //is this a new touch? If so, assign it to a new item in the pool, and update our iterators. if (touchPool[touchIdMap[d.id]].state < touch.activationState.ACTIVE) //a new touch! Point it to a new element in our touchPool (we know it is new because the place where the itr is pointing to is deactivated. Hence, it must have gone through at least 1 frame where no touch info was received for it.) { //we can not allow either key duplicates or value duplicates in the map. //key duplicates are already handled because an array index is by definition unique. //however here, we have to make sure another id is not already pointing to our desired touchPoolItr. for (int k = 0; k < maxTouches; k++) { if (touchIdMap[k] == touchPoolItr && k != d.id) { touchIdMap[k] = 0; //point it to our always defunct element. Without this, we can cause our touchCount to be incorrect. } } touchIdMap[d.id] = touchPoolItr; //point the id to the current iterator currentTouchID++; interfaces[touchIdMap[d.id]]._id = currentTouchID; //this id, is purely for external convenience and does not affect our functions here. touchPoolItr++; if (touchPoolItr >= touchPoolSize) { touchPoolItr = 1; //we rely on element 0 always being inactive so we can use it to fix any duplicates. } } interfaces[touchIdMap[d.id]].active = true; interfaces[touchIdMap[d.id]].rawTouchScreenX = (int)d.iX; interfaces[touchIdMap[d.id]].rawTouchScreenY = (int)d.iY; //interfaces[touchIdMap[d.id]].orientation = d.o; //already set. //set the normalized x/y to the touchscreen limits mapToRange(d.x / screenResX, d.y / screenResY, topLimit, rightLimit, bottomLimit, leftLimit, out interfaces[touchIdMap[d.id]].normalizedPos.x, out interfaces[touchIdMap[d.id]].normalizedPos.y); interfaces[touchIdMap[d.id]].physicalPos.x = (d.x / screenResX) * touchScreenWidth; interfaces[touchIdMap[d.id]].physicalPos.y = (d.y / screenResY) * touchScreenHeight; }