Mercurial > sdl-ios-xcode
view src/video/qnxgf/SDL_gf_input.c @ 3485:e77a69aae239
Mason Wheeler to sdl
I updated SDL, and suddenly my SDL frames stopped working. They'd "initialize" full of gibberish, and I couldn't render anything to them. After a bit of digging, I found a problem: the renderer initialization routine in my SDL frame code wasn't getting called anymore.
procedure TSdlFrame.Paint;
begin
if SDL_SelectRenderer(FWindowID) = -1 then
CreateRenderer;
SDL_RenderPresent;
end;
function TSdlFrame.CreateRenderer: boolean;
const
pf: tagPIXELFORMATDESCRIPTOR = (nSize: sizeof(pf); nVersion: 1;
dwFlags: PFD_DRAW_TO_WINDOW or PFD_SUPPORT_OPENGL or PFD_DOUBLEBUFFER;
iPixelType: PFD_TYPE_RGBA; cColorBits: 24; cAlphaBits: 8;
iLayerType: PFD_MAIN_PLANE);
RENDERERS: array[TRendererType] of AnsiString = ('software', 'gdi', 'opengl', 'd3d');
var
pFormat: integer;
begin
if (SDL_SelectRenderer(FWindowID) = 0) then
begin
result := true;
Exit;
end;
if FRendererType = rtOpenGL then
begin
pFormat := ChoosePixelFormat(canvas.Handle, @pf);
if not SetPixelFormat(canvas.Handle, pFormat, @pf) then
outputDebugString(PChar(SysErrorMessage(GetLastError)));
if wglCreateContext(canvas.Handle) = 0 then
outputDebugString(PChar(SysErrorMessage(GetLastError)));
end;
if (SDL_CreateRenderer(FWindowID, SDL_RendererIndex(RENDERERS[FRendererType]), [sdlrPresentFlip3, sdlrAccelerated]) = 0) then
begin
SDL_ShowWindow(FWindowID);
assert(SDL_SetRenderDrawColor(0, 0, 0, 255) = 0);
FFlags := SDL_GetWindowFlags(FWindowID);
if assigned(FOnAvailable) then
FOnAvailable(self);
end
else outputDebugString(pChar(format('SDL_CreateRenderer failed: %s', [sdl_GetError])));
result := SDL_SelectRenderer(FWindowID) = 0;
end;
This is a critical issue. The Paint method gets called when the control receives a WM_PAINT message from Windows. I can't create the renderer before then, or it will fail and cause trouble. And when I do create it, it needs to be created with certain parameters. So imagine my surprise when I started debugging into the DLL and found that SDL_SelectRenderer was trying to be "helpful" by creating the renderer for me if it didn't already exist! Now not only does my initialization code not get called, I end up with the wrong renderer and so things don't render as expected when I try to use the window.
author | Sam Lantinga <slouken@libsdl.org> |
---|---|
date | Tue, 24 Nov 2009 04:48:12 +0000 |
parents | 87182c69e080 |
children | 4b594623401b |
line wrap: on
line source
/* 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; if ((didata == NULL) || (mdata == NULL)) { return; } } 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; if (didata == NULL) { return; } } 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) { connection=NULL; 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) { connection=NULL; return -1; } /* Add handlers for HID devices */ hidparams.funcs = &hidfuncs; status = hidd_connect(&hidparams, &connection); if (status != EOK) { connection=NULL; return -1; } return 0; } static int32_t hiddi_disconnect_devices() { int32_t status; hiddi_disable_mouse(); /* Disconnect from HID server */ if (connection!=NULL) { status = hidd_disconnect(connection); if (status != EOK) { return -1; } } } void hiddi_enable_mouse() { collect_reports = 1; } void hiddi_disable_mouse() { collect_reports = 0; }