/* * nextpnr -- Next Generation Place and Route * * Copyright (C) 2018 David Shah * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * */ #ifndef UTIL_H #define UTIL_H #include #include #include #include "nextpnr.h" NEXTPNR_NAMESPACE_BEGIN // Get a value from a map-style container, returning default if value is not // found template ValueType get_or_default(const Container &ct, const KeyType &key, ValueType def = ValueType()) { auto found = ct.find(key); if (found == ct.end()) return def; else return found->second; }; // Get a value from a map-style container, returning default if value is not // found (forces string) template std::string str_or_default(const Container &ct, const KeyType &key, std::string def = "") { auto found = ct.find(key); if (found == ct.end()) return def; else return found->second; }; template std::string str_or_default(const std::unordered_map &ct, const KeyType &key, std::string def = "") { auto found = ct.find(key); if (found == ct.end()) return def; else return found->second.as_string(); }; // Get a value from a map-style container, converting to int, and returning // default if value is not found template int int_or_default(const Container &ct, const KeyType &key, int def = 0) { auto found = ct.find(key); if (found == ct.end()) return def; else return std::stoi(found->second); }; template int int_or_default(const std::unordered_map &ct, const KeyType &key, int def = 0) { auto found = ct.find(key); if (found == ct.end()) return def; else { if (found->second.is_string) return std::stoi(found->second.as_string()); else return found->second.as_int64(); } }; // As above, but convert to bool template bool bool_or_default(const Container &ct, const KeyType &key, bool def = false) { return bool(int_or_default(ct, key, int(def))); }; // Wrap an unordered_map, and allow it to be iterated over sorted by key template std::map sorted(const std::unordered_map> &orig) { std::map retVal; for (auto &item : orig) retVal.emplace(std::make_pair(item.first, item.second.get())); return retVal; }; // Wrap an unordered_set, and allow it to be iterated over sorted by key template std::set sorted(const std::unordered_set &orig) { std::set retVal; for (auto &item : orig) retVal.insert(item); return retVal; }; // Return a net if port exists, or nullptr inline const NetInfo *get_net_or_empty(const CellInfo *cell, const IdString port) { auto found = cell->ports.find(port); if (found != cell->ports.end()) return found->second.net; else return nullptr; }; NEXTPNR_NAMESPACE_END #endif #n15'>15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166
/* Copyright 2016 Jack Humbert
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program 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 General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
#include "quantum.h"
#include "action_tapping.h"

uint8_t get_oneshot_mods(void);

static uint16_t last_td;
static int8_t highest_td = -1;

void qk_tap_dance_pair_finished (qk_tap_dance_state_t *state, void *user_data) {
  qk_tap_dance_pair_t *pair = (qk_tap_dance_pair_t *)user_data;

  if (state->count == 1) {
    register_code16 (pair->kc1);
  } else if (state->count == 2) {
    register_code16 (pair->kc2);
  }
}

void qk_tap_dance_pair_reset (qk_tap_dance_state_t *state, void *user_data) {
  qk_tap_dance_pair_t *pair = (qk_tap_dance_pair_t *)user_data;

  if (state->count == 1) {
    unregister_code16 (pair->kc1);
  } else if (state->count == 2) {
    unregister_code16 (pair->kc2);
  }
}

static inline void _process_tap_dance_action_fn (qk_tap_dance_state_t *state,
                                                 void *user_data,
                                                 qk_tap_dance_user_fn_t fn)
{
  if (fn) {
    fn(state, user_data);
  }
}

static inline void process_tap_dance_action_on_each_tap (qk_tap_dance_action_t *action)
{
  _process_tap_dance_action_fn (&action->state, action->user_data, action->fn.on_each_tap);
}

static inline void process_tap_dance_action_on_dance_finished (qk_tap_dance_action_t *action)
{
  if (action->state.finished)
    return;
  action->state.finished = true;
  add_mods(action->state.oneshot_mods);
  send_keyboard_report();
  _process_tap_dance_action_fn (&action->state, action->user_data, action->fn.on_dance_finished);
}

static inline void process_tap_dance_action_on_reset (qk_tap_dance_action_t *action)
{
  _process_tap_dance_action_fn (&action->state, action->user_data, action->fn.on_reset);
  del_mods(action->state.oneshot_mods);
  send_keyboard_report();
}

bool process_tap_dance(uint16_t keycode, keyrecord_t *record) {
  uint16_t idx = keycode - QK_TAP_DANCE;
  qk_tap_dance_action_t *action;

  if (last_td && last_td != keycode) {
    (&tap_dance_actions[last_td - QK_TAP_DANCE])->state.interrupted = true;
  }

  switch(keycode) {
  case QK_TAP_DANCE ... QK_TAP_DANCE_MAX:
    if ((int16_t)idx > highest_td)
      highest_td = idx;
    action = &tap_dance_actions[idx];

    action->state.pressed = record->event.pressed;
    if (record->event.pressed) {
      action->state.keycode = keycode;
      action->state.count++;
      action->state.timer = timer_read();
      action->state.oneshot_mods = get_oneshot_mods();
      process_tap_dance_action_on_each_tap (action);

      if (last_td && last_td != keycode) {
        qk_tap_dance_action_t *paction = &tap_dance_actions[last_td - QK_TAP_DANCE];
        paction->state.interrupted = true;
        process_tap_dance_action_on_dance_finished (paction);
        reset_tap_dance (&paction->state);
      }

      last_td = keycode;
    }

    break;

  default:
    if (!record->event.pressed)
      return true;

    if (highest_td == -1)
      return true;

    for (int i = 0; i <= highest_td; i++) {
      action = &tap_dance_actions[i];
      if (action->state.count == 0)
        continue;
      action->state.interrupted = true;
      process_tap_dance_action_on_dance_finished (action);
      reset_tap_dance (&action->state);
    }
    break;
  }

  return true;
}



void matrix_scan_tap_dance () {
  if (highest_td == -1)
    return;
  uint16_t tap_user_defined;

for (uint8_t i = 0; i <= highest_td; i++) {
    qk_tap_dance_action_t *action = &tap_dance_actions[i];
    if(action->custom_tapping_term > 0 ) {
      tap_user_defined = action->custom_tapping_term;
    }
    else{
      tap_user_defined = TAPPING_TERM;
    }
    if (action->state.count && timer_elapsed (action->state.timer) > tap_user_defined) {
      process_tap_dance_action_on_dance_finished (action);
      reset_tap_dance (&action->state);
    }
  }
}

void reset_tap_dance (qk_tap_dance_state_t *state) {
  qk_tap_dance_action_t *action;

  if (state->pressed)
    return;

  action = &tap_dance_actions[state->keycode - QK_TAP_DANCE];

  process_tap_dance_action_on_reset (action);

  state->count = 0;
  state->interrupted = false;
  state->finished = false;
  last_td = 0;
}