void KeyStatus::press(u32 pad, u32 index, s32 value) { if (!IsAnalogKey(index)) { m_internal_button_pressure[pad][index] = value; if (m_state_acces[pad]) clear_bit(m_internal_button_kbd[pad], index); else clear_bit(m_internal_button_joy[pad], index); } else { // clamp value if (value > MAX_ANALOG_VALUE) value = MAX_ANALOG_VALUE; else if (value < -MAX_ANALOG_VALUE) value = -MAX_ANALOG_VALUE; // Left -> -- -> Right // Value range : FFFF8002 -> 0 -> 7FFE // Force range : 80 -> 0 -> 7F // Normal mode : expect value 0 -> 80 -> FF // Reverse mode: expect value FF -> 7F -> 0 u8 force = (value / 256); if (analog_is_reversed(pad,index)) analog_set(pad, index, m_analog_released_val - force); else analog_set(pad, index, m_analog_released_val + force); } }
void KeyStatus::release(u32 pad, u32 index) { if (!IsAnalogKey(index)) { if (m_state_acces[pad]) set_bit(m_internal_button_kbd[pad], index); else set_bit(m_internal_button_joy[pad], index); } else { analog_set(pad, index, m_analog_released_val); } }
void AnalyzeKeyEvent(int pad, keyEvent &evt) { KeySym key = (KeySym)evt.key; int index = get_keyboard_key(pad, key); switch (evt.evt) { case KeyPress: // Shift F12 is not yet use by pcsx2. So keep it to grab/ungrab input // I found it very handy vs the automatic fullscreen detection // 1/ Does not need to detect full-screen // 2/ Can use a debugger in full-screen // 3/ Can grab input in window without the need of a pixelated full-screen if (key == XK_Shift_R || key == XK_Shift_L) s_Shift = true; if (key == XK_F12 && s_Shift) { if(!s_grab_input) { s_grab_input = true; XGrabPointer(GSdsp, GSwin, True, ButtonPressMask, GrabModeAsync, GrabModeAsync, GSwin, None, CurrentTime); XGrabKeyboard(GSdsp, GSwin, True, GrabModeAsync, GrabModeAsync, CurrentTime); } else { s_grab_input = false; XUngrabPointer(GSdsp, CurrentTime); XUngrabKeyboard(GSdsp, CurrentTime); } } // Analog controls. if (IsAnalogKey(index)) { switch (index) { case PAD_R_LEFT: case PAD_R_UP: case PAD_L_LEFT: case PAD_L_UP: key_status->press(pad, index, -MAX_ANALOG_VALUE); break; case PAD_R_RIGHT: case PAD_R_DOWN: case PAD_L_RIGHT: case PAD_L_DOWN: key_status->press(pad, index, MAX_ANALOG_VALUE); break; } } else if (index != -1) key_status->press(pad, index); //PAD_LOG("Key pressed:%d\n", index); event.evt = KEYPRESS; event.key = key; break; case KeyRelease: if (key == XK_Shift_R || key == XK_Shift_L) s_Shift = false; if (index != -1) key_status->release(pad, index); event.evt = KEYRELEASE; event.key = key; break; case FocusIn: //XAutoRepeatOff(GSdsp); break; case FocusOut: //XAutoRepeatOn(GSdsp); s_Shift = false; break; case ButtonPress: if (index != -1) key_status->press(pad, index); break; case ButtonRelease: if (index != -1) key_status->release(pad, index); break; case MotionNotify: // FIXME: How to handle when the mouse does not move, no event generated!!! // 1/ small move == no move. Cons : can not do small movement // 2/ use a watchdog timer thread // 3/ ??? idea welcome ;) if (conf->pad_options[pad].mouse_l|conf->pad_options[pad].mouse_r) { unsigned int pad_x; unsigned int pad_y; // Note when both PADOPTION_MOUSE_R and PADOPTION_MOUSE_L are set, take only the right one if (conf->pad_options[pad].mouse_r) { pad_x = PAD_R_RIGHT; pad_y = PAD_R_UP; } else { pad_x = PAD_L_RIGHT; pad_y = PAD_L_UP; } unsigned x = evt.key & 0xFFFF; unsigned int value = (s_previous_mouse_x > x) ? s_previous_mouse_x - x : x - s_previous_mouse_x; value *= conf->get_sensibility(); if (x == 0) key_status->press(pad, pad_x, -MAX_ANALOG_VALUE); else if (x == 0xFFFF) key_status->press(pad, pad_x, MAX_ANALOG_VALUE); else if (x < (s_previous_mouse_x -2)) key_status->press(pad, pad_x, -value); else if (x > (s_previous_mouse_x +2)) key_status->press(pad, pad_x, value); else key_status->release(pad, pad_x); unsigned y = evt.key >> 16; value = (s_previous_mouse_y > y) ? s_previous_mouse_y - y : y - s_previous_mouse_y; value *= conf->get_sensibility(); if (y == 0) key_status->press(pad, pad_y, -MAX_ANALOG_VALUE); else if (y == 0xFFFF) key_status->press(pad, pad_y, MAX_ANALOG_VALUE); else if (y < (s_previous_mouse_y -2)) key_status->press(pad, pad_y, -value); else if (y > (s_previous_mouse_y +2)) key_status->press(pad, pad_y, value); else key_status->release(pad, pad_y); s_previous_mouse_x = x; s_previous_mouse_y = y; } break; }
void PollForJoystickInput(int cpad) { int joyid = conf->get_joyid(cpad); if (!JoystickIdWithinBounds(joyid)) return; SDL_JoystickUpdate(); for (int i = 0; i < MAX_KEYS; i++) { JoystickInfo* pjoy = s_vjoysticks[joyid]; switch (type_of_joykey(cpad, i)) { case PAD_JOYBUTTONS: { int value = SDL_JoystickGetButton((pjoy)->GetJoy(), key_to_button(cpad, i)); if (value) key_status->press(cpad, i); else key_status->release(cpad, i); break; } case PAD_HAT: { int value = SDL_JoystickGetHat((pjoy)->GetJoy(), key_to_axis(cpad, i)); // key_to_hat_dir and SDL_JoystickGetHat are a 4 bits bitmap, one for each directions. Only 1 bit can be high for // key_to_hat_dir. SDL_JoystickGetHat handles diagonal too (2 bits) so you must check the intersection // '&' not only equality '=='. -- Gregory if (key_to_hat_dir(cpad, i) & value) key_status->press(cpad, i); else key_status->release(cpad, i); break; } case PAD_AXIS: { int value = pjoy->GetAxisFromKey(cpad, i); bool sign = key_to_axis_sign(cpad, i); bool full_axis = key_to_axis_type(cpad, i); if (IsAnalogKey(i)) { if (abs(value) > pjoy->GetDeadzone()) key_status->press(cpad, i, value); else key_status->release(cpad, i); } else { if (full_axis) { value += 0x8000; if (value > pjoy->GetDeadzone()) key_status->press(cpad, i, min(value/256 , 0xFF)); else key_status->release(cpad, i); } else { if (sign && (-value > pjoy->GetDeadzone())) key_status->press(cpad, i, min(-value /128, 0xFF)); else if (!sign && (value > pjoy->GetDeadzone())) key_status->press(cpad, i, min(value /128, 0xFF)); else key_status->release(cpad, i); } } } default: break; } } }