Mercurial > sdl-ios-xcode
diff src/video/qnxgf/SDL_gf_input.c @ 3109:7b3a09fb9c8b
Support for HID devices (mice and keyboards only for now) has been added
author | Mike Gorchak <lestat@i.com.ua> |
---|---|
date | Tue, 28 Apr 2009 04:33:30 +0000 |
parents | |
children | d7174e9f65ce |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/video/qnxgf/SDL_gf_input.c Tue Apr 28 04:33:30 2009 +0000 @@ -0,0 +1,1187 @@ +/* + SDL - Simple DirectMedia Layer + Copyright (C) 1997-2009 Sam Lantinga + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + + Sam Lantinga + slouken@libsdl.org + + QNX Graphics Framework SDL driver + Copyright (C) 2009 Mike Gorchak + (mike@malva.ua, lestat@i.com.ua) +*/ + +#include "SDL_gf_input.h" + +#include "SDL_config.h" +#include "SDL_events.h" +#include "../../events/SDL_mouse_c.h" +#include "../../events/SDL_keyboard_c.h" + +/* Include QNX HIDDI definitions */ +#include "SDL_hiddi_keyboard.h" +#include "SDL_hiddi_mouse.h" +#include "SDL_hiddi_joystick.h" + +/* Mouse related functions */ +SDL_Cursor* gf_createcursor(SDL_Surface* surface, int hot_x, int hot_y); +int gf_showcursor(SDL_Cursor* cursor); +void gf_movecursor(SDL_Cursor* cursor); +void gf_freecursor(SDL_Cursor* cursor); +void gf_warpmouse(SDL_Mouse* mouse, SDL_WindowID windowID, int x, int y); +void gf_freemouse(SDL_Mouse* mouse); + +/* HIDDI interacting functions */ +static int32_t hiddi_connect_devices(); +static int32_t hiddi_disconnect_devices(); + +int32_t gf_addinputdevices(_THIS) +{ + SDL_VideoData* gfdata=(SDL_VideoData*)_this->driverdata; + SDL_DisplayData* didata; + struct SDL_Mouse gf_mouse; + SDL_Keyboard gf_keyboard; + SDLKey keymap[SDL_NUM_SCANCODES]; + SDL_MouseData* mdata; + uint32_t it; + + for (it=0; it<_this->num_displays; it++) + { + /* Clear SDL mouse structure */ + SDL_memset(&gf_mouse, 0x00, sizeof(struct SDL_Mouse)); + + /* Allocate SDL_MouseData structure */ + mdata=(SDL_MouseData*)SDL_calloc(1, sizeof(SDL_MouseData)); + if (mdata==NULL) + { + SDL_OutOfMemory(); + return -1; + } + + /* Mark this mouse with ID 0 */ + gf_mouse.id=it; + gf_mouse.driverdata=(void*)mdata; + gf_mouse.CreateCursor=gf_createcursor; + gf_mouse.ShowCursor=gf_showcursor; + gf_mouse.MoveCursor=gf_movecursor; + gf_mouse.FreeCursor=gf_freecursor; + gf_mouse.WarpMouse=gf_warpmouse; + gf_mouse.FreeMouse=gf_freemouse; + + /* Get display data */ + didata=(SDL_DisplayData*)_this->displays[it].driverdata; + + /* Store SDL_DisplayData pointer in the mouse driver internals */ + mdata->didata=didata; + + /* Set cursor pos to 0,0 to avoid cursor disappearing in some drivers */ + gf_cursor_set_pos(didata->display, 0, 0, 0); + + /* Register mouse cursor in SDL */ + SDL_AddMouse(&gf_mouse, "GF mouse cursor", 0, 0, 1); + } + + /* Keyboard could be one only */ + SDL_zero(gf_keyboard); + SDL_AddKeyboard(&gf_keyboard, -1); + + /* Add scancode to key mapping, HIDDI uses USB HID codes, so */ + /* map will be exact one-to-one */ + SDL_GetDefaultKeymap(keymap); + SDL_SetKeymap(0, 0, keymap, SDL_NUM_SCANCODES); + + /* Connect to HID server and enumerate all input devices */ + hiddi_connect_devices(); + + return 0; +} + +int32_t gf_delinputdevices(_THIS) +{ + /* Disconnect from HID server and release input devices */ + hiddi_disconnect_devices(); + + /* Delete keyboard */ + SDL_KeyboardQuit(); + + /* Destroy all of the mice */ + SDL_MouseQuit(); +} + +/*****************************************************************************/ +/* GF Mouse related functions */ +/*****************************************************************************/ +SDL_Cursor* gf_createcursor(SDL_Surface* surface, int hot_x, int hot_y) +{ + gf_cursor_t* internal_cursor; + SDL_Cursor* sdl_cursor; + uint8_t* image0=NULL; + uint8_t* image1=NULL; + uint32_t it; + uint32_t jt; + uint32_t shape_color; + + /* SDL converts monochrome cursor shape to 32bpp cursor shape */ + /* and we must convert it back to monochrome, this routine handles */ + /* 24/32bpp surfaces only */ + if ((surface->format->BitsPerPixel!=32) && (surface->format->BitsPerPixel!=24)) + { + SDL_SetError("GF: Cursor shape is not 24/32bpp."); + return NULL; + } + + /* Since GF is not checking data, we must check */ + if ((surface->w==0) || (surface->h==0)) + { + SDL_SetError("GF: Cursor shape dimensions are zero"); + return NULL; + } + + /* Allocate memory for the internal cursor format */ + internal_cursor=(gf_cursor_t*)SDL_calloc(1, sizeof(gf_cursor_t)); + if (internal_cursor==NULL) + { + SDL_OutOfMemory(); + return NULL; + } + + /* Allocate memory for the SDL cursor */ + sdl_cursor=(SDL_Cursor*)SDL_calloc(1, sizeof(SDL_Cursor)); + if (sdl_cursor==NULL) + { + SDL_free(internal_cursor); + SDL_OutOfMemory(); + return NULL; + } + + /* Allocate two monochrome images */ + image0=(uint8_t*)SDL_calloc(1, ((surface->w+7)/8)*surface->h); + if (image0==NULL) + { + SDL_free(sdl_cursor); + SDL_free(internal_cursor); + SDL_OutOfMemory(); + return NULL; + } + image1=(uint8_t*)SDL_calloc(1, ((surface->w+7)>>3)*surface->h); + if (image1==NULL) + { + SDL_free(image0); + SDL_free(sdl_cursor); + SDL_free(internal_cursor); + SDL_OutOfMemory(); + return NULL; + } + + /* Set driverdata as GF cursor format */ + sdl_cursor->driverdata=(void*)internal_cursor; + internal_cursor->type=GF_CURSOR_BITMAP; + internal_cursor->hotspot.x=hot_x; + internal_cursor->hotspot.y=hot_y; + internal_cursor->cursor.bitmap.w=surface->w; + internal_cursor->cursor.bitmap.h=surface->h; + internal_cursor->cursor.bitmap.color0=SDL_GF_MOUSE_COLOR_BLACK; + internal_cursor->cursor.bitmap.color1=SDL_GF_MOUSE_COLOR_WHITE; + + /* Setup cursor shape images */ + internal_cursor->cursor.bitmap.stride=((surface->w+7)>>3); + internal_cursor->cursor.bitmap.image0=image0; + internal_cursor->cursor.bitmap.image1=image1; + + /* Convert cursor from 32 bpp */ + for (jt=0; jt<surface->h; jt++) + { + for (it=0; it<surface->w; it++) + { + shape_color=*((uint32_t*)((uint8_t*)surface->pixels+jt*surface->pitch+it*surface->format->BytesPerPixel)); + switch(shape_color) + { + case SDL_GF_MOUSE_COLOR_BLACK: + { + *(image0+jt*(internal_cursor->cursor.bitmap.stride)+(it>>3))|=0x80>>(it%8); + *(image1+jt*(internal_cursor->cursor.bitmap.stride)+(it>>3))&=~(0x80>>(it%8)); + } + break; + case SDL_GF_MOUSE_COLOR_WHITE: + { + *(image0+jt*(internal_cursor->cursor.bitmap.stride)+(it>>3))&=~(0x80>>(it%8)); + *(image1+jt*(internal_cursor->cursor.bitmap.stride)+(it>>3))|=0x80>>(it%8); + } + break; + case SDL_GF_MOUSE_COLOR_TRANS: + { + *(image0+jt*(internal_cursor->cursor.bitmap.stride)+(it>>3))&=~(0x80>>(it%8)); + *(image1+jt*(internal_cursor->cursor.bitmap.stride)+(it>>3))&=~(0x80>>(it%8)); + } + break; + default: + { + /* The same as transparent color, must not happen */ + *(image0+jt*(internal_cursor->cursor.bitmap.stride)+(it>>3))&=~(0x80>>(it%8)); + *(image1+jt*(internal_cursor->cursor.bitmap.stride)+(it>>3))&=~(0x80>>(it%8)); + } + break; + } + } + } + + return sdl_cursor; +} + +int gf_showcursor(SDL_Cursor* cursor) +{ + SDL_VideoDisplay* display; + SDL_DisplayData* didata; + SDL_Window* window; + SDL_WindowID window_id; + gf_cursor_t* internal_cursor; + int32_t status; + + /* Get current window id */ + window_id=SDL_GetFocusWindow(); + if (window_id<=0) + { + SDL_MouseData* mdata=NULL; + + /* If there is no current window, then someone calls this function */ + /* to set global mouse settings during SDL initialization */ + if (cursor!=NULL) + { + mdata=(SDL_MouseData*)cursor->mouse->driverdata; + didata=(SDL_DisplayData*)mdata->didata; + } + else + { + /* We can't get SDL_DisplayData at this point, return fake success */ + return 0; + } + } + else + { + /* Sanity checks */ + window=SDL_GetWindowFromID(window_id); + if (window!=NULL) + { + display=SDL_GetDisplayFromWindow(window); + if (display!=NULL) + { + didata=(SDL_DisplayData*)display->driverdata; + if (didata==NULL) + { + return -1; + } + } + else + { + return -1; + } + } + else + { + return -1; + } + } + + /* Check if we need to set new shape or disable cursor shape */ + if (cursor!=NULL) + { + /* Retrieve GF cursor shape */ + internal_cursor=(gf_cursor_t*)cursor->driverdata; + if (internal_cursor==NULL) + { + SDL_SetError("GF: Internal cursor data is absent"); + return -1; + } + if ((internal_cursor->cursor.bitmap.image0==NULL) || + (internal_cursor->cursor.bitmap.image1==NULL)) + { + SDL_SetError("GF: Cursor shape is absent"); + return -1; + } + + /* Store last shown cursor to display data */ + didata->cursor.type=internal_cursor->type; + didata->cursor.hotspot.x=internal_cursor->hotspot.x; + didata->cursor.hotspot.y=internal_cursor->hotspot.y; + if (internal_cursor->cursor.bitmap.w>SDL_VIDEO_GF_MAX_CURSOR_SIZE) + { + didata->cursor.cursor.bitmap.w=SDL_VIDEO_GF_MAX_CURSOR_SIZE; + } + else + { + didata->cursor.cursor.bitmap.w=internal_cursor->cursor.bitmap.w; + } + + if (didata->cursor.cursor.bitmap.h>SDL_VIDEO_GF_MAX_CURSOR_SIZE) + { + didata->cursor.cursor.bitmap.h=SDL_VIDEO_GF_MAX_CURSOR_SIZE; + } + else + { + didata->cursor.cursor.bitmap.h=internal_cursor->cursor.bitmap.h; + } + + didata->cursor.cursor.bitmap.color0=internal_cursor->cursor.bitmap.color0; + didata->cursor.cursor.bitmap.color1=internal_cursor->cursor.bitmap.color1; + didata->cursor.cursor.bitmap.stride=internal_cursor->cursor.bitmap.stride; + SDL_memcpy(didata->cursor.cursor.bitmap.image0, + internal_cursor->cursor.bitmap.image0, + ((internal_cursor->cursor.bitmap.w+7)/(sizeof(uint8_t)*8))*internal_cursor->cursor.bitmap.h); + SDL_memcpy(didata->cursor.cursor.bitmap.image1, + internal_cursor->cursor.bitmap.image1, + ((internal_cursor->cursor.bitmap.w+7)/(sizeof(uint8_t)*8))*internal_cursor->cursor.bitmap.h); + + /* Setup cursor shape */ + status=gf_cursor_set(didata->display, 0, internal_cursor); + if (status!=GF_ERR_OK) + { + if (status!=GF_ERR_NOSUPPORT) + { + SDL_SetError("GF: Can't set hardware cursor shape"); + return -1; + } + } + + /* Enable just set cursor */ + status=gf_cursor_enable(didata->display, 0); + if (status!=GF_ERR_OK) + { + if (status!=GF_ERR_NOSUPPORT) + { + SDL_SetError("GF: Can't enable hardware cursor"); + return -1; + } + } + + /* Set cursor visible */ + didata->cursor_visible=SDL_TRUE; + } + else + { + /* SDL requests to disable cursor */ + status=gf_cursor_disable(didata->display, 0); + if (status!=GF_ERR_OK) + { + if (status!=GF_ERR_NOSUPPORT) + { + SDL_SetError("GF: Can't disable hardware cursor"); + return -1; + } + } + + /* Set cursor invisible */ + didata->cursor_visible=SDL_FALSE; + } + + /* New cursor shape is set */ + return 0; +} + +void gf_movecursor(SDL_Cursor* cursor) +{ + SDL_VideoDisplay* display; + SDL_DisplayData* didata; + SDL_Window* window; + SDL_WindowID window_id; + int32_t status; + uint32_t xmax; + uint32_t ymax; + + /* Get current window id */ + window_id=SDL_GetFocusWindow(); + if (window_id<=0) + { + didata=(SDL_DisplayData*)cursor->mouse->driverdata; + } + else + { + /* Sanity checks */ + window=SDL_GetWindowFromID(window_id); + if (window!=NULL) + { + display=SDL_GetDisplayFromWindow(window); + if (display!=NULL) + { + didata=(SDL_DisplayData*)display->driverdata; + if (didata==NULL) + { + return; + } + } + else + { + return; + } + } + else + { + return; + } + } + + /* Add checks for out of screen bounds position */ + if (cursor->mouse->x<0) + { + cursor->mouse->x=0; + } + if (cursor->mouse->y<0) + { + cursor->mouse->y=0; + } + + /* Get window size to clamp maximum coordinates */ + SDL_GetWindowSize(window_id, &xmax, &ymax); + if (cursor->mouse->x>=xmax) + { + cursor->mouse->x=xmax-1; + } + if (cursor->mouse->y>=ymax) + { + cursor->mouse->y=ymax-1; + } + + status=gf_cursor_set_pos(didata->display, 0, cursor->mouse->x, cursor->mouse->y); + if (status!=GF_ERR_OK) + { + if (status!=GF_ERR_NOSUPPORT) + { + SDL_SetError("GF: Can't set hardware cursor position"); + return; + } + } +} + +void gf_freecursor(SDL_Cursor* cursor) +{ + gf_cursor_t* internal_cursor; + + if (cursor!=NULL) + { + internal_cursor=(gf_cursor_t*)cursor->driverdata; + if (internal_cursor!=NULL) + { + if (internal_cursor->cursor.bitmap.image0!=NULL) + { + SDL_free((uint8_t*)internal_cursor->cursor.bitmap.image0); + } + if (internal_cursor->cursor.bitmap.image1!=NULL) + { + SDL_free((uint8_t*)internal_cursor->cursor.bitmap.image1); + } + SDL_free(internal_cursor); + } + } +} + +void gf_warpmouse(SDL_Mouse* mouse, SDL_WindowID windowID, int x, int y) +{ + SDL_VideoDisplay* display; + SDL_DisplayData* didata; + SDL_Window* window; + uint32_t xmax; + uint32_t ymax; + int32_t status; + + /* Sanity checks */ + window=SDL_GetWindowFromID(windowID); + if (window!=NULL) + { + display=SDL_GetDisplayFromWindow(window); + if (display!=NULL) + { + didata=(SDL_DisplayData*)display->driverdata; + if (didata==NULL) + { + return; + } + } + else + { + return; + } + } + else + { + return; + } + + /* Add checks for out of screen bounds position */ + if (x<0) + { + x=0; + } + if (y<0) + { + y=0; + } + + /* Get window size to clamp maximum coordinates */ + SDL_GetWindowSize(windowID, &xmax, &ymax); + if (x>=xmax) + { + x=xmax-1; + } + if (y>=ymax) + { + y=ymax-1; + } + + status=gf_cursor_set_pos(didata->display, 0, x, y); + if (status!=GF_ERR_OK) + { + if (status!=GF_ERR_NOSUPPORT) + { + SDL_SetError("GF: Can't set hardware cursor position"); + return; + } + } +} + +void gf_freemouse(SDL_Mouse* mouse) +{ + if (mouse->driverdata==NULL) + { + return; + } + + /* Mouse framework doesn't deletes automatically our driverdata */ + SDL_free(mouse->driverdata); + mouse->driverdata=NULL; + + return; +} + +/*****************************************************************************/ +/* HIDDI handlers code */ +/*****************************************************************************/ +static key_packet key_last_state[SDL_HIDDI_MAX_DEVICES]; + +static void hiddi_keyboard_handler(uint32_t devno, uint8_t* report_data, uint32_t report_len) +{ + key_packet* packet; + uint32_t it; + uint32_t jt; + + packet=(key_packet*)report_data; + + /* Check for special states */ + switch (report_len) + { + case 8: /* 8 bytes of report length */ + { + for (it=0; it<6; it++) + { + /* Check for keyboard overflow, when it can't handle */ + /* many simultaneous pressed keys */ + if (packet->codes[it]==HIDDI_KEY_OVERFLOW) + { + return; + } + } + } + break; + default: + { + /* Do not process unknown reports */ + return; + } + break; + } + + /* Check if modifier key was pressed */ + if (packet->modifiers!=key_last_state[devno].modifiers) + { + if (((packet->modifiers & HIDDI_MKEY_LEFT_CTRL)==HIDDI_MKEY_LEFT_CTRL) && + (key_last_state[devno].modifiers & HIDDI_MKEY_LEFT_CTRL)==0) + { + /* Left Ctrl key was pressed */ + SDL_SendKeyboardKey(0, SDL_PRESSED, SDL_SCANCODE_LCTRL); + } + if (((packet->modifiers & HIDDI_MKEY_LEFT_CTRL)==0) && + (key_last_state[devno].modifiers & HIDDI_MKEY_LEFT_CTRL)==HIDDI_MKEY_LEFT_CTRL) + { + /* Left Ctrl key was released */ + SDL_SendKeyboardKey(0, SDL_RELEASED, SDL_SCANCODE_LCTRL); + } + if (((packet->modifiers & HIDDI_MKEY_LEFT_SHIFT)==HIDDI_MKEY_LEFT_SHIFT) && + (key_last_state[devno].modifiers & HIDDI_MKEY_LEFT_SHIFT)==0) + { + /* Left Shift key was pressed */ + SDL_SendKeyboardKey(0, SDL_PRESSED, SDL_SCANCODE_LSHIFT); + } + if (((packet->modifiers & HIDDI_MKEY_LEFT_SHIFT)==0) && + (key_last_state[devno].modifiers & HIDDI_MKEY_LEFT_SHIFT)==HIDDI_MKEY_LEFT_SHIFT) + { + /* Left Shift key was released */ + SDL_SendKeyboardKey(0, SDL_RELEASED, SDL_SCANCODE_LSHIFT); + } + if (((packet->modifiers & HIDDI_MKEY_LEFT_ALT)==HIDDI_MKEY_LEFT_ALT) && + (key_last_state[devno].modifiers & HIDDI_MKEY_LEFT_ALT)==0) + { + /* Left Alt key was pressed */ + SDL_SendKeyboardKey(0, SDL_PRESSED, SDL_SCANCODE_LALT); + } + if (((packet->modifiers & HIDDI_MKEY_LEFT_ALT)==0) && + (key_last_state[devno].modifiers & HIDDI_MKEY_LEFT_ALT)==HIDDI_MKEY_LEFT_ALT) + { + /* Left Alt key was released */ + SDL_SendKeyboardKey(0, SDL_RELEASED, SDL_SCANCODE_LALT); + } + if (((packet->modifiers & HIDDI_MKEY_LEFT_WFLAG)==HIDDI_MKEY_LEFT_WFLAG) && + (key_last_state[devno].modifiers & HIDDI_MKEY_LEFT_WFLAG)==0) + { + /* Left Windows flag key was pressed */ + SDL_SendKeyboardKey(0, SDL_PRESSED, SDL_SCANCODE_LGUI); + } + if (((packet->modifiers & HIDDI_MKEY_LEFT_WFLAG)==0) && + (key_last_state[devno].modifiers & HIDDI_MKEY_LEFT_WFLAG)==HIDDI_MKEY_LEFT_WFLAG) + { + /* Left Windows flag key was released */ + SDL_SendKeyboardKey(0, SDL_RELEASED, SDL_SCANCODE_LGUI); + } + if (((packet->modifiers & HIDDI_MKEY_RIGHT_CTRL)==HIDDI_MKEY_RIGHT_CTRL) && + (key_last_state[devno].modifiers & HIDDI_MKEY_RIGHT_CTRL)==0) + { + /* Right Ctrl key was pressed */ + SDL_SendKeyboardKey(0, SDL_PRESSED, SDL_SCANCODE_RCTRL); + } + if (((packet->modifiers & HIDDI_MKEY_RIGHT_CTRL)==0) && + (key_last_state[devno].modifiers & HIDDI_MKEY_RIGHT_CTRL)==HIDDI_MKEY_RIGHT_CTRL) + { + /* Right Ctrl key was released */ + SDL_SendKeyboardKey(0, SDL_RELEASED, SDL_SCANCODE_RCTRL); + } + if (((packet->modifiers & HIDDI_MKEY_RIGHT_SHIFT)==HIDDI_MKEY_RIGHT_SHIFT) && + (key_last_state[devno].modifiers & HIDDI_MKEY_RIGHT_SHIFT)==0) + { + /* Right Shift key was pressed */ + SDL_SendKeyboardKey(0, SDL_PRESSED, SDL_SCANCODE_RSHIFT); + } + if (((packet->modifiers & HIDDI_MKEY_RIGHT_SHIFT)==0) && + (key_last_state[devno].modifiers & HIDDI_MKEY_RIGHT_SHIFT)==HIDDI_MKEY_RIGHT_SHIFT) + { + /* Right Shift key was released */ + SDL_SendKeyboardKey(0, SDL_RELEASED, SDL_SCANCODE_RSHIFT); + } + if (((packet->modifiers & HIDDI_MKEY_RIGHT_ALT)==HIDDI_MKEY_RIGHT_ALT) && + (key_last_state[devno].modifiers & HIDDI_MKEY_RIGHT_ALT)==0) + { + /* Right Alt key was pressed */ + SDL_SendKeyboardKey(0, SDL_PRESSED, SDL_SCANCODE_RALT); + } + if (((packet->modifiers & HIDDI_MKEY_RIGHT_ALT)==0) && + (key_last_state[devno].modifiers & HIDDI_MKEY_RIGHT_ALT)==HIDDI_MKEY_RIGHT_ALT) + { + /* Right Alt key was released */ + SDL_SendKeyboardKey(0, SDL_RELEASED, SDL_SCANCODE_RALT); + } + if (((packet->modifiers & HIDDI_MKEY_RIGHT_WFLAG)==HIDDI_MKEY_RIGHT_WFLAG) && + (key_last_state[devno].modifiers & HIDDI_MKEY_RIGHT_WFLAG)==0) + { + /* Right Windows flag key was pressed */ + SDL_SendKeyboardKey(0, SDL_PRESSED, SDL_SCANCODE_RGUI); + } + if (((packet->modifiers & HIDDI_MKEY_RIGHT_WFLAG)==0) && + (key_last_state[devno].modifiers & HIDDI_MKEY_RIGHT_WFLAG)==HIDDI_MKEY_RIGHT_WFLAG) + { + /* Right Windows flag key was released */ + SDL_SendKeyboardKey(0, SDL_RELEASED, SDL_SCANCODE_RGUI); + } + } + + /* Check each key in the press/release buffer */ + switch (report_len) + { + case 8: /* 8 bytes of report length */ + { + /* Check if at least one key was unpressed */ + for (it=0; it<6; it++) + { + if (key_last_state[devno].codes[it]==HIDDI_KEY_UNPRESSED) + { + /* if stored keycode is zero, find another */ + continue; + } + for (jt=0; jt<6; jt++) + { + /* Find stored keycode in the current pressed codes */ + if (packet->codes[jt]==key_last_state[devno].codes[it]) + { + /* If found then particular key state is not changed */ + break; + } + } + + /* Check if pressed key can't longer be found */ + if (jt==6) + { + SDL_SendKeyboardKey(0, SDL_RELEASED, key_last_state[devno].codes[it]); + } + } + + /* Check if at least one new key was pressed */ + for (it=0; it<6; it++) + { + if (packet->codes[it]==HIDDI_KEY_UNPRESSED) + { + continue; + } + for (jt=0; jt<6; jt++) + { + /* Find new keycode it the array of old pressed keys */ + if (packet->codes[it]==key_last_state[devno].codes[jt]) + { + break; + } + } + + /* Check if new key was pressed */ + if (jt==6) + { + SDL_SendKeyboardKey(0, SDL_PRESSED, packet->codes[it]); + } + } + } + default: /* unknown keyboard report type */ + { + /* Ignore all unknown reports */ + } + break; + } + + /* Store last state */ + key_last_state[devno]=*packet; +} + +static uint32_t mouse_last_state_button[SDL_HIDDI_MAX_DEVICES]; +static uint32_t collect_reports=0; + +static void hiddi_mouse_handler(uint32_t devno, uint8_t* report_data, uint32_t report_len) +{ + uint32_t it; + uint32_t sdlbutton; + + /* We do not want to collect stored events */ + if (collect_reports==0) + { + return; + } + + /* Check for special states */ + switch (report_len) + { + case 8: /* 8 bytes of report length, usually multi-button USB mice */ + { + mouse_packet8* packet; + packet=(mouse_packet8*)report_data; + + /* Send motion event if motion really was */ + if ((packet->horizontal_precision!=0) || (packet->vertical_precision!=0)) + { + SDL_SendMouseMotion(0, 1, packet->horizontal_precision, packet->vertical_precision, 0); + } + + /* Send mouse button press/release events */ + if (mouse_last_state_button[devno]!=packet->buttons) + { + /* Cycle all buttons status */ + for (it=0; it<8; it++) + { + /* convert hiddi button id to sdl button id */ + switch(it) + { + case 0: + { + sdlbutton=SDL_BUTTON_LEFT; + } + break; + case 1: + { + sdlbutton=SDL_BUTTON_RIGHT; + } + break; + case 2: + { + sdlbutton=SDL_BUTTON_MIDDLE; + } + break; + default: + { + sdlbutton=it+1; + } + break; + } + + /* Button pressed */ + if (((packet->buttons & (0x01<<it))==(0x01<<it)) && + ((mouse_last_state_button[devno] & (0x01<<it))==0x00)) + { + SDL_SendMouseButton(0, SDL_PRESSED, sdlbutton); + } + /* Button released */ + if (((packet->buttons & (0x01<<it))==0x00) && + ((mouse_last_state_button[devno] & (0x01<<it))==(0x01<<it))) + { + SDL_SendMouseButton(0, SDL_RELEASED, sdlbutton); + } + } + mouse_last_state_button[devno]=packet->buttons; + } + + /* Send mouse wheel events */ + if (packet->wheel!=0) + { + /* Send vertical wheel event only */ + SDL_SendMouseWheel(0, 0, packet->wheel); + } + } + break; + case 4: /* 4 bytes of report length, usually PS/2 mice */ + { + mouse_packet4* packet; + packet=(mouse_packet4*)report_data; + + /* Send motion event if motion really was */ + if ((packet->horizontal!=0) || (packet->vertical!=0)) + { + SDL_SendMouseMotion(0, 1, packet->horizontal, packet->vertical, 0); + } + + /* Send mouse button press/release events */ + if (mouse_last_state_button[devno]!=packet->buttons) + { + /* Cycle all buttons status */ + for (it=0; it<8; it++) + { + /* convert hiddi button id to sdl button id */ + switch(it) + { + case 0: + { + sdlbutton=SDL_BUTTON_LEFT; + } + break; + case 1: + { + sdlbutton=SDL_BUTTON_RIGHT; + } + break; + case 2: + { + sdlbutton=SDL_BUTTON_MIDDLE; + } + break; + default: + { + sdlbutton=it+1; + } + break; + } + + /* Button pressed */ + if (((packet->buttons & (0x01<<it))==(0x01<<it)) && + ((mouse_last_state_button[devno] & (0x01<<it))==0x00)) + { + SDL_SendMouseButton(0, SDL_PRESSED, sdlbutton); + } + /* Button released */ + if (((packet->buttons & (0x01<<it))==0x00) && + ((mouse_last_state_button[devno] & (0x01<<it))==(0x01<<it))) + { + SDL_SendMouseButton(0, SDL_RELEASED, sdlbutton); + } + } + mouse_last_state_button[devno]=packet->buttons; + } + + /* Send mouse wheel events */ + if (packet->wheel!=0) + { + /* Send vertical wheel event only */ + SDL_SendMouseWheel(0, 0, packet->wheel); + } + } + break; + } +} + +/*****************************************************************************/ +/* HIDDI interacting code */ +/*****************************************************************************/ +static hidd_device_ident_t hiddevice= +{ + HIDD_CONNECT_WILDCARD, /* vendor id: any */ + HIDD_CONNECT_WILDCARD, /* product id: any */ + HIDD_CONNECT_WILDCARD, /* version: any */ +}; + +static hidd_connect_parm_t hidparams={NULL, HID_VERSION, HIDD_VERSION, 0, 0, &hiddevice, NULL, 0}; + +static void hiddi_insertion(struct hidd_connection* connection, hidd_device_instance_t* device_instance); +static void hiddi_removal(struct hidd_connection* connection, hidd_device_instance_t* instance); +static void hiddi_report(struct hidd_connection* connection, struct hidd_report* report, void* report_data, uint32_t report_len, uint32_t flags, void* user); + +static hidd_funcs_t hidfuncs={_HIDDI_NFUNCS, hiddi_insertion, hiddi_removal, hiddi_report, NULL}; + +/* HID handle, singletone */ +struct hidd_connection* connection=NULL; + +/* SDL detected input device types, singletone */ +static uint32_t sdl_input_devices[SDL_HIDDI_MAX_DEVICES]; + +static int hiddi_register_for_reports(struct hidd_collection* col, hidd_device_instance_t* device_instance) +{ + int it; + uint16_t num_col; + struct hidd_collection** hidd_collections; + struct hidd_report_instance* report_instance; + struct hidd_report* report; + int status=0; + hidview_device_t* device; + + for (it=0 ; it<10 && !status; it++) + { + status=hidd_get_report_instance(col, it, HID_INPUT_REPORT, &report_instance); + if (status==EOK) + { + status=hidd_report_attach(connection, device_instance, report_instance, 0, sizeof(hidview_device_t), &report); + if (status==EOK) + { + device=hidd_report_extra(report); + device->report=report; + device->instance=report_instance; + } + } + } + hidd_get_collections(NULL, col, &hidd_collections, &num_col); + + for (it=0; it<num_col; it++) + { + hiddi_register_for_reports(hidd_collections[it], device_instance); + } + + return EOK; +} + +static void hiddi_insertion(struct hidd_connection* connection, hidd_device_instance_t* device_instance) +{ + uint32_t it; + struct hidd_collection** hidd_collections; + uint16_t num_col; + + /* get root level collections */ + hidd_get_collections(device_instance, NULL, &hidd_collections, &num_col); + for (it=0; it<num_col; it++) + { + hiddi_register_for_reports(hidd_collections[it], device_instance); + } +} + +static void hiddi_removal(struct hidd_connection* connection, hidd_device_instance_t* instance) +{ + hidd_reports_detach(connection, instance); +} + +static void hiddi_report(struct hidd_connection* connection, hidd_report_t* report, void* report_data, uint32_t report_len, uint32_t flags, void* user) +{ + if (report->dev_inst->devno>=SDL_HIDDI_MAX_DEVICES) + { + /* Unknown HID device, with devno number out of supported range */ + return; + } + + /* Check device type which generates event */ + switch (sdl_input_devices[report->dev_inst->devno]) + { + case SDL_GF_HIDDI_NONE: + { + /* We do not handle other devices type*/ + return; + } + break; + case SDL_GF_HIDDI_MOUSE: + { + /* Call mouse handler */ + hiddi_mouse_handler(report->dev_inst->devno, report_data, report_len); + } + break; + case SDL_GF_HIDDI_KEYBOARD: + { + /* Call keyboard handler */ + hiddi_keyboard_handler(report->dev_inst->devno, report_data, report_len); + } + break; + case SDL_GF_HIDDI_JOYSTICK: + { + /* Call joystick handler */ + } + break; + } +} + +static hiddi_get_device_type(uint8_t* report_data, uint16_t report_length) +{ + hid_byte_t byte; + uint16_t usage_page=0; + uint16_t usage=0; + uint16_t data=0; + + while (report_length && !(usage_page && usage)) + { + if (hidp_analyse_byte(*report_data, &byte)) + { + /* Error in parser, do nothing */ + } + data=hidp_get_data((report_data+1), &byte); + switch (byte.HIDB_Type) + { + case HID_TYPE_GLOBAL: + if (!usage_page && byte.HIDB_Tag==HID_GLOBAL_USAGE_PAGE) + { + usage_page=data; + } + break; + case HID_TYPE_LOCAL: + if (!usage && byte.HIDB_Tag==HID_LOCAL_USAGE) + { + usage=data; + } + break; + } + report_data+=byte.HIDB_Length+1; + report_length-=byte.HIDB_Length+1; + } + + switch (usage_page) + { + case HIDD_PAGE_DESKTOP: + { + switch (usage) + { + case HIDD_USAGE_MOUSE: + { + return SDL_GF_HIDDI_MOUSE; + } + break; + case HIDD_USAGE_JOYSTICK: + { + return SDL_GF_HIDDI_JOYSTICK; + } + break; + case HIDD_USAGE_KEYBOARD: + { + return SDL_GF_HIDDI_KEYBOARD; + } + break; + } + } + break; + case HIDD_PAGE_DIGITIZER: + { + /* Do not handle digitizers */ + } + break; + case HIDD_PAGE_CONSUMER: + { + /* Do not handle consumer input devices */ + } + break; + } + + return SDL_GF_HIDDI_NONE; +} + +static int32_t hiddi_connect_devices() +{ + int32_t status; + uint32_t it; + uint8_t* report_data; + uint16_t report_length; + hidd_device_instance_t instance; + + /* Cleanup initial keys and mice state */ + SDL_memset(key_last_state, 0x00, sizeof(key_packet)*SDL_HIDDI_MAX_DEVICES); + SDL_memset(mouse_last_state_button, 0x00, sizeof(uint32_t)*SDL_HIDDI_MAX_DEVICES); + + status=hidd_connect(&hidparams, &connection); + if (status!=EOK) + { + return -1; + } + + for (it=0; it<SDL_HIDDI_MAX_DEVICES; it++) + { + /* Get device instance */ + status=hidd_get_device_instance(connection, it, &instance); + if (status!=EOK) + { + continue; + } + + status=hidd_get_report_desc(connection, &instance, &report_data, &report_length); + if (status!=EOK) + { + continue; + } + + status=hiddi_get_device_type(report_data, report_length); + sdl_input_devices[it]=status; + + free(report_data); + } + + /* Disconnect from HID server */ + status=hidd_disconnect(connection); + if (status!=EOK) + { + return -1; + } + + /* Add handlers for HID devices */ + hidparams.funcs=&hidfuncs; + + status=hidd_connect(&hidparams, &connection); + if (status!=EOK) + { + return -1; + } + + return 0; +} + +static int32_t hiddi_disconnect_devices() +{ + int32_t status; + + hiddi_disable_mouse(); + + /* Disconnect from HID server */ + status=hidd_disconnect(connection); + if (status!=EOK) + { + return -1; + } +} + +void hiddi_enable_mouse() +{ + collect_reports=1; +} + +void hiddi_disable_mouse() +{ + collect_reports=0; +}